Ruby on Rails: Serious Software?
As a veteran of two and a half decades of this battleground we call Information Technology, I’ve seen a lot of technologies come and go, and I’ve seen a lot of companies fail to embrace technologies that could have made a significant difference in their ability to deliver software quickly and efficiently. Sadly, in far too many cases, IT leadership (management and senior architects) adopt a play-it-safe approach, opting to “ride it out” with tried-and-true technology stacks while their competitors (often smaller, newer and more nimble) embrace and fully exploit modern advances in technology.
Fifteen years ago, this often meant opting to continue to build mainframe-based applications using stalwarts like COBOL and CICS rather than upstarts like Java. Today, it means avoiding modern languages and frameworks like Ruby on Rails, favoring the safety of the familiar – Java and C#.NET.
In recent months, I’ve had the privilege to conduct “architecture assessments” for three very different companies – two large, established firms with large IT groups and well-established architectures, and a new, small firm with almost no permanent IT staff and a “do what makes sense” attitude toward technology.
The differences among these companies is striking. The largest and most established of these companies, coming from a strong J2EE background, was busy rebuilding a set of customer-facing applications, purportedly to increase reuse of components among them, and to reduce the ongoing cost of maintenance. This project, which was having some serious challenges, was not only using dated J2EE technology, but was piling an incredibly heavy, layered architecture on top of it – resulting in application code that – reuse benefits aside – is going to be as difficult to maintain as anything they currently have in production.
The smallest of these companies, in stark contrast, decided to throw away a VB.NET application that was only six years old, replacing it with a lightweight application my company built for them in Ruby on Rails, which is easily, without exaggeration, fifty times simpler to customize and maintain than the application it replaced.
This set of experiences has had me thinking lately. How much could be accomplished in large, established companies – which tend to have sizeable groups of talented software engineers – if they were to cling to the safety of the past a little less tightly, and more aggressively seek to harness the power of modern languages and frameworks?
Having personally built applications in technologies ranging from COBOL/CICS to PowerBuilder to J2EE to Grails and Rails, I have seen the steady increase in productivity offered with each set of advances in technology. I have also witnessed companies fail to embrace these benefits until well after their competition had done so, nearly always to their detriment.
If you are a CTO, IT manager, architect, or anyone who is responsible for the technical direction of your company’s suite of applications, you owe it to yourself to learn as much as you can about modern, dynamic languages (Groovy, Ruby, etc.) and the web application frameworks built on them (Grails, Rails, etc.). The leading reason companies tend to avoid these technologies – slow execution speed relative to Java or fully compiled languages – is usually given more importance than is warranted, since most performance problems tend to stem from sluggish database interactions or network data transmission time. And many large companies tend to overstate their own performance demands. Sure, your internal applications get a lot of use, but are they really under more of an onslaught than the thousands of public-facing web applications built in dynamic, interpreted languages?
Consider this an open letter to the guardians of reference architectures across the Fortune 1000. Do yourselves a favor. Do not ignore Ruby on Rails. or Groovy and Grails. There’s a whole segment of applications tailor-made for these technologies, and far too many of them are still being built with Enterprise Java Beans, by teams that are far too big and not nearly productive enough.
A little Groovy magic – Lists and Property Accessors
Dynamic languages like Groovy and Ruby are all about productivity. Not only do they eliminate the need to write tons of boilerplate code, they also contain all sorts of “syntactic sugar” – language features that let you accomplish a tremendous amount of work with very little code.
Most of these features – closures, ultra-convenient collection-oriented operators like the spread-dot (*.), etc., are well-documented. Some, however, are a bit more arcane, and not realizing they exist can actually cost you a lot of time if you stumble into them inadvertently.
The feature I have in mind at the moment is a very convenient but somewhat surprising bit of collection behavior in Groovy. I’ve been working with the language for quite a while, and have dutifully pored over books and language reference documents to become familiar with all of the groovy goodness at my disposal, but somehow I missed this one until someone on my project team found it – quite by accident.
Here’s the magic find. In Groovy, if you have a list of objects, you can access, on the list itself, properties that belong to objects within the list. The result, somewhat intuitively (but somehow quizzical at the same time), is a list of values of that property across all the members in the list. Here’s an example to illustrate what I mean – just copy this and run it as a Groovy script.
class Player {
def name
def teams
public String toString() {
"${name} - played for ${teams}"
}
}
def players =
[
new Player(name: "Greg Maddux", teams: ["Cubs", "Braves"]),
new Player(name: "Ron Santo", teams: ["Cubs", "White Sox"]),
new Player(name: "Billy Williams", teams: ["Cubs", "Athletics"]),
new Player(name: "Bruce Sutter", teams: ["Cubs", "Cardinals"]),
new Player(name: "Lou Brock", teams: ["Cubs", "Cardinals"]),
new Player(name: "Gary Gaetti", teams: ["Twins", "Cubs"]),
new Player(name: "Ron Cey", teams: ["Dodgers", "Cubs"]),
new Player(name: "Ryne Sandberg", teams: ["Cubs"]),
new Player(name: "Mark Grace", teams: ["Cubs", "Diamondbacks"]),
new Player(name: "Goose Gossage", teams: ["Athletics", "Yankees", "Cubs"]),
new Player(name: "Sammy Sosa", teams: ["Rangers", "White Sox", "Cubs"]),
new Player(name: "Larry Bowa", teams: ["Phillies", "Cubs"]),
new Player(name: "Rick Monday", teams: ["Dodgers", "Cubs"]),
new Player(name: "Dave Kingman", teams: ["Rangers", "Mets", "Cubs"]),
new Player(name: "Joe Girardi", teams: ["Cubs", "Cardinals", "Yankees"])
]
def playerNames = players.name
println "Here, amazingly enough, is a list containing the names of all those players:\n $(playerNames)"
Once you know this behavior exists, it’s pretty easy to find situations where it’s an insanely convenient feature. If you don’t know it exists, you can get some pretty confusing results. In our case, we were running a GORM query to retrieve a domain object using an alternate ID (expecting a single result), and incorrectly used the list() method (we should have used get(), which returns the domain object, whereas list() always returns a list).
In our code, after querying for the domain object, we accessed properties of the object, and were puzzled when instead of getting Strings and Integers and Dates, we were getting single-member lists of Strings and Integers and Dates. Each list contained the value we expected, inexplicably embedded in a List instance. It took a little head-scratching before we figured out that the root cause was that our query was returning a list containing our domain object, and our code that accessed the properties, which would have failed miserably in Java if attempting to treat a List as though it were a domain object, was happily drilling through the wall of that list and getting at its contents.
Syntactic sugar? Definitely. Violation of the principle of least surprise? Maybe. Will I use it, now that I know it’s a tool at my disposal? Absolutely.
Stay Groovy, my friends…
