On reading Paul Graham's essays on computer languages, I was struck by some interesting points he makes. This blog entry could just as well be called "What Paul Graham made me realize about Ruby and Rails."
First,
new languages may be trending towards LISP, perhaps because LISP was initially a theoretical exercise by McCarthy, a gedankenexperiment not really designed to be shoehorned into 1958 computational constraints, but rather discovered "when you try to axiomatize computation." (See Graham's full postscript paper
The Roots of Lisp.) FORTRAN and C, on the other hand, took a lot of cues from the hardware; they had to be fast. Over time, the lower-level languages have been relegated to handle algorithmically-simple, computationally-needy problems, while the scripting languages - PERL, PHP, Python, Ruby - have been getting fast and moving from simple glue to more complex processing tasks.
Two decades have passed since I looked at LISP code, and I'm wondering if I like Ruby because it's as powerful as that language in my distant memory, yet more aesthetically pleasing syntax-wise since I'd been coding in C, C++, and PHP. It's refreshing to be using a true object-oriented (message-based) language that has strong (as in
"walks like a duck") typing,
closures, and seemingly dynamic everything (types, open classes). Although I'm a relative newcomer to Ruby and Rails, I can see this is a language I'm going to
enjoy using and figuring out.
Graham talks about
bottom-up design, changing the language to suit the problem. It suggests one reason why Rails looks so good compared to other web frameworks: Rails looks like souped-up Ruby and not just a bunch of classes, procedure calls, and bolted-on code.
"In Lisp, you don't just write your program down toward the language, you also build the language up toward your program," Graham wrote. "Language and program evolve together... In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient." That's a pretty good description from 1993 on Rails development and points to a not-so-subtle difference between the web frameworks.
Just as standard Ruby lets you use
"attr_writer :some_attribute", Rails provides a formalism for defining data relationships like
"has_many :data_thing". The Ruby Way seems to run deep.
[1] It'll be interesting to see if Rails manages to adhere to Ruby's style as it expands.
When answering the question "Could Rails be built without Ruby?", I think you have to address not only the functionality but the aesthetics as well. It's more than the simple lines-of-code metric. It's whether you've built a language up towards a
Rails language that solves problems common in web development. As Graham points out, you could build Rails out of any language that's Turing-equivalent; the real question is in your quest to duplicate the aesthetics, whether you'd wind up doing a back-door implementation of a Ruby interpreter in the process. For Python users, the port might not be incredibly difficult. For C users, it might be easier to build a Ruby interpreter.
One of the knocks against Zope 2, a leading Python app and backend server framework, was how un-
Pythonic the framework appeared to some developers. The architects of a ground-up rewrite,
Zope X3, took this to heart. In their early developmental roadmap, they wrote: "We know that Python is a great language because it has a small core of concepts, values explicitness and consistency, and has a great standard library. Zope will follow this lead." At least one Pythonista,
Xavier Defrang, thinks "there will never be anything like [Rails] in Python, PHP, Perl or Java just because
language matters... It's so great to finally get your hands on a framework which is primarly designed with
simplicity and elegance in mind instead of trying to show up as a Design Pattern gallery."
Defrang's complaint about the heavy-handed use of patterns is telling. Graham ended one of his essays with the following note:
..in the OO world you hear a good deal about "patterns." I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work. When I see paterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough - often that I'm generating by hand the expansions of some macro that I need to write.
Here, I think Graham's interpretation of pattern is synonymous with "duplication," and very different than how a Martin Fowler would think of a pattern - namely, it's a mechanism for formalizing the how
and the when.
Rails founder,
David Heinemeier Hansson, digs patterns so much he even created nice diagrams for
Martin Fowler's catalog of patterns. Rails exemplifies the Model-View-Controller (MVC) pattern. A number of other patterns, like Active Records, influenced the design of the framework, sometimes so seamlessly that
even critics don't realize they are there. The developers of Rails attempt to abstract away as much of the
regularity as possible. In Rail-speak, they call it the "Don't Repeat Yourself" (DRY) principle. Conventions allow us to extract model information from the database without replicating it in code. Helpers relieve us of the need to create forms and other view-oriented chunks of code. Rails is not the first framework to attempt these simplifications, but it may be the cleanest because the abstractions fit into the style of the Ruby language.
Some frameworks embrace the regularity, even codify it - possibly with additional languages - so tools can analyze and auto-generate portions of the code. When humans look at the code, they see a verbose melange. The common understanding is to use tools when programming in such an environment. Development proceeds not so much in language X as in language X within tool Y. I think Ruby on Rails takes the opposite approach, where the underlying code is as terse as possible using Ruby constructs and
metaprogramming (like
has_many above), perhaps because Rails aficianados lack a custom-fit IDE like VisualStudio.NET.
There are many Rails-specific keywords, as you'd expect when establishing any language for web applications, but those keywords are used in a Ruby-like way. This can be contrasted to frameworks which require mastering not only new identifiers but new methodologies which don't blend into the underlying language. Ruby on Rails does have code-generating scripts that quickly establish scaffolds, and I wonder if this suggests even more abstraction is desirable.
Rails hasn't hit the 1.0 version yet. It's a work of art in progress, with tough decisions still to be made on what contributions to let into future Rails versions and what to leave out. As I dive deeper into Ruby and Rails programming, I'll try to wrap my mind around optimal levels of abstractions, how patterns fit, and how server-side code can best engage a world filled with heterogeneous and possibly rich clients. The Graham essays made me think about and revisit a number of issues in programming and web development. Even if you don't agree with what he writes, that's the mark of good writing.
[1]
Oliver Steele has come to the same conclusion.
Comments are closed
2 Comments
why not Lisp then? by Anonymous (2006-05-25)
Surrogate keys by Anonymous (2006-05-25)