Writing Flexible Code with the Single Responsibility Principle
SOLID Principles and Maintainable Code
If you’ve been around software for a while, then you’ve almost certainly heard of the SOLID principles. In short, these are a set of principles intended to help developers write clean, well-structured, and easily-maintainable code. In software, as in any intellectual and creative endeavor, there is quite a bit of debate about the “right” way to do things. Different practitioners have different ideas about what is “right”, depending on their individual experiences and inclinations. However, the ideas prescribed by SOLID adherents have been widely adopted in the software community, and agree with them or not, they’re a useful set of principles from which to draw best practices. Moreover, SOLID has been thoroughly integrated into a broader set of Agile development practices and understanding them is thus a virtual requirement in the modern software industry.
Developers and bloggers have written seemingly ad infinitum about SOLID in various places across the web. In researching this article, I encountered many such resources, some of which are cited at the bottom of this article for your reference. So, if the SOLID principles are well-covered elsewhere, why write yet another article about them? In short, for my own edification. Writing about complex topics is one of the best ways to learn them yourself. And for that reason, I am planning a series of five articles — one on each of the SOLID principles. What follows is the first such article and focuses on the single responsibility principle. Although I don’t expect my addition to the corpus on this topic will be particularly unique, I hope that it will prove useful to some readers. And with that, let’s dive in.
A Quick Refresher on SOLID
SOLID is an acronym for a set of five software development principles, which if followed, are intended to help developers create flexible and clean code. The five principles are:
- The Single Responsibility Principle — Classes should have a single responsibility and thus only a single reason to change.
- The Open/Closed Principle — Classes and other entities should be open for extension but closed for modification.
- The Liskov Substitution Principle — Objects should be replaceable by their subtypes.
- The Interface Segregation Principle — Interfaces should be client specific rather than general.
- The Dependency Inversion Principle — Depend on abstractions rather than concretions.
The Single Responsibility Principle
The single responsibility principle (SRP) states that every class or module in a program should have responsibility for just a single piece of that program’s functionality. Further, the elements of that responsibility should be encapsulated by the responsible class rather than spread out in unrelated classes. The developer and chief evangelist of the SRP, Robert C. Martin, describes a responsibility as a “reason to change.” So, another way of putting the SRP is to say, as Martin does, that “a class should have only one reason to change.”
Before going any further it’s worth taking a look at the history of the SRP. Martin originally introduced the term in as part of his Principles of Object Oriented Design [1]. According to Martin, the SRP has origins in Tom Demarco’s idea of cohesion, which describes the extent to which elements in a given class/module are related and relevant to one another. Furthermore, it builds on David Parnas’ description of encapsulation, or information hiding, which says that attributes and behavior relevant to a given object should be bundled together and hidden from outside access [2]. Taken together, these ideas lead naturally to the principle that a given piece of software functionality (aka, a responsibility) should be bundled into a single class and hidden from other elements of the program — exposing only those pieces necessary to the functionality of the program as a whole.
On its face, this seems relatively straightforward. Individual pieces of a program’s functionality should be distributed to distinct entities that are capable of handling them without outside assistance. But how do you define an “individual piece” of a program? What, exactly, is a “responsibility” and how do you reason about it from a business perspective? Martin, popularly known as “Uncle Bob,” clarified just this concern in a 2014 blog article where he tied “responsibility” to the idea of interested actors [3]. Martin’s article is well worth a read, but to summarize, he argues that if a piece of software has several different kinds of users (aka, actors), then the disparate interests of each of those users defines a piece of that software’s responsibilities. Martin uses the example of C-Suite executives (COO, CTO, CFO), each of whom uses some piece of business software for different reasons. Moreover, when considering how software should be changed, each of those actors should be able to dictate changes in the software without affecting the interests of the other actors.
The “God Object”
Per usual, probably the best way to learn about the SRP is to see it in action. But to do that, we should perhaps first see what a program looks like when it does not adhere to the SRP. Let’s take a look at a simple program and see if we can break down its responsibilities. What follows is a brief Ruby program that outlines a class that describes the behaviors and attributes of space stations. Read through it and see if you can identify: a) the various responsibilities of objects instantiated by the SpaceStation class; and, b) the types of actors who might have an interest in an a space station’s activities.





