SOLID

The Importance of SOLID Design Principles

S ⇒ Single Responsibility

Robert Martin summarizes this principle well by mandating that,

“a class should have one, and only one, reason to change.”

Following this principle means that each class only does one thing and every class or module only has responsibility for one part of the software’s functionality. More simply, each class should solve only one problem.

O ⇒ Open-Closed

Your class complies with this principle if it is:

  1. Open for extension, meaning that the class’s behavior can be extended; and
  2. Closed for modification, meaning that the source code is set and cannot be changed.

The way to comply with these principles and to make sure that your class is easily extendable without having to modify the code is through the use of abstractions. Using inheritance or interfaces that allow polymorphic substitutions is a common way to comply with this principle.

L ⇒ Liskov Substitution

Broadly, this principle simply requires that every derived class should be substitutable for its parent class.

…in a lot of ways it’s simply an extension of open-closed principle, as it’s a way of ensuring that derived classes extend the base class without changing behavior.

I ⇒ Interface Segregation

The general idea of interface segregation principle is that it’s better to have a lot of smaller interfaces than a few bigger ones. Martin explains this principle by advising,

“Make fine grained interfaces that are client-specific. Clients should not be forced to implement interfaces they do not use.”

D ⇒ Dependency Inversion

“high level modules should not depend upon low level modules. Both should depend on abstractions.” Further, “abstractions should not depend on details. Details should depend upon abstractions.”

Some guy on the internet (Bjarne is not the some guy, some guy is quoting Bjarne):

Bjarne Stroustrup: My rule of thumb is that you should have a real class with an interface and a hidden representation if and only if you can consider an invariant for the class.

And that is the hard, mathematical, overarching principle. LSP, when expressed in terms of the class invariants is obvious… get it wrong, you obviously have a bug.

SRP should be thought of in terms of “Can you decompose the class (and it’s invariant) into subclasses (and the invariant into subexpressions)?”

OCP again… think about it in terms of what is happening to the invariant?

In any real world code there are invariant all over the place, if you don’t know what they are… you are writing bugs all over the place. Pretty much by definition in fact.

Think of a class invariant as defining the “valid region”, the set of all possible states an object can be in, for which every public method works correctly.

ie. Step out of the valid region… you guarantee that you have a bug (by definition)… ie. Some public method, for some valid parameters, will fail.

It’s as simple and as hard as that.

Stop thinking of SRP, LSP, OCP, Law of Demeter as wishy washy “design guidelines” and start thinking in terms of building bug free programs out of bug free classes.

As stated (except for LSP) they are wishy washy. But underneath is the hard steel of “class invariant doesn’t hold” === “you have hit a bug”.


  • Single Responsibility - do one thing

  • Open/Closed - open for extension, closed for modification (code to interfaces, not concrete classes)

    Open-Closed principle:

    Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

    The original interpretation of open-closed was to achieve the “extension” part of the above definition by leveraging inheritance. That is, when new behaviour needs to be introduced to a class, we create a new subclass inheriting from it, and override the method we need to add to. Inheritance introduces tight-coupling between the child and parent class though, with the child having a concrete dependency on the implementation details of the parent.

    Instead we can apply what has been called Polymorphic Open-Closed, which uses interfaces and composition to allow for different implementations rather than inheritance.

    SOLID Design Principles Explained: The Open/Closed Principle with Code Examples

    Open-closed principle - Wikipedia

  • Liskov Subsitution - objects of a superclass should be replaceable with objects of its subclasses without breaking the application

  • Interface Segregation - clients should not be forced to depend upon interfaces that they do not use

  • Dependency Inversion

    1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
    2. Abstractions should not depend on details. Details should depend on abstractions.