On Rails

Feb 05 2006

A couple of weeks ago I did another one of those infamous infrastructure overhauls to this site where all the perfectly functional pylons are quickly knocked out and in that split second before the whole thing falls down something new is rammed underneath. It's really an entertaining and nerdy experience, I recommend it highly. It's something I had been hoping to do for quite some time, but I stay pretty busy these days and haven't been able to justify spending any time on it. But then along comes IAP and the degree of freedom in my schedule makes the temptation just too irresistible and so I make a pact with myself to spend no more than two days, then I set out with the sledgehammer.

I was tired of patching up Movable Type by stuffing the cracks with lots of little custom plugins and having to resort to one of my least favorite environments, PHP, whenever I wanted to add any sort of dynamic feature. In the course of a couple of days, the site when entirely over to ruby on rails. I liked it when we used it to build OPENSTUDIO, so when Dreamhost decided to install it on their shared hosting accounts I was all over it. And to let you in on a little secret: Even though I taught a python seminar over the summer at the Media Lab, ruby has now become my dynamic language of choice. Why, you might ask?

Why Ruby?

Metaprogramming – Ruby not only gives the ability to cleverly change horses in midstream but goes further allowing you to actually change horse to something that more resembles a Miami Vice style cigar boat. It turns out that changing the class definition at runtime is incredibly powerful. If you've ever written any sort of object-relational system to tie classes to database records, you already know of one place it proves it's worth. Come one, you know. You once wrote that thing in Java, where you debated for two days over the merits of:

person.getName()

vs. the more general

person.getField(“name”);

Ah, if only you could have defined the class on the fly you could have had your cake and execute(“eaten”) it too. In fact, you even change the meaning of classes you didn't put there. If you decide that Array needs a sum method, feel free to put it in:

class Array
    def sum
        inject(0) { |s,x| s+x }
    end
end

Blocks and Closures – This is the point where all the smalltalk people start to quiver before uniting in a deafening chorus of, “that was stolen from Smalltalk.” Yup, and put to good use. In ruby, it's very easy for methods to accept a functional block as a parameter. In fact, you could even go as far as saying that convention in ruby encourages it. As a result, you get very nice iterations:

numbers.collect { |x| x*x }
numbers.each_with_index { |i,x| puts “#{i}: #{x}” }

But you also get a pleasant solution to those situations where you need to explicitly clean up after you're done. For instance, how many times have you forgotten to close a an open file:

File.open('/etc/passwd') { |fh|
    do_something(fh.read);
}

Probably more than you think, especially when you try to make things robust and wrap your IO calls in a try…catch…finally style block. In the example above, File's open method takes the responsibility of closing the file so you don't have to worry about it. Rails also puts this to great use in allowing database changes to be conveniently wrapped in a call to the transaction method. If you've ever done much database coding in Java, you can definitely appreciate that.

Everything is an object – This was one of the promises that python never quite made good on in my opinion. For instance, this is a dialog I had with python more than once:

$ python
>>> a = []
>>> a.length
AttributeError: 'list' object has no attribute 'length'
>>> a.count()
TypeError: count() takes exactly one argument (0 given)
>>> dammit
NameError: name 'dammit' is not defined

Whereas ruby makes it a bit more difficult to disprove the everything is an object assertion:

$ irb
> 14.next
==> 15
> 3.1.floor
==> 3

Of course, there are a few other small things that have helped to put ruby in my good graces. It stole a lot of decent things from Perl (like a lot of concise and flexible syntax and built in regular expressions). It also has an interactive command-line interpreter like python.

Unicode, the unsightly flaw

But alas, nothing ever comes off without a hitch. For reasons I cannot even begin to fathom, ruby is still trudging along without full Unicode support. Though it's promised in 1.9 (the current version being 1.8.4), I still wonder how languages make it into 2006 without good Unicode support. Trust me folks, this Unicode thing is here to stay. Even if the Bush administration bombs Arabic out of existence, there will be more than enough Kanji to go around.

Despite the Unicode flaw, I'm sold on ruby for now. Over the years, I've become a big fan of agility in development and right now I think ruby has it on the web development front.