Twas Brillig, and the Slithy Code…

No matter what level of developer you are, at some point you will have the underrated joy of inheriting a legacy software project. And since we're fortunate enough to work in such a fast-paced community and ecosystem, "legacy" really encapsulates any piece of software more than a month or two old. Often though, we don't have time to appreciate how our ancestors used to write Ruby back in the days of Rails 2.3, or even (gasp) 2.1 — we need to get right to work. It's at this point that the nefarious Jabberwocky method can rear its ugly head.

The Jabberwock in the Room

When we first adopt a project, some of the language may seem like gibberish. Let's say we encounter this snippet of code in some controller:

@sword = VorpalSword.new @sword.snicker_snack! 

Looking at this code, we might expect to open up the VorpalSword model and find:

def snicker_snack!    Jabberwock.destroy_all end 

Unfortunately, in this all-too-contrived example, the VorpalSword class simply doesn't have that method!

The Jaws That Bite, the Claws That Catch!

Stuff and nonsense! Now we'll have to dig through and see if we can find a way to uncover this method. Let's start doing some sleuthing…

  • Maybe there's a method_missing in the VorpalSword class

  • Does VorpalSword inherit from anything?

  • Hmm…does it include or extend any modules?

  • It's probably just a plugin. Let's check the vendor/ folder…

  • Okay, maybe not. How about something under the lib/ folder…

  • Is "snicker_snack!" a gem?? Who would name a gem "snicker_snack!"

  • Did someone overwrite method_missing in ActiveRecord::Base?!

  • That's it, I'm switching to Scala!

Final Uffish Thoughts

Abstraction is a fantastic technique – we love to keep our software DRY and happy, but occasionally it can lead to code obfuscation. So before you go galumphing back to your project, take a few minutes and follow these suggestions to keep your code readable, and avoid those Jabberwocky methods:

  • Using modules is a self-documenting way to extend the functionality of your classes. If you do decide to use a shared library to cover some functionality, try to use modules rather than re-opening classes.

  • Be very careful when you use metaprogramming techniques like method_missing, or dynamic code creation. Writing a lot of crafty methods using a few lines of Ruby can be lots of fun, but sometimes a little bit of duplication can improve the readability of your code tenfold.

  • Lastly, documentation and tidy code is important. Try to organize your methods, and definitely drop a comment into the class if you know a shared library will be mutating it down the road.

Be sure to keep these tips in mind, and you'll find whoever inherits the code after you will chortle in his joy.