Single Responsibility Principle (SRP) (OOP - SOLID Principles)

_config.yml

We will now have a look at something popularised by Dr Uncle Bob Martin - who very kindly and thoughtfully answered a query I had regarding this very issue - we will look at the first of the SOLID principles: the single responsibility principle.

There is much confusion on what the Single Responsibility Principle (SRP) means exactly. Perhaps it’s best to start off by understanding the situation we are trying to avoid, by making sure our code doesn’t violate the SRP princile:

Example: Indian Airlines

Consider the airline company Indian Airlines - India’s national airline carrier. Suppose they only contain pilots and accountants. Each of these groups has different, but sometimes similar requirements.

The important point to note is that accountants and pilots represent two different axises of change. Now what does that mean? It means that either or both group can require changes to your code base that may conflict with each other.

If you don’t understand, things will become more clear with an example:

Notice how it has only one method?

  • Pilots use this method to calculate the amount they need to descend.

  • Accountants also use this method to calculate the losses the airline made over the past year.

Things are flying smoothly (and inefficiently) - and everyone in the airline is happy (except the passengers).

But then, as is wont to happen, the accountants are demanding that you make a change. Accounting rules have changed. Legislation has been passed. The government of India will now credit to the airline 10 times the profit they make. The accountants want that reflected in the bottom line when they add up their profit totals. So you duly oblige them:

You oblige accordingly. And you thoughtfully add a comment in there as well to help the next poor soul reading the code. You’re feeling very proud of yourself, and everybody is having champaign to celebrate the latest rort they’ve pulled over the taxpayer.

But then you start to get some angry phone calls from some pilots, who also happen to be using the total_numbers method to calculate how much they need to descend in order to safely land their airlines:

“Dude, what the….? All our planes are crashing. Did you change the total_numbers method?”

Oh no! Things look really bad. You look into the matter and realise that pilots are also using this method and getting unexpected results.

You immediately realise that the changes wanted by the accountant are not the changes wanted by the pilots.

Now you can see the problem:

  • IndianAirlines has two reasons to change: the pilots and secondly the accountants.

  • Accoridngly, that class violates the SRP principle.

What does the SRP try to avoid?

The SRP tries to avoid the situation where: a change to one piece of code, causes unexpected results in another. Uncle Bob uses this example which I’ll borrow from him: let’s say you take your car to the mechanic and ask him to fix your electric windows. He makes the change and you’re feeling happy. But when you try to start your car, you find that your engine no longer starts! Why should fixing the window cause the engine to break down?

Similarly in software, you do not want a situation where a change in one thing causes cascading errors in a completely different thing. The chances of this occurring will significantly decrease if the SRP principle is followed.

More examples

When I was trying to learn this principle, I paid up to learn the SRP from an online video course – from Udemy / CoursEra and the like. The tutorial used this analogy to explain the SRP: Imagine a CEO has many tasks:

  • Determining Company strategy.
  • Long term budget planning.
  • Fixing cars in the garage.

Accordingly, the first two sound very much CEO-ish, while the third sounds more like something a mechanic would do. Accordingly, according to the teacher, the third method fails the SRP. But why?

In my opinion you cannot answer this question without also answering another question:

  • Will that code ever change?
  • Where will the change come from. Will the change come from - other players in this scenario: Fred, or from Bob, or perhaps other people? Will both Fred and Bob be happy with any change the other makes? Or is there a chance that Fred and Bob will want different things? You cannot determine whether there is an SRP violation without also considering where sources of change will come from.

Scenario 1: The Shareholder sets the CEOs duties

The shareholder is the only person who will ever make a demand of the CEO. The only change will come from that one source. If that is the case, then we can leave the fixing cars method within the CEO class.

Scenario 2: The Shareholder sets the CEOs duties, and the Accountants will also help with the Budget

  • Will the Shareholder and Accountants want different things? If the answer is yes, then we have a problem. We don’t want a change in one to adversely affect the requirements of the other. In this case, the budget method violates the SRP. Accordingly we will need to “duplicate” this code, so that the accountants will have their own version of handling the budget, without affect the shareholders’ ability to similarly have their way of handing budgets.

Implementing this in your software:

As Bob Martin puts it:

Code that changes for the same reason should be grouped together. Code that changes for different reasons should be grouped separately.

This will prevent a situation where a change in one line of code will not adversely affect another party who is also using that code – but wanting a different outcome. If you have code which changes for different reasons next to each other, it is much more likely that they will soon become entangled. If that’s the case, then a change in one will cause unintended consequences for the other.

Or as I like to put it:

A person cannot serve two masters. If Master A tells him to dig, and Master B tells that same person to climb – then one of those masters will be disappointed.

How do we know whether a class violates the SRP (Single Responsibility Principle)? - What do some authoritative sources say?

(1) Ask the class as if it’s sentient?

Determining whether a class violates the SRP (Single Responsibility Principle) depends on asking the class, as if it’s sentient, whether its method makes any sense:

  • Mr Car, what is your engine (method name)?
  • Mr Car, what is your tire size (method name)?
  • Mr Car, what is your bank account (method name)?

Accordingly, if the method name doesn’t make sense to be in the class (like question three in the example above) then the SRP principle fails. Accordingly the bank account method should be deported from the Car class and placed in exile. But why? Why is the bank account relegated? Why can’t the car also manage the bank account? Why is the engine deemed to be within, and the bank account given over to diaspora?

While a useful tool to organise your classes, I feel that this explanation does not heave those doubts over the bleachers.

The second method is equally nebulous:

(2) Describe the class in one sentence?

We determine whether a class violates the SRP if, when describing the class, you are forced to use the word ‘and’. This school of thought says that the class should do the smallest possible useful thing - which is a good thought in and of itself, but it doesn’t help us understand the why - why a class voilates the SRP. It doesn’t tell us why we should separate things into two different classes. What is so wrong with a Car: travelling from A to B and also playing music on the radio?

So how do we determine whether there is an SRP (Single Responsibility Principle) violation - and what’s wrong with such violations anyway

I feel that the above two rules of thumb miss their mark. In my opinion, Uncle Bob best answers these questions when he states the principle as follows:

“A class should have only one reason to change.”

Summary

  • A class cannot serve two masters: he will love one and hate the other.
  • A class should have only one reason to change, and no more. Violations may cause far reaching and unintended results - especially in complex code-bases.

I hope that clears it up for you. Any questions, please feel free to ask.

Written on May 29, 2017