Solid is an acronym invented by Robert C. Martin to establish the five basic principles of object-oriented programming and design. This acronym has a lot to do with design patterns, especially with the high cohesion and the low coupling.
The objective of having a good programming design is to cover the maintenance phase in a more readable and simple way as well as to be able to create new functionalities without having to modify to a great extent old code. Maintenance costs can cover 80% of a software project, so a good design must be valued.
S-Simple responsibility (Single responsibility)
This principle tries to assign each class to a simple and concrete purpose. On many occasions we are tempted to put a reusable method that has nothing to do with the class simply because it uses it and it is more convenient for us. At that moment we thought “Since we are here, why am I going to create a class to do this. I directly put it here”.
The problem arises when we have the need to use that same method from another class. If it is not refactored at that time and a dedicated class is created for the purpose of the methodIn the long run, we will find that classes perform tasks that should not be their responsibility.
With the above mentality we will find, for example, a number formatting algorithm in a class destined to read from the database because it was the first place where it began to be used. This leads to having methods that are difficult to detect and find so that the code must be memorized in the head.
O-Open / Closed (Open / Closed)
Principle attributed to Bertrand Meyer which talks about creating extensible classes without having to enter the source code to modify it. That is, the design must be open to be able to extend but closed to be able to modify. Although said seems easy, the complicated thing is to predict where it should be extended and that we do not have to modify it. To achieve this principle, it is necessary to be very clear about how the application is going to work, where it can be extended and how the classes are going to interact.
The most common use of extension is by inheritance and reimplementation of methods. There is another alternative which is to use methods that accept a interface so that we can execute any class that implements that interface. In all cases, the behavior of the class changes without us having to touch internal code.
As I have already mentioned, there comes a time when the needs can become so unpredictable that we come across that the methods defined in the interface or in the extensible methods are not enough to cover the needs. In this case there will be no choice but to break this principle and refactor.
L-Substitution Liskov (Liskov substitution)
This principle was created by Barbara Liskov and talks about the importance of creating all derived classes so that they can also be treated as the base class itself. When we create derived classes we must make sure not to reimplement methods that make the base class’s methods not work if they are treated as an object of that base class.
I-Segregation of the interface (Interface segregation)
This principle was formulated by Robert C. Martin and it deals with something similar to the first principle. When interfaces are defined they must be specific to a specific purpose. Therefore, if we have to define a series of abstract methods that a class must use through interfaces, it is preferable to have many interfaces that define few methods than to have an interface with many methods.
The aim of this principle is primarily to be able reuse the interfaces in other classes. If we have an interface that compare and clone in the same interface, in a more complicated way it can be used in a class that only has to compare or in another that only has to clone.
It was also defined by Robert C. Martin. The objective of this principle is to decouple the classes. In any design there should always be a coupling but it should be avoided as far as possible. An uncoupled system does nothing but a highly coupled system is very difficult to maintain.
The goal of this principle is the use of abstractions to get a class to interact with other classes without directly knowing them. That is, the higher-level classes must not know the lower-level classes. In other words, you don’t need to know the details. There are different patterns such as dependency injection or service locator that allow us to reverse control.