Monday, December 4, 2006

Running With Scissors

A while back I commented on DHH's blog about how cool one of the upcoming changes in Rails 1.2 is going to be. The change is that form_tag will now take a block. I commented that this allowed you to have fun simply passing Procs or lambdas directly to form_tag, and was sharply criticized by another commenter:

Proc is short for: (say it with me) procedure. HTML is not a procedure. Yes, we do use executable code to generate HTML, this is called a template, and again, is different from a code block. Storing web forms as proc objects does not compute, even if you put it in an rhtml file.


Comments have since been closed on the entry -- DHH's blog is very popular and appears to be regularly clogged with spam as a consequence -- but I finally came up with my comeback. Yep, about a month later. Not exactly a snappy comeback, but maybe an interesting one.

The criticism was kind of harsh, but the point was valid. Storing Procs in the view is pretty unorthodox. Confusing other programmers is usually a bad idea. But the idea that it could never be useful, I knew he was wrong there, and I finally figured out why.

Say you've got a Web app running in both England and France. The two countries use different languages and different postal systems. So, you're presenting your content in one of two languages, and you have something controlling that. It comes time to write the order form, and you don't know what kind of address form they're going to need. They could need the British postal system, or the French one. You don't know until runtime.

So you just do this:

form_tag &address_form


Elsewhere in the application, say in the helpers, you have a method called address_form which returns or builds the correct partial based on the user's chosen language. Since the language and the address form requirements vary together by country, they are effectively the same thing.

Admittedly, multilingual countries exist, and are in fact very common. Postal systems do not always vary by language. Certainly there are other ways to do this. It's just an example. And it's an example written under the influence of only one small shot of espresso. I do my best work with three or four. But like any example it exists to illustrate a point, and that point is, this design decision can be useful and beneficial beyond the obvious -- beyond its intended application. I think good design results in code which isn't just easy to use for the problems it was designed to solve, but which is also easy to use in ways the original programmer never imagined -- whereas bad design constrains your range of possible choices to things that the original programmer already knew would happen. The great thing about this decision for Rails 1.2 is that it's going to open up new possibilities -- in addition to the fact that it is an excellent way to handle the problem it was designed to solve.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.