• Skip to main content
  • Skip to primary sidebar
  • Skip to footer

Alex Aitken

Technical and Engineering Leadership, Coaching, and Mentorship

S for Single Responsibility Principle

May 7, 2018 By Alex Leave a Comment

A class should have only one reason to change.
Robert C. Martin

I’m going to start a five blog post journey about the five principles behind SOLID. I’ll describe these in my own words and give examples of what breaks the rule and how to fix it. Now, what I’m not going to prescribe, is that you must be SOLID all the time. Because that is not true. Sometimes, you need to break a few rules.

The first rule I’m going to be talking about is ‘S’. S for Single Responsibility Principle. The name of the concept gives it away. What we’re talking about, is that each class should be responsible for one thing, and one thing only. None of this “oh but I need this class to do A and B”. No. You can split these functionalities up into separate classes, and you’ll be happy in the long run.

Now, not everyone agrees with these principles. A lot of engineers haven’t even heard of them. That’s okay. But, let me explain them in my way anyway. Because I find these principles useful and I tend to mostly follow them when I can.

Breaking the principle

Let’s take a practical example. Let’s say you have a list of objects, and you want to apply some business logic to them, and that will also map them, and then we want to add them to a stored list on your class. It doesn’t sound too bad, right? It’s testable. It’s simple. All your logic is in one place. But what happens if everyone thinks like that? What happens when things start to get more complicated?

public class MyObject
{
    public int MyInt { get; set; }
}

public class MyTransformedObject
{
    public string MyInt { get; set; }
}

public class MyBusinessLogicClass
{
    private readonly List<MyTransformedObject> objects = new List<MyTransformedObject>();

    public void AddToList(List<MyObject> list)
    {
        list.ForEach(i => i.MyInt += 10);
        var localList = list.Select(i => new MyTransformedObject { MyInt = i.MyInt.ToString() });
        objects.AddRange(localList);
    }
}

Obviously, this example is not code you’d write. Let’s take Martin’s quote “A class should have only one reason to change.”  In this case, you have the change in the mapping, the change in the business logic, or the change in how you add to the list. Because you’re doing three things at once, you’re breaking the Single Responsibility Principle.

Fix using the principle

Step one: Let’s take out the mapping.

public class MyObject
{
    public int MyInt { get; set; }
}

public class MyTransformedObject
{
    public string MyInt { get; set; }
}

public class MyObjectMapper
{
    public MyTransformedObject Map(MyObject i)
    {
        return new MyTransformedObject {MyInt = i.MyInt.ToString()};
    } 
}

public class MyBusinessLogicClass
{
    private readonly List<MyTransformedObject> objects = new List<MyTransformedObject>();
    private readonly MyObjectMapper mapper;

    public MyBusinessLogicClass(MyObjectMapper mapper)
    {
        this.mapper = mapper;
    }

    public void AddToList(List<MyObject> list)
    {
        list.ForEach(i => i.MyInt += 10);
        var localList = list.Select(mapper.Map);
        objects.AddRange(localList);
    }
}

Step two: Let’s extract the business logic.

public class MyObject
{
    public int MyInt { get; set; }
}

public class MyTransformedObject
{
    public string MyInt { get; set; }
}

public class MyObjectMapper
{
    public MyTransformedObject Map(MyObject i)
    {
        return new MyTransformedObject {MyInt = i.MyInt.ToString()};
    } 
}

public class MyBusinessLogicClass
{
    public void DoLogic(MyObject iMyObject)
    {
        iMyObject.MyInt += 10;
    }
}

public class MyListClass
{
    private readonly List<MyTransformedObject> objects = new List<MyTransformedObject>();
    private readonly MyObjectMapper mapper;
    private readonly MyBusinessLogicClass businessLogic;

    public MyListClass(MyObjectMapper mapper, MyBusinessLogicClass businessLogic)
    {
        this.mapper = mapper;
        this.businessLogic = businessLogic;
    }

    public void AddToList(List<MyObject> list)
    {
        list.ForEach(businessLogic.DoLogic);
        var localList = list.Select(mapper.Map);
        objects.AddRange(localList);
    }
}

Step Three: Let’s finally let these guys be responsible for the lists

public class MyObject
{
    public int MyInt { get; set; }
}

public class MyTransformedObject
{
    public string MyInt { get; set; }
}

public class MyObjectMapper
{
    public MyTransformedObject Map(MyObject i)
    {
        return new MyTransformedObject {MyInt = i.MyInt.ToString()};
    }

    public IEnumerable<MyTransformedObject> Map(List<MyObject> list)
    {
        return list.Select(Map);
    }
}

public class MyBusinessLogicClass
{
    public void DoLogic(MyObject iMyObject)
    {
        iMyObject.MyInt += 10;
    }

    public void DoLogic(List<MyObject> list)
    {
        list.ForEach(DoLogic);
    }
}

public class MyListClass
{
    private readonly List<MyTransformedObject> objects = new List<MyTransformedObject>();
    private readonly MyObjectMapper mapper;
    private readonly MyBusinessLogicClass businessLogic;

    public MyListClass(MyObjectMapper mapper, MyBusinessLogicClass businessLogic)
    {
        this.mapper = mapper;
        this.businessLogic = businessLogic;
    }

    public void AddToList(List<MyObject> list)
    {
        businessLogic.DoLogic(list);
        var localList = mapper.Map(list);
        objects.AddRange(localList);
    }
}

Now you could take it even further and have AddToList only add to the list and have it take the correct parameters, but you don’t need to do that. Because now the only way this class should change is that you change how you add to the list, right? The business logic (of adding 10) won’t change this class. The mapping won’t change the class. It’s all been taken out.

S for Single Responsibility Principle

I do hope that this will help someone someday. Keep your classes/methods slim and simple. Extract logic into their own places. Think about what would the responsibility of your class be. Is it a data access class? Should I be mapping in this class? Is it a repository class? Should I have that extra layer of database logic so I can change my database in the future? Think about these things and keep your classes lean. One responsibility. One purpose. One reason to change.

Reposted on Medium.

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook

Like this:

Like Loading...

Related

Filed Under: Coding

Alex

Reader Interactions

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

About the author

Alex is an AVP of Engineering currently working at Bukalapak. He is a leader in full-stack technologies. Read More…

Pages

  • Speaking Experience
  • About

Social Profiles

  • LinkedIn
  • Medium
  • ADPList

Recent Posts

  • Interviewing as an Engineering Leader
  • Managing Low Performers
  • Getting Docker, React, .NET Core, Postgres, and Nginx Playing Nice
  • What Makes a Good Software Engineering Manager?
  • “Am I There Yet?” Said an Engineer

Archives

  • January 2025
  • August 2024
  • July 2024
  • October 2023
  • August 2023
  • October 2020
  • May 2020
  • February 2020
  • June 2019
  • March 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • January 2018

Categories

  • Coding
  • Essay
  • Leadership
  • Management
  • Roundtable
  • Strategy

Footer

Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy

Copyright © 2025

%d