Today I’ll continue my efforts in understanding the benefits of writing maintainable code. This post, as did the last one, is inspired by my reading of Sandi Metz’ book Practical Object-Oriented Design in Ruby. I have been covering books on design recently, with the goal of writing code thats easier for a human to both understand and change. In my next post I’ll be covering a TicTacToe game, I’ll either post the unfinished program with a list of challenges left to overcome, or I’ll be refactoring a complete v1 TicTacToe program.
If there was a theme in chapter2 of Sandi’s book, one could make a case that it would be enforcing single responsibility everywhere. Creating Classes and methods with a single responsibility makes them easier to change and reuse in the future, which can cut down on a developer’s technical debt.
Here’s an example pulled from Sandi’s book to kick off our single responsibility discussion.
This method violates the single responsibility principle. One responsibility of this method as it stands is to iterate over
wheels, and the second responsibility is that
diameters also calculates the diameter of every
wheel in the
If we wanted to refactor
diameters into two separate methods, each with only one responsibility we could do something like so:
Sandi points out that separating iteration from the action thats being performed on each element is a common case of multiple responsibility thats easy to recognize. But there are other cases where extracting extra responsibilities from methods aren’t so obvious.
Due to the fact that the
gear_inches method includes a calculation for a wheel’s diameter, we can extract this
wheel.diameter calculation into a new
diameter method which will contribute to an easier examination of this class’s responsibilities.
This refactor doesn’t change how a wheel diameter is calculated, instead it isolates the exact same behavior in a separate method. Here’s an excellent excerpt from Sandi describing the reasoning behind refactoring to follow SRP:
These refactorings are needed, not because the design is clear, but because it isn’t clear. You do not have to know where you are going to use good design practices to get there. Good practices reveal design.
Methods that have only a single responsibility provide the following benefits:
- It exposes previously hidden qualities: Having each method serve a single purpose makes the set of things the class does more obvious.
- It avoids the need for comments: If a bit of code inside a method needs a comment, extract that bit out into a separate method. The new method’s name will now serve the same purpose as the comment once did.
- It encourages code reuse: Other programmers will reuse the methods instead of duplicating the code. They’ll follow the pattern you have established and create small, reusable methods in return.
- It makes it easy to move methods into another class: With small methods, you can rearrange behavior without doing a lot of method extracting.
I hope that these past few posts have been as insightful for you as they have been for me. I’m looking forward to applying these new perspectives of thinking to some upcoming Ruby programs.
Here’s a view of a TicTacToe program that I’m working on completing. Can you point out places in need of single responsibility? Maybe its best for me to get it working first. 🙂
In either case (finished or still in progress), I’ll be covering this game in my next post.