Monday, January 19, 2009

HAML Brings Seaside Awesome To Ruby

Seaside packs a lot of ideas into one framework. One innovation: you don't write HTML. You tell Seaside what HTML you want, and it does all the dirty work.

Here's a Seaside object with a method that creates a simple form. It's for a mini-app that takes your address, tells you who your senators and representative are, and gives you their phone numbers. It currently has no graphic design.

The Seaside version of this app is unfinished, because I'm much more competent with Ruby. But it's a nice, simple example. Take a look at the code.

This code is easy to read. You're creating an HTML form, with text, a text input, and a submit button. You know that whether you can read Smalltalk or not.

In Seaside, you have web app components (WAComponent subclasses) with renderContentOn methods (actually messages) that generate HTML for you. This structure, combined with Smalltalk's syntax, gives you clear and simple code. The clarity and simplicity make Seaside fun to work in.

There's a lot of frustration as well, since Seaside generally happens outside of Unix, making me a stranger in a strange land. But the code is, afterwards, just easy as hell to read. I often come back to code and scratch my head wondering what I was thinking when I wrote it. That doesn't happen with Seaside, as far as I can tell. You always know what you meant to do.

The downside, however, is that this code just uses the word html too much. It's kind of ridiculous to type html space. when you could just type " ". In Seaside, you're not going to type a whole lot of HTML, but you are going to type html a whole lot. Any time I see code like this I look for a refactor. If you're calling the same object with every line of code, then the method belongs in that object.

Here's code from a Seaside tutorial:

I don't think this is any real serious of criticism of Seaside, however, although I do think it's a valid criticism of the Seaside community. It's an obvious need for refactoring, and it comes from the language that invented refactoring. What's up with that? I think Seaside programmers should be subclassing the renderer at least as often as WAComponent - but that's a tangent.

I bring this all up for the sake of comparison. Like I say, I didn't actually write this app in Seaside. I wrote it in Sinatra with HAML.

Take a look at the code for this view.

It isn't as pretty as the Seaside code, but it's almost as clear, and it's terser. With HAML, you don't have to type a whole lot of HTML, and you might not type a whole lot of anything. And just like the Seaside code, it's easy enough to figure out what this code is doing. There's HTML; there's a form; there's a text input and a submit input, which is to say, a submit button.

That could be more readable. In the best of both worlds, HAML wouldn't just abbreviate the process of writing HTML; it would also replace nonsense like input{:type => "submit"} with Rails-y helpers with logical names like, for example, button. It always worries me, when somebody thinks I'm smart because I'm a programmer, that they're going to find out that one of the reasons programmers think DHH is a genius is because he figured out that we should use the word button when we want to say "button."

At the same time, however, HAML annoys a lot of people. I praised it on Twitter and everybody I work with started laughing at me, even people who can't write code. Hampton Caitlin took the Python feature that annoys people the most, namely semantic indentation, and combined it with the Perl feature that annoys people the most, namely gratuitous punctuation. It should be no surprise that combining the most annoying feature of Perl with the most annoying feature of Python would result in a language that annoys many people very much. It's like a eugenics program to breed a hybrid super-annoyance. I don't know if Hampton's next language is going to take a lot of the busywork out of JavaScript, or simply fart in public while forcing you to hear Battlestar Galactica spoilers.

I like it anyway, though. HAML kind of gives you the inverse of Seaside's advantage. The readability isn't perfect, but the writing is fast. Like Smalltalk, HAML uses incredibly simple rules. You can learn them in a few minutes, and afterwards, it pretty much just works out the box. And most people don't compare HAML to Smalltalk; they compare it to HTML.

Here's HAML generating your list of representatives:

Here's the HTML:

Here's what that would look like in ERb:

The HAML makes the ERb look messy. But look closer and you'll see a much more interesting difference. The HAML is almost entirely programming. There's very little markup involved. That means that when you're writing HAML, you're programming more and marking up less. This is the same advantage Seaside gives you. If you like programming and you don't like writing markup, then the advantage is you have more fun.

I enjoy programming in Seaside because when I'm programming in Seaside, I'm programming. I'm not wrestling with markup; that's for computers to do. I get the same pleasure out of using HAML. At the same time, when I'm in Seaside, I trip over my own feet a lot, because there's a lot about Smalltalk's idiosyncratic environment that doesn't make sense to me. HAML doesn't have that issue.

HAML also takes a more even-handed approach to the balance of programming and markup than ERb. ERb requires bulky special delimiters for programming, and treats markup as plain text. The implication is that markup code is normal, and programming code is unusual. In many cases you don't notice, because delimiters are built into the markup, so you're adding them to both markup and programming either way. However, in a mostly-programming view like the above example, the delimiters just look stupid.

ERb favors a type of application where you have less dynamic content and more static content. Where ERb requires bulky special delimiters for programming but treats markup as text, HAML requires svelte special delimiters for both markup and programming, and only treats text as text. This works equally well whether static markup code predominates, or dynamic programming code. Balance is good.

I think HAML is awesome. I get a major Seaside advantage without the stumbling. I have to take annoyances from Perl and Python, but in exchange I get to skip the HTML. I've written a lot of Perl, a little Python, and an unholy fuckton of HTML. I remember what I enjoyed; I know what I like. The tradeoff's worth it, to me. I'm more than happy to take Perl and Python aggravation if it means I don't have to write HTML.

I've heard that HAML doesn't have unit tests, but it does on GitHub. The project started with Hampton Caitlin and Nathan Weizenbaum took it over. It could be that an early version lacked tests, and Nathan added them. I haven't taken a look at the tests in detail but there are plenty of them, for what that's worth.

Update: Brett Morgan clued me in to Smalltalk cascades, which allow you to skip typing html 100 times without having to subclass anything; and a heckler on Twitter came close to making a good point, that Rails uses submit_tag instead of button. He didn't actually say that, he said <input type="submit"> != <button>, which was kind of my point, but if he had managed to think of a better criticism, he would have brought up the submit_tag thing. But Rails does use link_to instead of a href, and it does have button_for, so, close enough.


And: the app, which looks up your legislators by your address, took 20 lines of code. I wrote it while watching The Silence Of The Lambs and debugging work code on a client's staging server. I used full addresses because you need the full address; searching only by zip code will sometimes return inaccurate results, due to pervasive gerrymandering. I never got around to deploying, but here's the code.

Just for the hell of it, here's an 8-line version: