Maintaining Legacy Rails
Something that has been bugging me for a long time is that our oldest Rails apps will be 5 years old soon, an eternity in software terms, and yet the topic of maintenance is rarely raised in the community. Rails is exciting because it is so easy and quick to launch new sites and applications, and its practices have influenced almost every web framework out there; life is certainly rich if you’re a creator right now. But while a great deal of the sites launched each day are reasonably “throwaway” and not built for the long term, there are plenty of sites out there that have to stick around for a while.
Anyway, this rising issue of maintainence has been tumbling around in my head for a couple of years. Then, in the middle of 2010 and after a specatcular amount of work, Rails 3 was released. Around that time, Charles Nutter of JRuby fame tweeted: “I hear the words ‘legacy codebase’ applied to Rails apps more and more lately. Maturity or obsolescence?”. I’ve also alluded to issues around this in the past too. We’re hitting a stage where some major customer facing apps are getting long in the tooth, and have also lost their original developers.
The scary thing we face is: Rails is fantastic because it develops so rapidly and makes us very productive, but the very danger of this is that the constantly moving target can become a maintenance nightmare. Gems are constantly changing in subtle ways, dependencies break, and developers move on to new gigs. Now an abondoned open source project is sad, but not irretrievable. But a hard to maintain enterprise scale app is another story – its maintenance can be a thorny issue for an organisation, and can cost real money.
I’ve come across apps migrated from Rails 1.1, and done a couple of migrations through the major revisions myself, and they certainly present some challenges. Indeed, to get them to Rails 3 can sometimes trigger rewriting major parts of the systems.
Some will point to a fully packed test suite as the answer. But is it enough? Can a test suite overcome architectural complexity? Can a test suite explain intentions and historical decisions clearly? The answer to all of these is: sometimes.
So, how do we future proof our apps? And how do we take control of existing apps in maintenance mode? I have a number of suggestions:
-
Know the dependencies - by this I mean we need to know everything the app relies on. Ever installed a gem without looking at it’s source? Bad move. Open it up and get reading. If the code is a mess, has a poor API, or is mising tests then you shouldn’t be using it if your app needs to last.
-
Know your code - have a full test suite with a high level of coverage.
-
Update the platform - smaller, incremental updates will be easier on you than rarer large updates.
-
Document the intentions - While tests can give you a good overview of the codebase, and even the intentions if written well, I don’t want to be relying on them to explain everything. For a long term Rails app of signigicant size, I need to know why things are done a certain way. A key thing to slip through the gaps here is non-functional requirements. Write them down, and then relate the code back to them (via comments, doco etc)
What have I missed? What else can help with maintainence of a large, one day legacy, Rails app? (either for development or maintenance time)