Reginald Braithwaite-Lee really nailed it with a great post that ties together a bunch of my favorite topics into a nice, coherent bundle:
- language power and expressiveness
- why you sometimes don’t “get it” until you try something
- the different strengths of Rails and Seaside
I particularly like the way he debunks the “you can build new idioms in any language” argument: different languages have different idioms for building new idioms, and that makes a difference.
The first time I delivered my “Metaprogramming Ruby” talk at OSCON this year, I was privileged to have two of the masters of Ruby metaprogramming in the audience: Rich Kilmer and David Heinemeier Hansson. Rails is, of course, the poster child for the benefits of Ruby’s metaprogramming power at the moment. But Rich paved the way with several less well known projects that showed just how much metaprogramming power Ruby has.
Anyway, during the talk I presented two approaches to doing metaprogramming, and since Rich and David were there I put them on the spot and asked them to confirm my suspicions—and I was right. The two of them approach the task in different ways.
Rich typically starts with a domain he understands fairly well, and designs domain-specific constructs to support that domain. Then he implements those constructs using Ruby. That’s the approach he used during the week of OSCON to build the prototype of a Rails interface for his ActionStep framework.
I think that’s how most people think metaprogramming is done, and it sounds really intimidating and difficult—especially when you’re not used to thinking about domain-specific languages, or you don’t understand your domain very well yet, or if you’re not familiar with the techniques of metaprogramming.
But there’s another approach, and it may surprise people that DHH used this
different approach to design and build Rails. He admitted that when he
started building Rails he didn’t have a deep understanding of what a web
framework should look like, and he wasn’t an experienced Ruby developer. But
he started with a strong desire to build good, clean code, and a devotion to
the DRY principle as one way of keeping
his code and design clean. And then he “explored” his way toward Rails’
metaprogramming sweetness. During programming, when he found himself writing
duplicate code, or code that felt ugly or unnecessarily complex, he would
look for ways to eliminate the duplication or make the code simpler and more
expressive. Sometimes that was possible in ways that would seem perfectly
natural to a Java programmer. But in other cases he had to go farther,
augmenting the Ruby language itself through metaprogramming. In less dynamic
languages, some of that duplication or ugliness would’ve remained, simply
because there would be no effective way to eliminate it. (Don’t believe me?
Look at the source to
java.util.Arrays.sort.) But in Ruby your refactoring
toolkit is bigger, and most of Ruby’s metaprogramming idioms are quite easy
to use once you learn them.
That’s how I like to explain metaprogramming: as an additional set of tools that dynamic languages provide to help you eliminate bad-smelling code.
Those rich idioms give you a lot of power for keeping your systems clean and simple.