The SOLID Principles
The SOLID principles are five software design principles that you can use to evaluate the quality of your software design. Each character in the name SOLID stands for a single design principle. The SOLID principles are:
- S - Single responsibility principle
- O - Open closed principle
- L - Liskov substitution principle
- I - Interface segregation principle
- D - Dependency inversion principle
I will explore each of this principles in more detail in the following sections.
Single Responsibility Principle
The single responsibility principle means that each unit in your code should only have a single responsibility. By unit I mean each class. However, you could probably extend that principle to methods too.
Having only a single responsibility for a class makes it easier to implement, as there is less functionality to keep in your head as you design and write the implementation. Typically, a class with a single responsibility will also be easier to read and understand, and often also easier to test. Additionally, having a class be focused on a single responsibility will often also make it easier to reuse.
One issue I have with the word "single" in the single responsibility principle is - that it can be hard to define what a "single responsibility" means. Often, a larger single responsibility can be subdivided into narrower individual responsibilities - sometimes even recursively. Just think about it: The fact that the responsibility of a class can be subdivided into multiple methods is already a sign that responsibility often can be narrowed multiple times - before being too small to make sense to subdivide further. That is why I use the term "narrow responsibility" in my own design philosohpy - rather than "single responsibility".
Open - Closed Principle
The open - closed principle means that a class should be open for extension - but closed for modification.
By "open for extension" is meant that you should be able to "extend" the functionality of the class without modifying it. This can typically be done in two ways: Via subclassing the class, or via plugging in a dependency the class can use. A pluggable dependency can be replaced later.
Bertrand Meyer is credited for having come up with the open closed principle originally.
Liskov's Substitution Principle
Liskov's substitution principle means, that if you have a superclass A and a subclass B, then you should be able to use B everywhere an instance of A is required. In other words, if B is a subclass of A, then B should be substitutable for A - meaning an instance of B should be usable instead of an instance of A. The code using A should not have to care if it gets an instance of A or a subclass of A.
Liskov's substitution principle is named after Barbara Liskov who first expressed it.
The interface segregation principle means that a class should not depend on interfaces it does not need.
Interface segregation sometimes means that a big interface should be split into multiple smaller interfaces, when it makes sense. Thus, a class that needs only part of the methods of the big interface can now depend on the smaller interface that contains that part of the methods.
The dependency inversion principle means, that if a class A depends on another class C, then an interface (or abstract class) B should be inserted between them. Thus, A now depends on the interface B - which the class C then implements.
The reason it is called the dependency "inversion" principle may not be entirely clear. The reason is, that before A depended on C, and C did not depend on anything - but after, both A and C depends on B - which in a diagram looks like the dependency has been inverted. I personally find the name a bit odd, though.