SRP - The Single Responsibility Principle

SRP - The Single Responsibility Principle

SRP is a part of SOLID, a mnemonic acronym which bundles a total of 5 design principles.

But what is SRP, is it important, and should you care?

What does it state?

I could give you my own definition now, but Robert C. Martin has already given a pretty great one when he first wrote about this principle:

"A class should have one, and only one reason to change"

Although he specifically stated classes, we can also apply the principle to modules and functions. So, when you have a class, a module, or a function, there should be exactly one reason to change code within it.

Not two, not three, only one.

A basic example

Let's take a look at a pretty basic example, a function that creates some report data. And as you will see, there is an issue within this function. It does more than one thing.

function createReportData(user) {
  const lowerCasedForename = user.forename.toLowerCase();
  const capitalizedForename = lowerCasedForename.charAt(0).toUpperCase() + lowerCasedForename.slice(1);
  const greeting = `Hello ${capitalizedForename}!`;
  return {
    id: user.id,
    name: user.name,
    forename: user.forename,
    greeting
  };
}

What happens if you want to change the greeting? => You have to change createReportData.

What happens if you want to add data to the report? => You have to change createReportData.

Why is it important?

SRP makes your code:

1. Testable

Your code is easier to test when it does exactly one thing because you only need to test for that one thing.

2. Reusable

Imagine you wanted to reuse the logic to create the greeting. Would you use createReportData?

By leveraging SRP you have small independent units which you can compose on-demand.

3. Readable

A unit that does only one thing is highly likely to be smaller in size and thus way more readable, especially as it usually has a descriptive naming associated with it.

4. Refactorable

When your units are small and each does only do one thing well, it's way easier for you to refactor it.

You don't need to take care of the other 50 lines doing something different when you're only interested in the first 5.

Applying SRP

You can fix the example above by creating individual functions, each with its own responsibility.

The following code snippet should give you an idea of how it might look:

function createGreeting(forename) {
  const lowerCasedForename = forename.toLowerCase();
  const capitalizedForename = lowerCasedForename.charAt(0).toUpperCase() + lowerCasedForename.slice(1);
  return `Hello ${capitalizedForename}!`;
}

function createReportData(user) {
  const greeting = createGreeting(user.forename);
  return {
    id: user.id,
    name: user.name,
    forename: user.forename,
    greeting
  };
}

Analyzing the changes

What happened?

The logic to create a greeting string is now a separate function. If the greeting ever changes, that's the place to apply the changes to.

createReportData does now only use createGreeting because the greeting is part of the data of the report. The function itself does, from now on, only have to change if, and only if, you want to add, remove or change the report data.

And as an added bonus: Your test cases become more separated and independent.

Should you care?

You should definitely care about SRP because it is usually one of the easier principles to apply. It doesn't cost that much energy to split your code, because you can always ask one question:

"When do I have to change this?"

Whenever you have more than one answer, you know that you can and should split your code into multiple functions.

SRP also comes with a lot of benefits as you have read here. => Why not take them with you for such little cost?

Show Your Support

If you liked this article, visit me on Twitter, and it would mean the world to me if you also liked and shared the thread on Twitter.