Writing Readable Ruby
Ruby inherits the philosophy of “there’s more than one way to do it,” or TMTOWTDI, from Perl. Of course, TMTOWTDI is worthless unless at least a handful of those ways can be written clearly not just for the author, but (perhaps more importantly) for future readers and editors. So, how do you make the best use of the many ways Ruby and Rails allow you to do things?
Before Ruby, the experience I had in dynamic, interpreted languages was with Python – a language with a totally opposite motto, “There should be one, and preferably only one, obvious way to do it.” As such, Ruby and Rails were somewhat of a shock. The first thing that comes to mind about loose dynamically-typed languages like Perl and Ruby is usually, “But it’ll be so easy to write bad code!”
And it is! As the author of Eloquent Ruby says, Ruby is a “language for grownups,” meaning that writing ugly, hard-to-maintain code is certainly possible, but this freedom allows for beautifully expressive, concise, and readable code.
Here are some guidelines that I and other Highgroovers use to make sure we achieve the latter whenever we can:
- Write functional. Why write code that looks imperative when it doesn’t really change any state? Enumerable methods like
reducego a long way towards making code understandable in less time, as does the ubiquitous
- Use method synonyms that make sense. It seems like many newcomers to Ruby are wary of using more than one name for the same method. For example, you can retrieve the number of elements in an array with
#size. Which one you use depends on why the number of elements is needed, and what “sounds right” in the given section of code. Synonyms also make it easier to
- Make syntax English-like when reasonable. Readers of _why’s poignant guide know this already, and know how it can make reading code more like a game than a chore. This includes using the right synonyms for a method as above, as well as choosing your own variable and method names cleverly. Why name a method that returns a list of primes less than
primes(n)when it could just be
- Review! Of course, it isn’t always possible to stick with these guidelines. Business logic can get messy and working with legacy code can make English-like syntax a pipe dream. But having your code reviewed can reveal which bits can be fixed easily, as well as which bits are completely opaque to a newcomer.
As an example of putting these into action, let’s write a method that turns a hypothetical Rails model into a hash of its reports; we need to convert every report to a hash, combine them, and return it. Here’s the straight imperative way:
It gets the job done, but it ain’t pretty; again, the
#merge! method seems out of place, since it implies a change in state and the only thing really changing is the return value, which should be expected.
Here’s a more functional way:
This is a bit shorter, and the fact that
@reports is the “subject” being method chained and then returned makes it clearer that the return value is just some transformation of the model’s reports. But let’s try to make it almost readable English:
This is much shorter, and translates easily to its purpose: Take this instance’s reports, map them to hashes, and reduce them by merging them together. It’s also nearly point-free since the
reduce blocks just take method symbols.
Of course, personal tastes will vary on whether this is the ideal way of representing this or that method. But for me, the guidelines above have led to generally clearer, more comprehensible code during review.
How do you make sure your code is clear and concise?