Single Responsibility Principle

One of the most common interview questions I have been asked is some version of “What does SOLID stand for and what does each principle mean?” I know there are thousands of articles already covering this subject with dozens more probably being created each week, but I’m going to add to the pile anyway! We’re going to take a deeper look at what each of these principles mean, how they should be used, and why they are important.

Starting with the S in SOLID…

*If you would like to check out code examples for this post you can find them on Github.

What is Solid

  • S stands for Single Responsibility Principle (SRP)
  • O stands for Open Closed Principle (OCP)
  • L stands for Liskov Substitution Principle (LSP)
  • I stands for Interface Segregation Principle (ISP)
  • D stands for Dependency Inversion Principle (DIP)

Background

You should read my posts on the other SOLID principles for a good understanding.

  1. Single Responsibility Principle
  2. Open/Closed Principle
  3. Liskov Substitution Principle
  4. Dependency Inversion Principle

Understanding the Single Responsibility Principle

SRP states that every module or class in an application should have exactly 1 responsibility, and therefore only 1 reason to change. This sounds pretty simple, but achieving that simplicity can get tricky at times. To best understand this principle, let’s break it down into its smaller parts.

What is “Single”?

This seems simple enough. Single means only one. Something that is single is isolated from any other parts. In our case it means that there is only one action being performed.

What is Considered a Responsibility?

A responsibility can be thought of as a family of actions which serve a particular purpose. This is the work being done by the system.

What is Change?

This is an alteration or modification of the existing code. These changes are typically caused by adding new features, fixing bugs, and restructuring the code to accommodate future changes. It is important here to realize the reason for a change is not defined as the events which led the developer to modify the logic behind a certain responsibility (such as the need to fix a bug or add a new feature) but rather the fact that the responsibility exists where it does. That was a very heavy statement so we should look at that a little deeper.

Basically, the external reasons a developer needs to make a change such as fixing a bug should not be considered for this principle. Instead, we should acknowledge the coupling between the term “reason to change” and “responsibility” and that a single responsibility amounts to a single reason to change. Take the code below as an example.

public void divide(double x, double y) {
    return x / y;
}

This code could possibly be dividing by 0, which would be a bug. Does the need for the developer to alter this code and fix this bug account for a reason to change? No. The result of the developer’s work might cause a conflict with SRP now that it needs to check for an invalid denominator AND perform the operation. I personally wouldn’t worry about it with such a trivial example, but I hope you get the point. I’ll move on.

Let’s apply these definitions to an example…

Does a class which stores the information for a book and knows how to display that information to the user follow this principle?

The short answer is no. To understand why, let’s look at it from the perspective of each of the definitions above.

Responsibility - Identify the actions being performed

  1. Storage of information
  2. Display of that information to the user

Single - This class has 2 responsibilities. It stores information AND displays that information. Notice my emphasis on the word “and” in that last sentence, because the use of this word is one of the easiest ways to identify that this principle is being broken.

Change - We would need to change this class if we either need to modify the way the information is being displayed (responsibility 2) OR if we need to modify what information is being stored (responsibility 1). Notice my use of the word “or” in that last sentence; just like the word “and” in the last section, the use of “or” here is the easiest way to identify that this principle is being broken.

Of course identifying that something is wrong is never enough. No one wants to be that guy who continuously points out issues but never has a solution for them (you know who you are). So, how do we fix it?

Well, the most straightforward way to resolve this issue is to isolate change. This means that we look closely at the responsibilities and separate them logically into smaller sections.

Big is bad, small is good

Continuing down this path we end up with two distinct classes.

  1. A class which stores the information for a book
  2. a class which displays that information to the user

Now when we look at each of these classes they have a single responsibility and a single reason to change.

  1. Responsible for storing information about a book and should only change when we need to modify the information being stored.
  2. Responsible for displaying the information about a book to the user and should only change when we need to modify the way we are displaying that information.

Why is SRP Important?

There are a number of reasons why adhering to the single responsibility principle is vital to creating good software. The primary reasons are listed below.

Increased Readability

Readability is the ease in which the code can be read and understood by others. If you keep your code short and focused it is easier for other developers to understand later.

Increased Cohesion

Cohesion is the degree to which the elements of a module belong together. If there is high cohesion then the module focuses on a single concept. Cohesion measures the strength of relationship between pieces of functionality with a given module. In other words, the degree of interaction within a module. By limiting the internal responsibilities you are ensuring that each element is closely related in functionality to the other elements.

Decreased Coupling

Coupling is the manner and degree of interdependence between software modules. This measures the strength of the relationship between modules; more simply put: the degree of interaction between 2 modules. By ensuring that your module focuses on a single responsibility you limit the number of reasons other modules have to interact with it.

Conclusion

The Single Responsibility Principle is a vital concept for the development of complex systems. It’s important to remember that complex solutions should be composed of identifiable, readable, and simple concepts.

Written on January 28, 2018