Many companies ask in their development positions that professionals have knowledge of SOLID. However, many developers believe that it is just a set of practices during development, not really knowing the theory behind it.
The S.O.L.I.D. principles, an acronym with the initials of the principles discussed below, aims to organize the functions and data structures in order to facilitate the development and evolution of software. The goal of these principles is to create code that tolerates change, is easy to understand, and is the foundation of components that can be used across multiple systems.
S - Single Responsiblity Principle (SRP)
O - Open-Closed Principle (OCP)
L - Liskov Substitution Principle (LSP)
I - Interface Segregation Principle (ISP)
D - Dependency Inversion Principle (DIP)
Each of these principles above will be detailed below.
This principle shows that a class must be specialized in a single subject and have only one responsibility. In other words, the class must have a single action to execute.
Robert MARTIN (2017) reformulates the commonly used description, that a module must have only one reason to change, and states that the SRP must be described as a module that must be responsible for only one actor. This actor is the representation of a user or stakeholder who is the “reason for change” of the initial definition. The term module can be defined as the source file or a cohesive set of functions and data structure.
The violation of this principle can cause a class to assume responsibilities that are not its own, increase the level of coupling, generate difficulties in implementing automated tests, and make code reuse difficult.
This principle was created by Bertrand MEYER (1997) and states that software should be open for extension, but closed for modification. That is, when new features need to be added to the system, it must be extended and not change the original source code.
According to MARTIN (2017), OCP is one of the driving forces in systems architecture, this being the most important principle of object orientation. In order to achieve the objective of making the system easy without this change causing a big impact, it is necessary to divide the system into components. These components are organized into a dependency hierarchy in order to protect high-level components from changes made to lower-level components.
Liskov's Substitution Principle was defined by Barbara Liskov and talks about using the substitution property as a basis. This property is described by the proof:
if for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T (MEYER, 1997).
In other words, the LSP says that if S is a subtype of T, then objects of type T in a program can be replaced by objects of type S without needing to change the properties of that system.
LSP has become a broader object-oriented design principle that can be applied to interfaces and implementations. This principle tells us that implementations must comply with some kind of contract. LSP enforcement is important, as users need well-defined interfaces and this ability to replace the implementation of the interfaces
This principle must be applied to architecture, as a violation of replaceability can contaminate the system architecture with a large amount of extra mechanisms.
Some examples of what can happen when violating this principle are:
- throw an unexpected exception;
- override or implement a method that does nothing;
- return values of types other than the base class.
This principle shows that a class should not be forced to implement interfaces and methods that it will not use, that is, it is better to create more specific interfaces than to have a big generic interface. Classes shouldn't depend on things they don't need.
This principle is used in the architecture to avoid module dependencies with many unnecessary elements. This is valid at both higher and lower architectural levels, as for example source code dependencies can unnecessarily force recompilation and redeployment.
About the Dependency Inversion Principle, MARTIN (2017) states that the most flexible systems are those in which source code dependencies refer only to abstractions and not to concrete items.
In general, it says that no class or function should be concerned with how a certain thing is done. Some classes, such as the String class, are concrete, so it wouldn't be interesting to force them to be abstract. However, these classes are very stable, so changes to them are very rare and controlled, so you don't need to worry about these changes. Concrete classes are tolerable because it is known that they will not change.
Applying to Clean Architecture, high-level modules should not depend on low-level modules, both must depend on abstraction. Abstractions should not depend on details, but details that should depend on abstractions.
SOLID is not just another line in the requirements of companies when looking for professionals, it is an essential set of good practices.
When these principles are applied to systems, they tend to be better structured, cohesive and scale more harmoniously - being also fundamental to Clean Architecture.
Every good professional should seek to delve deeper into the SOLID principles, apply them in their daily lives and disseminate them to their teams. Good practices must be disseminated and applied.
- MARTIN, Robert C. Clean Architecture: A Craftsman’s Guide to Software Structure and Design. 1st. ed. USA: Prentice Hall Press, 2017. ISBN 0134494164.
- MEYER, Bertrand. Object-Oriented Software Construction. 2. ed. Upper Saddle River, NJ: Prentice Hall, 1997. ISBN 978-0-13-629155-8.