Ian Bicking: the old part of his blog

More thoughts on Ruby on Rails

I wrote some thoughts on Ruby on Rails a couple months ago. But that was just formed by reading a bunch of docs, which is actually about as far as I get into a number of things. I'm a little embarrassed to admit it, but I often build strong opinions on things I've only read about. But, I don't really feed bad about it; I try not to be a curmudgeon and I give projects the benefit of the doubt. Installation sometimes feels like a waste of time when I just want to look around.

But anyway, since I've been thinking about Rails lately, I thought I'd give it an actual test run. I only went through the quite-short Making a to-do list tutorial.

So, I installed Ruby from the Debian packages (0.11.1) and set out. Impressions...

First thing that Rails does is create a bunch of files and directories for your project. I think this is a good idea, and something I added recently to Paste. (When I was introducing a coworker to Webware, the lack of a clear convention for file structure was actually one of his first concerns.)

Now... the actual files. More than I would have expected -- 11 directories at the top level, and 29 total. I'm not a fan of hierarchy, so this puts me off a little. And it feels more complex than I expected. But people can argue about file layout forever.

Onward... I made a controller. I notice controllers feel a lot like a published object, or even Webware's servlets. Controllers are classes, and every method is its own page/URL (index as the default all the way down). There's other more complicated ways to map URLs, but personally I find URLs a little boring. People who start applications with URL design are, IMHO, displaying classic engineer tendencies wherein they focus on small technical details that don't matter in any larger picture. But I digress...

I find it odd that every method is published. Which means there's no private methods. Instead there's a "helper" class (for app/controllers/todo_controller.rb there's app/helpers/todo_helper.rb). That's... awkward. At one time Zope used docstrings to mark methods as public, but that was a bad idea ("docstring abuse"). Now (in Python) function attributes are an easy way to do that, like:

def screen_method(...): ...
screen_method.public = True

Or decorators can be used to the same effect, but with somewhat more pleasant syntax. Or you can just use a naming convention (a name prefix that indicates a method is public). But in Rails not only do helper methods not go in the same class, or the same file, or even the same directory, but in a separate file in a sibling directory. Strange. I think there's also a good deal of mix-ins happening -- not just the helper into the controller, but the template into the controller as well. Mix-ins were something people thought to be a good idea in Python some time back, but I think we've all realized they don't scale well (no worse than multiple inheritance, but that doesn't scale well either). Or at least mix-ins implies modularity where in fact there is none.

Lots of things get passed around as instance variables of the controller. It's encouraged (from what I can tell) to use instance variables for even local scope, so that helper methods can find these variables by name. People who study language history will know pass-by-name as the black sheep in the pass-by-value/pass-by-reference debate. No one uses pass-by-name anymore. (Well, maybe that's not entirely true -- Tcl uses it for arrays, PHP uses it for callbacks, REST uses it for identifiers, and everyone who uses XML configuration uses it for all sorts of stuff.) I'm sure there's good reasons for this stuff, but I also feel like Rails is willing to compromise on predictable isolated programming constructs if it saves them a line or two of code. I like short code, but I like locally-understandable code much more.

The model thing confuses me a bit as well. I'm used to models being an abstract concept. Models are your objects. Yours, not the framework's. The model can be a dictionary, or a number, or a ORM object, or a set of functions that call to a database procedurally, or code that queries remote services. Whatever. I don't see much of a difference between your "model" and your "library". But Rails formalizes it -- at least a little -- but making a separate directory for models. Presumably they are distinguished in other ways too. It's hard to tell the difference between suggestive convention -- meant to embody good practices -- and meaningful distinctions.

One thing I like about the generation process (generating models, controllers, etc) is that it also extends the test framework. That's definitely something that is going to go into Paste. In addition to adding files for unit tests, it also adds model fixtures, which are some sample data. Stuff you could use to see what the website looks like in a more realistic situation, or a way to avoid some tedium in your unit test setup. This is similar to what scaffolding provides -- not a great UI, but just enough stuff to give you enough navigation to get to the part you are working on right now. I think there's value in that, and the name indicates its purpose, but it's also easy to over-appreciate because it seems magic.

One last thing that struck me was the templates. In a bad way. The templates are a standard ASP-style of template; a classification one commenter seemed offended by in my last post, but it's not meant that way. That's just what they are; they look exactly like ASP. So what? Anyway, I don't care much about that. I think ZPT has some interesting ideas about how to put code into HTML, but I've never been that convinced that tag-based templates are easier or even as easy as more textual/program-oriented templating languages.

What bothered me was the way they dealt with reuse. At least in the template two options were given -- one generated the HTML in plain Ruby code. Clearly ugly. The other use "partials", which a way of saying "a second template that gets embedded".

Well, like I said, I don't like hierarchy, and similarly I like keeping information together. As a result, I really like templating languages that have structure. Both ZPT and Cheetah have this, though using different metaphors. In ZPT you have macros (METAL), and you use this for both the site wrapper and for reusing markup inside a page. It's very nice; it really is a macro, and I'm not a big fan of macros, but I haven't had any problems with that aspect. You can put lots of macros in a single file, you can give them all sorts of internal structure, etc. Works great. Cheetah does it with #def and representing templates as classes. This serves many of the same purposes -- the ZPT macro is a Cheetah abstract superclass, and the macro "slots" are methods in Cheetah. Either way you can define rich structure without adding new files or putting in new conditionals and funny exceptions and whatnot into your code. Rails seems to offer no structure in its templates, and so they lack expressiveness.

Anyway, that's my impression; still a bit shallow, but more informed. There's good things that I plan to borrow from Rails. But there's a lot of things that feel unnecessary, or feel like paths I've explored (or seen other people explore) and chosen not to follow. My impression of Rails' success has been that, compared to Java and PHP, it is really great. In no small part because those are really crappy languages; low-level and lacking expressiveness. There are also some important things Rails gets right, and I'm not going to ignore those. There's some important things PHP gets right too, and I try not to ignore those either. Java....... well, I guess it must get some things right too. People besides myself will have to figure out what to take from them.

In the end, there are some real distinctions between Rails and My Ideal Framework that go beyond these nitpicky details I bring up here; distinctions that are real tradeoffs, and where there can be real differentiation between us and them. Not trivial things, like blocks or threads or whitespace, but different perspectives on programming. But I'll talk about that another time.

Created 23 Apr '05

Comments:

I'm really confused why so few people have noticed Myghty. This Python web framework started as a direct Mason port, then added some MVC and advanced Resolver abilities (in the alpha release) that have turned it into an even more powerful web framework. The templating approach is already known and proven to scale for large deployment and development, as Amazon.com is using Mason.

While this particular code-base re-implementing Mason is young, it's running great and is quite solid. When I was looking for a Python web framework, I originally considered Cheetah, ZPT, and some of the other template designs but they all seemed deficient in some way compared to Mason which I had been using earlier. I'm currently using Myghty with SQLObject for a large production site at my company and the performance has been excellent, and being able to specify per Component Caching is a feature you won't want to live without in any templating language once you see it in operation.

# Ben Bangert