7.4. The Essence So, Rails is not a toy, and it's not a gimmick. In my opinion, Rails represents a significant advance in the state of the art. You've probably seen frameworks like this one solve the database-with-UI problem in several different ways: Object-oriented development frameworks are flexible and robust. They're usually at a lower abstraction level, so they may not be as productive. You can use them to create flexible, robust, and powerful applications, but you're going to pay for it with productivity. Quick compromise frameworks trade conventional wisdom and sound design for implementation speed. PHP and Visual Basic, for example, compromise by trading design wisdom (frameworks should encourage separation of model and view logic) for development speed. Code generation frameworks generate most of the code for such an application at compile time. They trade the feedback cycle, easy maintenance, and often, customization, for speed. Customization point frameworks take a few parameters, like database tables or models, and build default implementations with a few well-defined anticipated customization points. These frameworks break down when the inventor's imagination doesn't anticipate important hook points. Rails is none of these. It uses macros to help you quickly generate code based on the structure of the database and a few well-placed macros. Since you effectively get generated code at runtime without tangled source code, you don't have to maintain the added code. Rails avoids the trap of customization points through Ruby's extensive hook points. You start with a clean design. You can then extend it through subclassing, changing class definitions, or any of the other metaprogramming techniques we discussed. You can even replace major Rails components like Active Record. Rails accelerates your development through meaningful conventions and defaults. By guiding your naming strategies in the database, Rails can save you lots of typing, and infer your intent by the consistent names that you provide. Rails keeps development convenient by providing the scripts and debugging tools that you need to do the job right. You can run the server from a script, manage your active record classes and the database tables behind them from a console, use generated test fixtures, or run performance tests from generated scripts. In Hackers and Painters (O'Reilly), Paul Graham suggested that great tools for good programmers are built by programmers to solve their own problems. I think he's on to something. Maybe Rails is so good because the authors built it to solve their own real- world problems first. As you've seen, Rails was created to help build the popular Base Camp and Back Pack projects. 7.4.1. Is Rails the Killer App? Is Rails the catalyst that will take us beyond Java? I'm not sure. Ruby does not have strong commercial backing. There's no JVM implementation that will yet run Rails, and the existing project has had some false starts. Ruby doesn't have the rich frameworks or name recognition of Python and Java. But it is an important advancement in productivity, in an important niche. And unlike Python, Groovy, and Lisp, Rails has generated an incredible buzz in the Java community right now. Something like Rails may be what eventually replaces Java in this web development niche. 7.4.2. Or Is Metaprogramming the Killer Technique? On another level, Rails may use a killer technique. Rails is one of the first commercially successful demonstrations of metaprogramming in Ruby, in combination with meaningful defaults. Let's dive a little deeper into metaprogramming. In some ways, this programming technique reminds me of another buzzword, the domain specific language (DSL) . A DSL solves a domain problem with a language whose syntax and keywords match ideas in the domain. Look ov er Active Record again. That framework lets you express ideas about the relationship between a database and a model, with keywords for ideas like inheritance, relationships, and name mappings. Rails may be the application that breaks the dam. Some of my mentors, like Stuart Halloway and Glenn Vanderburg, speak often about the importance of these techniques. By showing what's possible in Ruby, Rails may release a massive wave of metaprogramming frameworks custom built for a given domain. If we do see such a wave, it likely won't be in Java, because reflection is just too painful, and the wild mix of primitives and objects simply makes it too cumbersome. 7.4.3. Final Thoughts on Ruby and Rails To me, Ruby smells and feels like a good language, and Rails feels special. That alone is not enough to make it succeed. In this industry, individuals often make the difference, and the Davids (Thomas and Hansson) may be special enough to take this language and framework into the mainstream. Dave Thomas is a tireless promoter of all things pragmatic, and he seems to be focusing his publishing business on Ruby. He's already locked down many of the top Ruby authors by treating them well and providing a publishing experience that larger publishers cannot duplicate. Printed books provide credibility and exposure that languages need to succeed. David Heinemeier Hansson has a unique combination of a technical vision, a flair for understanding the end user, and a zest for marketing that you rarely find in one person. Rails is at once theoretically sound enough to attract hard-core web developers, and approachable enough to attract the masses. This kind of leadership often makes the difference between a successful technology, and a good technology that failed or never hit the mainstream. You don't often find technical passion and marketing vision wrapped up in a single mind, but when you do, great things can happen. Bill Gates built Microsoft from a BASIC shop operating out of a garage to the biggest software company in the world. Steve Jobs made Apple cool, left, and came back to overhaul its image and bring it back. Java, too, is full of technical visionaries. James Duncan Davidson fought the bureaucracy in Sun to break servlets into the mainstream by open sourcing Tomcat, and then did it again with Ant. Java seems to be losing the visionaries and technologists that I respect the most. Glenn Vanderburg may pay some of his bills with Java, but his public persona now spends more time in the Smalltalk (Seaside) and Ruby communities, bec ause of his interest in metaprogramming. James Duncan Davidson left the Java community years ago to focus on the Apple operating system, primarily on Objective C. Many of those who remain seem to be here because Java pays the bills. Ruby and Rails seem to be going in the other direction. Increasingly, Rails finds itself in the middle of controversy. You've probably heard all the arguments: Can it possibly scale? Is it ready for the enterprise? What will you do without all of those Java programmers and libraries? Isn't Rails a toy? Do you really want to run your business on a scripting language? In the first half of 2005, I saw more than two dozen blogs attacking Rails. Some of the arguments are valid. Java can do some things that Ruby can't, yet. Other arguments are born out of ignorance or misconceptions. I'm intrigued, because more and more in the Java community are paying attention. The Davids certainly get the Rails message out there. We're about to see whether that spotlight will provide energy for growth, or a sweltering, destructive, withering heat. 8.1. The Problem Web development, for all its usefulness, often happens with a curious inelegance. It's kind of like making sausage. I like the result, but I don't want to see how it's made. Web programming in Java was better than web programming in alternative languages. It gave you more structure with easier maintenance and, often, better scalability than Visual Basic or Perl-based approaches, and an easier programming model than C++. But for all the benefits, certain problems make it seem clunky and awkward. 8.1.1. What You Want Current web application servers might be powerful, but they're not convenient or natural. So, what is convenient and natural? It shouldn't take too much effort to figure that out. What if your controllers looked like this: if (logon.show( ) = = true) { mainPage.show( ); } or this: if (shoppingCart.verify( )) checkout.show( ); That's better. What you really want to do is encapsulate the presentation of one or more web screens in a method. Then, more sophisticated page flows would not be a problem. You could simply roll up more and more pages into higher-level components. For example, you could take this code: checkoutAddress.showForm( ); if(checkoutAddress.getSeparateBilling) checkoutBilling.showForm( ); creditCardNumber.showForm( ); and roll it up onto a method: public static void showCheckoutWizard( ) { checkoutAddress.showForm( ); if(checkoutAddress.getSeparateBilling) checkoutBilling.showForm( ); creditCardNumber.showForm( ); } so the usage becomes: cart.showCheckoutWizard( ); in its cleaner, refactored form. But you can't code that way, because your web server won't let you. Creators of most web application servers will sell their soul to keep things stateless and scalable. 8.1.2. Statelessness Think of living without any short-term memory. Normal conversations in day-to- day life would be nearly impossible. Think of the logistics: You'd have to write down every important phrase of every conversation as it occurred. Then, when someone asked you a question, you'd have to look up the history of your conversation with that person before you could answer. To optimize things, you'd have to decide how much information you should keep close bysay, in your briefcaseversus at home, in your filing cabinets. When information got too old, you'd need to throw it out. You'd have to maintain this whole system and revisit it when it didn't meet your needs. That's the status quo for web developers. Your briefcase is the HTTP session, and your file cabinet at home is the relational database. It's an insane proposition, but we deal with the tedium because the Web is so important, and stateless solutions scale better. So, you willingly take a pretty large stride away from the ideal solution. Still, each time you struggle with the awkward little edge cases, you ask yourself if there's a better way, some kind of abstraction that fits the problem more neatly. 8.1.3. The Back Button Saving state within simple conversations does not cover the whole problem. On the Web, conversations are not linear. Users can and do change their minds, pressing the Back button. Some assumptions that you've made as you continue to accumulate data may no longer apply. Sometimes, you'll want to keep the user from going back, such as when she's made a purchase, or done something to force a committed change in a relational database. In these cases, you can simply punt and disable the Back button. Most often, you need to build special support for the Back button. You may even have to remove data from a database that a user would not have seen yet. Worse, many web designers simply don't solve the problem, and tell the user to expect unintuitive behavior. You've taken one more step back, away from the ideal. Once again, this awkward Back button forces you to deal with things on a case-by-case basis, and it just doesn't feel right. 8.1.4. Navigation Web development in Java focuses an incredible amount of brain power around navigation and flow . You'd think controlling flow from the server side would be natural, but servers can't update clientsthey can only respond to requests. This simple little truism forces servers to handle hundreds of little requests rather than a couple dozen application flows. It's also hard to synchronize the user interface with the model. You'd like to use a simple method call that controls the user interface and model, but you can't. The web server just doesn't work that way. And you're stepping back again, and you've got that sinking suspicion that there's a cliff behind you somewhere. 8.1.5. Continuation Servers to the Rescue A new class of web servers called continuation servers is starting to make some real noise. A continuation server uses a programming construct called the continuation to keep enough information about a request to be able to completely reconstruct the context. In technical terms, a continuation saves the execution environment, including the call stack. In practical terms, using continuations in a web server lets the server maintain context for you, freeing you to program in a more natural way. . higher-level components. For example, you could take this code: checkoutAddress.showForm( ); if(checkoutAddress.getSeparateBilling) checkoutBilling.showForm( ); creditCardNumber.showForm( ); and. before you could answer. To optimize things, you'd have to decide how much information you should keep close bysay, in your briefcaseversus at home, in your filing cabinets. When information. showCheckoutWizard( ) { checkoutAddress.showForm( ); if(checkoutAddress.getSeparateBilling) checkoutBilling.showForm( ); creditCardNumber.showForm( ); } so the usage becomes: cart.showCheckoutWizard(