Part of my series of easy primers on methods to eliminate code smell: needlessly lengthy or complex code.
Code smell: You’re typing the same lines of code more than twice.
This is part II of my blog post on abstracting methods. Part I, which you can find here, covered the Single Responsibility Principle. Here’s a brief recap:
Two fundamental principles of elegant code are the Single Responsibility Principle (SRP) and DRY (Don’t Repeat Yourself). They are as simple as the code they aim to inspire:
1) Whenever you notice yourself writing the same code more than twice, you should separate it into its own method. (DRY)
2) Each method should fulfill a single, discrete task. (SRP)
One of the most important things you can do to make your code more elegant doesn’t come from a method provided by Ruby, but from the methods you provide for yourself — namely, how you organize them. And if you follow the two principles above, they’ll naturally lead to shorter, cleaner code. In this post, I’ll cover DRY, an oft-repeated dictum among devs: Don’t Repeat Yourself.
don’t repeat yourself (DRY)
The assignment was to take the above nested hash of stats about two basketball teams and compose a variety of methods that would extract information from it. Let’s take a look at my first draft:
This implementation is complex and convoluted — each method has several nested layers of iterators. By the time you get to the middle where all of the logic is happening, you’re juggling so many variables that it’s hard to remember where you are and what data you’re dealing with.
This code is also full of repetition. Every time a method needs to find information regarding a specific player, we repeat the logic of finding that player. Four of the six methods require this process, and we reuse the same three lines of code three separate times. Very much not DRY.
One of our first tasks at Flatiron was to refactor this code along the guiding principle of Don’t Repeat Yourself. So, let’s see the cleaned up version:
The biggest improvement in this version comes from abstracting the task of finding a player’s stats into its own method, instead of iterating several levels down each time we need that information. (Remember how I mentioned doing that when I was talking about the SRP?) The new method takes just two lines, and now, every time we want to find a player’s info, it takes only one easily-readable line of code. We’ve done the same thing with the task of selecting a specific team.
Not only has doing this eliminated most repetition, but each discrete task is separated into its own method, and only one of the methods is over 5 lines long (it’s 6 lines…tsk tsk); the rest are considerably smaller.
Now, our methods can be reused in multiple places, you can pretty much immediately tell what each method is doing and how, and, as an added benefit, the program is shorter overall by 15 lines, or about 25%. (You can also tell that I had now learned about higher-level iterators #select and #each_with_object, my ensuing favorite.) It is, undeniably, more elegant code.
By following DRY and SRP, we make our code:
– more versatile
– easier to read
A future developer (including ourselves) who needed to read or debug this code would have a much easier and faster time doing so. And, were something about our data to change (for example, we restructured our hash or renamed some of our keys), adapting these methods would be much simpler. We would only have to update the information in a single place, instead of within each method that repeats the same task.
Such are the reasons for and benefits of Don’t Repeat Yourself and the Single Responsibility Principle. Try to keep an eye out for repetition and multi-purpose methods within your code, and abstract that functionality out into its own method. The more you code (and work with other developers’ code), the more you’ll appreciate how much these principles simplify it. In the meantime, stay DRY.