{ |one, step, back| }

Staying Simple
13 Sep 04 - http://www.pairprogrammingbot.com/index.cgi/Tech/Ruby/StayingSimple.rdoc
One of the most important lessons I have ever learned as a software developer is to keep things simple. It’s also one of the hardest lessons to remember, because as programmers, we revel in the complex. Sometimes I am forced to reconsider designs where I let my love of complexity override my good sense for simplicity.

Revisiting Builder

Here’s one small example where complexity got away from me. My last blog entry mentioned BuilderObjects used to build XML markup. It turns out that these builders are really useful and I’ve been making good use of them in my latest web project.

However, as I was using, I discovered a rather annoying feature. If you recall, builders depended on the method_missing feature of Ruby to implement arbitrary XML tags on the fly. But, in order for code like this …

   builder.p { em("Hello World") }

to work, the em message must be sent to the builder object. Normally unadorned messages are sent to self. However, the builder object evaluated its block in a special way to hijack the value of self to point to itself.

It is really cool that we just need to mention the tag name and it automatically gets generated. But there is a downside. Suppose we replace the literal "Hello World" with a method called greet that dynamically determines the proper form of greeting. Now the code looks like this…

  builder.p { em(greet) }   # greet is a method

Now, not only em, but also greet gets sent to the builder. This is wrong, greet is a method defined on the current object, not the builder. To get around this, we must save the value of self outside the block and make it available under a different name. Perhaps like this…

  s = self
  builder.p { em(s.greet) }

As I was using builder I notice I was doing the s = self step on almost everytime I used a builder. And when I forget to use the s, I would get weird bugs in my HTML output.

Clearly I was being too clever (in my defense, I just copied the Groovy design for their builders). So I fixed the builder to use normal blocks with normal evaluation and the number of accidental bugs went way down. The greet example now reads like this under the new version of builder:

  builder.p { builder.em(greet) }

Now, since is it awkward to keep mentioning the builder name over and over, it would be nice to have a shortcut. Hence builders pass themselves as a parameter to the blocks. This gives us the opportunity to use a shorter name, but only with in the block. Again, the greet example is

  builder.p { |xml|  xml.em(greet) }

(The shorter name isn’t a big advantage here, but is a big convenience when many tags are created.)

So, it gets back to that old adage: KISS — Keep It Simple Stupid!

Postscript …

Builder is availble as a gem. Version 1.0.0 has the new, simpler interface. Because Builder is a gem, you can install both versions and use either, as long as you don’t mix their usage in a single application. To use the new version (after installing), just say

  require_gem 'builder', '~> 1.0'

This allows you to use any version greater than 1.0 but less that 2.0. To use the old interface, say …

  require_gem 'builder', '~> 0.1'

This allows any version 0.1 or later, but rejects version 1.0 and up. The ~> operator is called the Pessimistic version constraint is is helpful when versions of software have incompatible interfaces. The RubyGems wiki has more information about pessimistic version constraint and about versioning policies.