Beautiful Code: Domain Specific Languages

Written on 5:10:00 PM by S. Potter

Last year when I was first introduced to Ruby on Rails through the screencasts, I remember watching DHH (Rails creator David H. Hanson) say that one of the main motivations behind developing Rails for him was to allow him to create "beautiful code" and that writing beautiful code made him happy and more productive. At the time I liked the concept, but wasn't really sure how true that would be, at least for me. I am a non-visual person and I really didn't think writing beautiful code would affect the way I work and make me noticably more productive. Well, I was wrong! Since last year (2005) when I started Rails development I have grown very attached to creating beautiful code, so much so that have noticed a remarkable difference in how productive I am in Ruby and Ruby on Rails projects compared to my Java work. Remember in 2003 I thought Java was the dog's tuxedo and only ever wanted to write Java (oh, how things have changed). Late last night I watched a Ruby SIG talk about designing domain-specific languages (DSLs), which peaked my interest in the relationship between Sapir-Whorf, beautiful code and developer productivity. Of course, I heard about Sapir-Whorf a while ago and found it interesting at the time, but wasn't really applicable to what I was working on at the time (or at least I thought), so I didn't pay much attention to it until now when almost every Ruby presentation discusses it. Until this evening, I was not able to work on CodeGenie since my last blog entry, but I think it was for the best. My new found love for rspec (a DSL for spec-ing software written in Ruby) and my interest in the relationship above both have inspired me to think about CodeGenie in a new light. Let's take a step back. The general idea behind the Sapir-Whorf hypothesis is that the language you use to "discuss" a subject affects your internal thought processes, such that using one language could restrict or expand your thought process compared to another language. This is applied to both natural and programming languages (in programming languages I include both DSLs and general purpose programming languages that must be Turing-complete, e.g. Ruby, Python, Java, C++, COBOL, etc.). For those that haven't looked at rspec, here is a quick snippet of code:

context "An empty Array" do
  setup do
    @array = []
  end
  
  specify "should be empty" do
    @array.should.be.empty
  end

  specify "should have size of 0" do
    @array.size.should.equal 0
  end
end
Of course, this is pretty simple stuff, but you can immediately read what the snippet specs out for the Array class. It uses language the is specific to the domain of specifying software requirements. In a loose way Rails provides DSLs for defining controller actions, data schema migrations, object-relational mapping, web services and whatever else you use the Rails environment for. However, rspec really goes the extra distance in defining a "language" to use for the sole purpose of specifying software requirements. In many ways this supercedes Test::Unit (or JUnit for the Java heads out there) - you should check out Dave Astels' presentation at Google on Behavior Driven Development (BDD) [very enlightening]. In CodeGenie I want to create a DSL that allows plugin developers to define generators and/or metamodels implemented within the plugin. The idea is that a plugin can contain one or more generators or metamodel implementations. Each generator defines one manifest per metamodel that it supports. A metamodel will define a translator that sucks in the metamodel data, parses it and then spits it out in an in-memory object representation custom to the metamodel format. CodeGenie itself will provide a set of very standard generators and metamodel implementations. Currently am thinking the plugin developer will define a plugin with one generator, something like the following snippet:
context = CodeGenie::Context.new(:TEMPLATE_DIR => "templates", :DOCUMENT_DIR => "documents")

generator "Rails startup generator" do
  manifest :yaml, context do
    # generate setup.py using data from the YAML metamodel passed in to the eRB template
    template "#{TEMPLATE_DIR}/setup.py" "setup.py"
    # create src directory in the root directory of the destination path.
    dir "src"
    # copy standard README, LICENSE and INSTALL files without processing it through the eRB engine - straight copy
    file "#{DOCUMENT_DIR}/README" "README"
    file "#{DOCUMENT_DIR}/LICENSE" "LICENSE"
    file "#{DOCUMENT_DIR}/INSTALL" "INSTALL"
  end
end
For those familiar with the Rails generator, this should like slightly familiar, except that instead of extending a Rails class and defining a manifest class method, I have created a bit more syntactic sugar to make it more domain-specific. These are my initial thoughts and I will work on maturing the DSL over the next couple of weeks. My plan is to get a simple, but working CodeGenie released with YAML and limited MOF support by the end of 2006. Thanks for your patience and if you have suggestions for CodeGenie, please send a message to codegenie-suggest@rubyforge.org

If you enjoyed this post Subscribe to our feed

No Comment

Post a Comment