April 26, 2020

Single Responsibility Principle

By jobala

I used to understand the single responsibility principle to mean that a module should do one thing. This is not true and unfortunately is a common misunderstanding of the principle which leads to a fragmented codebase with thin classes — that have one or two methods — littering the codebase as we can see in this Stackoverflow question.

While researching for this article, I came across the SRP is a hoax blog post which in my opinion embodies the misunderstanding of this principle. The author shows the code below.

class AwsOcket {
  boolean exists() { /* ... */ }
  void read(final OutputStream output) { /* ... */ }
  void write(final InputStream input) { /* ... */ }
}

Then argues that according to the single responsibility principle the class does too many things because it checks for the existence of an AWS bucket, reads its content and modifies its content.

The author then goes ahead and puts each of the methods in their own class in ‘adherence’ to the single responsibility principle resulting in an explosion of classes after which he concludes that the single responsibility principle is a hoax.

To be fair, the author gets a number of things wrong. He errs the most by divorcing the code from the business function it supports. He also uses a sloppy interpretation of the principle and applies it to code that doesn’t have symptoms — accidental duplication and merge conflicts — common to codebases that violate the single responsibility principle.

The single responsibility principle states that a module should have one reason to change. The reasons to change are related to a function in the business which the software supports. Which is why I said the author erred by separating the code from the business it supports. Since changes in business functions are inspired by users, we can say that a module should be responsible to one, and only one user or stakeholder.

However, it is likely that multiple users or stakeholders will want to have the system changed in the same way. So what we are really saying is that a group of users or stakeholders will want the system changed in the same way. We’ll refer to the group as actors. Reducing the principle to a module should be responsible to one and only one actor. A module can be a class or source file depending on the programming language.

Now that we understand what the principle is, let’s look at a module that violates the principle and fix it.

Let’s assume we have the following class in a payroll processing system.

class  Employee:
	def calculate_pay():
	      # calculates pay

	def report_hours():
	      # report hours

	def save():
	      # save

The calculate_pay method is responsible to an accounting actor and the report_hours method is responsible to the HR actor. You can already see that this class is responsible to more than one actor. By having the calculate_pay and report_hours methods in the same class, we couple the accounting and HR actors. This leads to fragile code that is prone to accidental duplication.

To remove the coupling and in adherence to the single responsibility principle we should put the calculate_pay and report_hours methods in their own classes, so that each class is responsible to one and only one actor.

class PayCalculator:
	def calculate_pay()
	      # calculate pay

class HourReporter:
         def hour_reporter
               # report hours

In conclusion, the single responsibility is not about each class doing one thing but instead each class being responsible to one actor.