Thursday, March 22, 2007

Can Your Rails App Write Itself?

First off, this post is for wizards who like mischief. You shouldn't even consider implementing the ideas in this post unless you can name twenty or thirty really good reasons not to. You have to be this tall to ride.



That being said, there's a great old post from last year which I happened across the other day. It reminded me of some slightly wizardly and slightly mischevious code I wrote around Novemberish. In the post, Jake Howerton creates a CRUDController which your controllers can inherit from; when they do, they get all the standard Rails CRUD actions for free, the same ones that are autogenerated by script/generate controller, the same ones you see over and over again in many different files in every single Rails app on the planet. Is that DRY? Of course not. And if you use this CRUDController, you get to move all that stuff to one place, and you never have to type def save or def edit in a Rails controller ever again.

However, Howerton gets this to happen through a combination of the usual Rails "convention over configuration" thinking and some instance_variable_get() cleverness. There's nothing wrong with that; in fact David Black says that making a distinction between "metaprogramming" and plain ol' programming is not only unnecessary in Ruby, it's more trouble than it's worth. But even though there's nothing wrong with it, it's the still the type of thing that makes certain people very nervous.



The first argument usually raised against this type of programming is that it's unmaintainable, because nobody but a wizard will ever even be able to figure out what it does. Anybody who's ever looked at the source for Seaside or read Paul Graham's praise for Lisp macros knows the answer to that one. You isolate the code which a novice couldn't maintain somewhere a novice would never find it -- somewhere a novice would only ever even go if they were deliberately looking for something which would challenge them and push them past their novice status. It's pretty easy to maintain wizardly code. Just make it interesting or lucrative enough that a wizard will care, and then slap a big "Do Not Enter" sign on it. This will keep the cowardly away and draw wizards like a magnet.

The second argument raised against this style is that it's harder to debug. That one's harder to tackle, and I don't want to write a novel here. Just realize that all the usual tropes of unadventurous programming apply, in fact, all the stuff that Java programmers are so afraid to do that it makes you wonder if maybe every Java programmer thinks that every other Java programmer is stupid. All those concerns are relevant here. Some of these concerns are foolish and some of them have merit, but none of them have ever really convinced me, because none of them have ever really been strong enough to counteract the two really powerful arguments for coding this way:

1. It's fun.

2. Typing the same thing twice makes you feel like a monkey.



So, I'm definitely very much in favor of this CRUDController thing. So, my own code, which I mentioned earlier, the code I wrote which similarly revolves around instance_variable_get(), this code is a controller with a view which allows you to create a Ferret search method for any particular attribute on a model just by creating a partial named after the attribute in the views dir named after the model.

The interesting thing about this code is that I wrote it for a nonwizardly client who's more of a business guy than a coder. However, he got the idea of it very quickly, and it turned out to be very handy during a deadline-oriented sort of sprint of work -- the type of last-minute late-night sleepless rush which agile software development abhors and ad agencies embrace wholeheartedly.

It turned out very handy because I was able to set up a different type of functionality in the app in the same dynamic way, essentially creating an API for my client which he could use just by creating view files. Ruby and Rails have got to be the only combination I've ever seen where you can get a programmer coding an API and a business guy using it all in the space of a few minutes. Even the Lispers and the Smalltalkers can't claim that, because you'll never find a business guy coding Lisp or Smalltalk.

Although my client ended up switching from Ferret to HyperEstraier due to issues with Ferret's indexing, this code was very, very useful for this particular situation, and additionally is one of the cleanest, concisest, most elegant things I've ever written. I posted about it on the ruby-talk mailing list, saying something like "I love this code so much that sometimes I buy it chocolates and sing to it." I was exaggerating, but honestly, not by much.

I'm posting it here, but if you don't like it, don't tell me. It is a thing of beauty. But the point is not my Irish temper or my prima donna attitude. The point is not even the conciseness of this lovely code. The point is that the number one argument against writing code this way is that it allegedly creates obstacles for less skilled programmers; and yet the single most useful experience I've had with this style of coding was when it proved immensely helpful for a client programmer who was really just a client -- a business guy with the brains to write code, but neither the personality type nor the training of a dyed-in-the-wool hacker. This client should have been the poster child for not coding this way, if the arguments against this style have any merit, but in reality it was very useful for him.

So go for it. Use CRUDController. Use eval() and instance_variable_set(), and not even because it's a good idea. Do it because you can. The big open secret of software development is that good programmers aren't engineers at all -- we're artists, and artists who aren't living on the edge aren't living at all.



Don't go crazy, though.