Why is the single responsibility principle (SRP) so hard to define? From my experience, SRP stumbles people much more than any other SOLID principle. I thought back to my own struggles with the five principles, and thought it would be better to explain SOLID in a different way; or rather, a different order.

What is an interface?

a point where two systems, subjects, organizations, etc. meet and interact. When A wants to interact with B, A will communicate through interface C, for which A and B mutually understands.

In programming languages such as C# and Java, an interface is the same idea. You have an object A, which wants to interact with B, object A will communicate through an interface C, for which A will consume as a dependency, and B will implement.

    namespace World
    {
        public interface C
        {
            void DoStuff();
        }

        public class A
        {
            public C C { get;set; }

            public A(C c)
            {
                this.C = c;
            }

            public void InteractWithC()
            {
                this.C.DoStuff();
            }
        }

        public class B : C
        {
            public void DoStuff()
            {
                // Do some stuff the B way.
            }
        }
    }

Why are interfaces useful?

Interfaces are useful for polymorphism. object A only understands or knows about interface C, which means it does not know object B exists. This means that polymorphism can occur-I.e., object B can be substituted for many different implementations, without affecting object A.

Why am I talking about interfaces?

I am talking about interfaces because it leads onto the most important principle I find of all the SOLID principles; the interface segregation principle (ISP).

The Interface Segregation Principle (ISP)

ISP states that no client should be forced to depend on methods it does not use. Within the world of C#, this means that an interface with many methods on it, tends to break this principle. But how many is too many? Ultimately it doesn’t really come down to one number, but a goal. The ultimate interface will have no more methods on it than what is absolutely necessary to perform it’s given purpose.

You could argue then, that an interface that follows this principle perfectly, would be an interface with one method. You cannot argue against the fact that if there is only one method on an interface, then no client is forced to depend on more methods than it uses. Otherwise, it would not select it as a dependency at all.

The goal of ISP is to make it very simple and easy to use dependencies. If you only need to know about one method on an interface, doesn’t that make it the easiest it can be to use?

Header vs Role based interfaces

A clear sign that you are breaking ISP, is the idea of header interfaces. A header interface is where you have a class with 20 methods, and every method on the interface is as a carbon copy. This is bad, as it isn’t very flexible. If some other class wants to implement the interface, and they had to implement 20 methods, they have their work cut out. As mentioned, it’s also much harder to understand and reason about an interface with 20 methods.

    namespace OrderManagement
    {
        public interface IOrderManager
        {
            void CalculatePrice();
            void Save(Order order);

            void CreateNewOrderLine(Order order);

            ...
        }

        public class OrderManager : IOrderManager
        {
            // implements all 20 methods
        }
    }

So instead of a header interface, what we must do is split that interface up into smaller interfaces. But how? Employ the notion of a role based interface. As you can see from the previous example, the interface has a name with a suffix of Manager. This is vague, and doesn’t really tell us precisely the meaning of the interface. This is where you start preferring adjectives in the interface name, where some interface governs a certain activity, not a blanket piece of functionality.

    namespace OrderManagement
    {
        public interface IOrderLineCreator
        {
            void Create(Order order);
        }

        public interface IOrderPriceCalculator
        {
            Price Calculate(Order order);
        }

        public interface IOrderPersister
        {
            void Save(Order oder);
        }
    }

Pros and cons

The problem with applying ISP, is that it can balloon the number of interfaces in your codebase. This can lead to more verbosity, and a quick glance at a codebase is harder. The sheer number of files within a project can be daunting to a less experienced programmer, and this can make it seem at first, to be a huge overcomplication. So, like the majority of problems in our industry, it depends.

What ISP does give you, is exactly what SOLID as a whole is trying to achieve. Classes that are reusable, extensible, not at all rigid, and above all, composable. A classic analogy for the composability you achieve from ISP, is Lego. 1000s of small pieces, that can fit together in any shape or form, to create a complex system of operations.

Summary

What I have described here is ISP. I have not gone into details around SOLID as a whole. There is a great deal of practical information out there for SOLID principles, and so I will not delve into them here. It is my belief that when you fully understand how to utilise ISP, then every other principle falls into place.

SRP is easier to achieve when ISP looms over your interfaces by splitting them out. The Liskov Substitution Principle is easier to achieve, as there is less tendency to break the principle when there are less methods to implement. You will also realise that a system becomes extremely extensible, without any change, as an interface with one method, will very rarely change, and that lends itself to the open/closed principle. Of course, learning ISP will naturally make you learn dependency injection as well.

ISP was the principle that transformed my programming for the better.

Learn SOLID right, start with I.

The best place to learn SOLID principles, is from Mark Seemann’s Pluralsight course Encapsulation and SOLID. He gives great examples in his course, and will give you a firm foundation for SOLID principles.