At the Forge - Assessing Ruby on Rails
Several years ago, at the height of the dot-com boom, the phone was ringing off the hook with consulting work. My employees and I scrambled to fulfill all of the projects people were throwing at us. In the midst of this boom, it became obvious that nearly every project had similar characteristics, and that we were spending time (and clients' money) re-inventing the wheel with each new project. We began to look for ways in which we could reuse code, or at least techniques, across different projects. This, we assumed, would make us not only a more-competitive business, but it also would make our day-to-day work more interesting. It is, after all, more interesting to work on the new and different elements of each project, rather than creating yet another user-group permission system.
We soon abandoned our plans for a common code system, in part because other developers had not only solved many of these problems, but had released their solutions under an open-source license. And so over the years, we did a variety of different projects using Web development frameworks, many of which I have described in earlier editions of At the Forge.
But as anyone who has worked with such frameworks has learned, there is no free lunch. Nearly every framework tries to shoehorn you into doing things in a particular way, making its own set of trade-offs that might (or might not) fit the way you want to develop solutions. I have used a number of these frameworks over the years, and although I enjoyed various parts of them, I didn't feel like any of them allowed me to express myself the way I wanted.
I'm, thus, one of many developers who has become increasingly excited about a relative newcomer to the arena, known as Ruby on Rails. As we have seen during the last few months, Rails is a framework that provides a number of different functions, including an object-relational mapper, an MVC (model-view-controller) approach to design, an integrated templating system and built-in support for testing.
Rails has become extremely popular in the year or so since it was first released, and though it is still rough around some edges, the momentum is undeniable. Moreover, Rails has now become so popular that other frameworks are springing up, claiming to be Rails-like or with many features that are “just like Rails” or “better than Rails”.
Why are so many people excited about Rails? More importantly, should you consider using it for your next Web/database project? Finally, what trade-offs does it force developers to make, and how might these trade-offs affect your decisions?
I have been developing Web applications since the days when the phrase Web application described CGI programs that sent e-mail, rather than a billion-dollar industry. Every framework I have used has brought something to the table, and has made it easier for me to develop applications in one or more ways. At the same time, each frustrated me with the trade-offs I was expected to make in order to work with the system.
For example, Mason was one of the first Web development frameworks that I worked with, and it spoiled me with its flexibility and ease of use. Mason is written in Perl, and it is designed to work most easily with mod_perl and Apache. Installation and configuration have become trivially simple over the years, assuming you already have a working copy of Apache and mod_perl on your server. Also, Mason integrates beautifully with the many Perl modules available on CPAN, and with the mature and robust development tools the Perl community has created over the years. When I have to create an on-line system with Perl, Mason is definitely the first tool I turn to.
But what has always frustrated me with Mason is the small number of components that come with the system. Sure, I could create a system for handling user accounts, and even for permissions and groups. But did I really want to write such code from scratch for every project I worked on? Moreover, although Mason's templates are highly expressive for developers, they include a great deal of Perl code and unusual constructs that can scare or surprise nontechnical developers.
I was thus drawn to OpenACS, an Open Source community system that has a significantly smaller following than Mason. However, the OpenACS templating system separated each viewed page into two components, one written in Tcl and the other in a modified form of HTML, with a specified “contract” between the two. In addition, OpenACS came with a standard data model designed to be used by all of the different applications in the system. You didn't need to worry about creating a registration module, because one came standard with the system. You also didn't need to create forums, Weblogs or calendars, because those also came in the standard system.
The centralized, standard data model and set of administrative applications was certainly appealing; however, OpenACS also had its problems. Perhaps the biggest one was the weird way in which OpenACS implemented its data model, using a relational database to keep track of hierarchies and objects. This system had a great deal of intellectual appeal; relational databases are fast, stable and cheap, and object-oriented programming has made it easier to model many types of data. But the marriage of the two meant that creating even a simple OpenACS application could be quite complicated. Moreover, as the OpenACS community grew, the data models became increasingly difficult to keep small, because everyone's needs were slightly different.
I also looked into Zope, a Web development framework written largely in Python. Zope has a large, strong community, and it continues to be developed and enhanced by Zope Corporation. Zope has many attractive features, including an extremely robust development environment, compartmentalized “products” that can be added and upgraded individually, and a sophisticated system of users, roles and permissions. Zope also pioneered the idea of object publishing, in which a URL describes the method that should be called on a particular object. Thus the URL /Foo/bar means that we're invoking Foo.bar, passing inputs via the HTTP request and receiving any output via the HTTP response.
The most commonly heard complaint about Zope is that it is complicated to learn. This is somewhat true; it took some time before I found myself understanding the “Zope zen”, as it is known. In addition, many things I would expect to be straightforward require some coding acrobatics in order to work correctly—which might be a reflection on my coding style, but it also seems to be an artifact of how some Zope design decisions were made and the pervasive way in which objects are used within Zope.
Early on, Zope's designers decided to avoid the problems associated with relational databases by building their own object-oriented database. On the one hand, this gave Zope a number of big advantages over its rivals, including the ability to undo changes to the system, built-in permissions and a storage system that mapped perfectly onto data types in Zope. But given the speed and pervasive nature of relational databases, SQL was also necessary. Zope thus provides the ability to connect to and work with relational databases, using a version of its DTML-templating language.
But this means that many Zope products—and certainly all of the products I have worked on—must coordinate the relational and object databases. This is generally a not-too-terrible way to handle things, but I always have ended up wondering why my life needs to be so complicated. And for all of its sophistication, I have often found myself creating the same types of create-update-delete methods and templates time after time.
So, it should come as no surprise that Ruby on Rails fills many of the gaps I have long perceived for Web developers. That said, my above descriptions also should make it clear where I think Rails should go if it is to continue to be successful.
One of the biggest draws for Rails is the speed and ease with which developers can create code that talks to a relational database. And although I am far from convinced by demos of what you can do in 15 minutes, my experience confirms that the demos are quite realistic. This is because Rails assumes you will create your database tables following its conventions, such as plural table names, ID fields named id and time/date fields ending with _at.
If you follow these conventions, you will discover you have to write a ridiculously small amount of code to handle many standard situations. Indeed, you probably will find yourself writing a handful of lines of code for many of the model objects you create, because the Active Record mapper within Rails will have done almost all of the work for you.
This means that much of the work needed for a Rails application is on the controllers (that is, objects whose methods are exposed via URLs) and views (that is, Ruby-HTML hybrid templates). Each controller method can produce its own output in plain text, HTML or via a template of the same name in the views directory. There is even a built-in Rails function for sending a file to the user, allowing you to set up downloads of binary files without having to worry about the syntax for specifying MIME types and filenames.
Zope advocates undoubtedly will say that these latter features are available in Zope, and have been around for several years. This is true—but figuring out how to use them, and where they go, can be maddeningly difficult for newcomers. By providing reasonable defaults for a great number of activities, and then allowing developers to change those defaults, Rails manages to make the simple cases trivially easy, and the difficult cases only moderately hard. Moreover, the scaffolding generators included with Rails provide just enough of a basic, initial set of controllers and templates to get people going without having to spend hours creating and modifying various code files.
Because of these intelligent defaults, there is a limited number of objects and methods that a new Rails developer must master before starting to create an application. This stands in stark contrast with all of the other frameworks I described, which require understanding a fairly large number of objects and methods, as well as how they fit together, in order to work productively. True, Rails is growing in size and sophistication, and it runs the risk of gaining some of the bloat we see with more-established frameworks. So far, Rails has managed to avoid many of those problems and complications, and the developers seem committed to keeping things as simple as possible.
As I wrote above, each Web development framework has made its own set of design trade-offs. What is missing from Rails that would make it even better? What should you keep in mind when considering whether to use Rails for an application you are developing?
First, working with Rails requires an acceptance of the Ruby language. I had been looking at Ruby for some time before working with Rails, and I am increasingly enjoying it. However, undoubtedly many programmers will resent elements of Ruby, from the syntax to the object model. Ruby is also less mature than Perl and PHP when it comes to third-party add-on libraries, which means that you might need to write some specialized routines yourself, rather than rely on the community for support. And finally, Ruby lacks true Unicode support, which means that many multilingual Web sites will be unable to use it for the time being.
But if you are willing to consider Ruby as a language for Web development, should you use Rails? I would argue that the smaller the development team and the more ambitious the project, the more likely you are to benefit from Rails. Very small projects don't need the overhead that Rails requires, and they are probably best served with CGI programs and PHP. But the moment you need a relational database with more than one table, you're likely to benefit from working with Rails.
However, both Ruby and Rails are designed for small teams of programmers, and even programmers who are working alone. If more than one person is going to work on a Rails project successfully, it will require great discipline on the part of the programmers to ensure that no one modifies files that are in someone else's purview. The fact that each Rails application resides in a single directory might increase the likelihood for such confusion.
Large projects, thus, might benefit from some of the larger frameworks, such as Zope—or even one of the many Java-based projects that has been released in recent years. My biggest hangup with Java is that it is relatively cumbersome and slow, especially when compared with languages such as Perl, Python and Ruby. But when you are working on a large project with many other programmers, it might be an advantage to have more compile-time checking, explicit declarations and safeguards that are missing from languages such as Ruby.
You also might want to consider the sophistication of your Web designers when thinking about Rails as a platform. Some relish the idea of working with code within templates, and others are scared of it and might even erase or change code. I still think that ZPT and OpenACS templates are a better system of templates, so I was encouraged by the recent announcement of Liquid, a templating system for Rails in the style of PHP's Smarty. I have been impressed by Smarty in the past, and I think this might help speed the introduction of Rails into large, established Web shops.
The fact that each Rails application uses a single directory of plain-text files has both advantages and disadvantages. One major advantage is that everything can be stored easily in CVS or a similar version-control system; installing the application in a new location can be as simple as checking out the code. However, this approach means that it's a bit harder to have multiple instances of the same application running on the same server, as with OpenACS packages and Zope products. We always can create multiple copies of the Rails application's directory tree, but it doesn't seem possible to have multiple instances of the same package.
As I mentioned above, I was originally quite attracted to OpenACS because of its single, standardized data model. I now understand that such a heavy, centralized data model is almost always going to be inadequate, but I still have to wonder why Rails doesn't come with any generic set of built-in permissions or registration. The answer, I suppose, is the growing number of Rails plugins, among which are several registration systems that can be integrated into existing Rails applications. I still would prefer to see more standardization on this front, but that is probably a lost cause at this point.
Finally, one problem Rails shares with every other environment is that of legacy code. Rails is so new, and so different, does it mean that its adoption will force us to abandon what we have already done? Possibly, but not necessarily. Rather than rewrite a mature Perl library in Ruby, I simply wrote a wrapper using XML-RPC. Ruby has an easy-to-use XML-RPC client, which I used within my Rails application to contact the Perl code. This has worked smoothly and easily, and it means I can benefit from Rails and CPAN at the same time. The fact that Rails lets developers override its database naming conventions also means it can be used with existing databases, rather than force users to create new database schemas that conform with Rails conventions.
Some people are hailing the arrival of Rails as the beginning of a new era in Web development. And indeed, I think Rails has set a new standard for what we can expect in a Web development framework. No longer will developers believe that it should take more than a few lines of code to create a “hello, world” program, or even to handle basic database actions.
Also, Rails is starting to convince developers that common conventions can be conducive to rapid, bug-free development. It took many years for developers to agree that garbage-collected languages were an improvement over malloc(), and it is taking a similarly long time for us to agree that conventions are better than configuration files. But the popularity of Rails probably means that we are increasingly ready for such a change.
Although no Web development framework is perfect, I believe that Rails has hit the sweet spot for many of the applications I have found myself writing for more than a decade. Both Ruby (the language) and Rails (the framework) are still maturing—but if this is how they are as relatively immature tools, I can't wait to see what they're like when they are finally ready.
Resources for this article: /article/8693.
Reuven M. Lerner, a longtime Web/database consultant, is currently a PhD student in Learning Sciences at Northwestern University in Evanston, Illinois. He and his wife recently celebrated the birth of their third child, a boy.