It’s been a lengthy two months since I decided to sit down and try to learn Ruby on Rails. Having already been through PHP and Python (both Pylons and Django), Rails is one of those technologies that you know you should learn as a web developer, but for me anyway, just never made the time, especially when there’s the above languages/frameworks available already.
Well, of course, Square’s web stack runs on Rails, and having experienced Rail developers (and a few colleagues whose Rails experience only predates me by a few weeks) provide tips and tricks for everyday coding tasks makes learning much easier than self-education. So here are some of my thoughts regarding Rails, from a developer having had some experience with the alternatives.
Doing the right thing
The first thing that struck me about Rails and the community around it is that the default convention adheres to good development practices. Rails already has the model-view-controller paradigm built-in, but on top of that it adds niceties such as RSpec for unit testing and Cucumber for integration testing. There’s database schema migration from code, settings for development versus production, and front-end integration is handled with Compass, SASS, and jQuery. Gems are packaged and auto-updated via managers like bundle.
In short, the framework provides a pretty comprehensive set of tools for today’s web development environment. It’s great to have all these things already integrated and ready for use, even if it makes all Rails apps feel homogenous.
Over the first hill
One of the idiosyncrasies of the Ruby language (and by extension, Rails) is that it’s meant to be readable; I’m finding out that means that the base corpus (i.e., keywords) is considerably larger than other languages, and while the code kinda reads like English after it’s been written, it’s actually an impediment to learning.
For one, there’s a variety of ways to accomplish the same task, with some keywords being simple syntactic sugar (e.g.,
unless) while others have greater implications (e.g.,
.size). Simple things like calling functions without
() and passing in parameters with a space is again great for readability, except when the meaning becomes ambiguous, which then requires the coder to figure out the workings of the language parser and add the appropriate punctuation. Rails especially has a bunch of magic functions meta-programmed into its models and controllers and views, codifying in additional rules to remember.
And while having a syntax that’s English-like is great, the convenience breaks down when the grammatically correct line of code that makes perfect sense to me wouldn’t be accepted by Ruby’s parser. There is a nice simplicity to a small, tight number of keywords and language conventions; the Ruby language itself seems to encapsulate the core of a lesser language…plus all the standard and extended libraries.
Upon my first day of work at Square (and first professional exposure to Rails), I was cautioned that Rails had a particular habit of strict versioning. That is, the version of gems matter – a lot. Gem dependency configurations tend to specify the exact version dependent libraries and repositories have every version available. Future versions do not guarantee compatibility and it’s usually a thankless chore to upgrade to a newer version.
This is a strange choice. In my mind, the entire point of code modularity (and hence, libraries, and Ruby gems) is separation by abstraction while maintaining an interface contract; that is, a good library ought to easily pluggable into your code, but it also should be easily replaceable by alternative or better code, by keeping the interface identical while performing the same set of actions. Microsoft is notorious for maintaining compatibility across operating systems and decades, and Rails seems to take the opposite route in breaking compatibility. With every version1.
Development environment happiness
At every company I’ve been, setting up and maintaining a development environment has been an afterthought. It’s easy enough to set up some test users locally and copy them to the production server for testing – when there are only one or two developers. As the number of people working on a codebase grows, getting a development environment defined (complete with packages, variables, database schemas, data) for a new developer or even keeping existing developers up-to-date is messy.
Which is why I like Rails’s insistence on keeping a set of test data in YAML files to be version controlled, as well as codifying database schema changes and system configurations. It then becomes trivial to clone a development environment onto a new machine, or wipe and recreate all the testing data, or coerce the program to a certain state to allow regression and integration tests to run properly.
I think I like Rails, and learning it now is probably ideal given my experience with other frameworks and languages (especially that have taken some Rails ideas, e.g., Django). It tries to deal with some pain points in modern web development, espouses good practice across the board, has its own style and flair, but also has its own set of quirks and frustrations. I’m also beginning to see how ActiveRecord is a core part of the framework and how its abstractions might be difficult to scale or replace.
It’s still a lot more fun than programming in MFC.
Admittedly Ruby isn’t the only language that does this. Python 3 breaks from Python 2, and PHP 5 breaks from PHP 4. Perhaps it’s the explicit nature of gem versioning that leaves this lingering impression.↩