In the process of software development, we always deal with the changes in requirements of features at the beginning or ongoing development process, even getting new feature add-ons after deployment. Therefore it is most important to write code that is more readable, easy to extend, and makes other developers’ lives easy to work on. In object-oriented programming (OOP), SOLID principles teach us how to design our code and write code in well-structured architecture as it has a set of rules which guide how to achieve that.
SOLID principles have five sets of rules proposed to write maintainable and extensible systems. Understanding these concepts will make you a better developer and enable you to avoid code smells.
Well, Let’s see what these five rules are,
- Single responsibility principle
- 2. Open/Close principle
3. Liskov substitution principle
4. Interface segregation principle
5. Dependency inversion principle
Ok then, Let’s dive deeper into those principles.
“A class should have one and only one reason to change, meaning that a class should have only one job”. It means that if our class assumes more than one responsibility we will have a high coupling. The cause is that our code will be fragile at any changes.
Suppose we have a User class like the following:
In this case, the method store is out of the scope and this responsibility should belong to a class that manages the database. The solution here is to create two classes each with proper responsibilities.
According to this principle, a software entity must be easily extensible with new features without having to modify its existing code in use.
Suppose we have to calculate the total area of some objects and to do that we need an AreaCalculator class that does only a sum of each shape area. The issue here is that each shape has a different method to calculate its own area.
If we add another shape like a Circle we have to change the AreaCalculator in order to calculate the new shape area and this is not sustainable. The solution here is to create a simple Shape interface that has the area method and will be implemented by all other shapes. In this way, we will use only one method to calculate the sum and if we need to add a new shape it will just implement the Shape interface.
Liskov Substitution Principle
This principle says that objects must be replaceable by instances of their subtypes without altering the correct functioning of our system.
Let’s Imagine managing two types of the coffee machines. According to the user plan, we will use a basic or a premium coffee machine, the only difference is that the premium machine makes a good vanilla coffee plus than the basic machine. The main program behavior must be the same for both machines.
Interface Segregation Principle
This principle defines that a class should never implement an interface that does not go to use. In that case, means that in our implementations we will have methods that don’t need. The solution is to develop specific interfaces instead of general-purpose interfaces.
Dependency Inversion Principle
Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module, but should depend on abstractions. This principle means that a particular class should not depend directly on another class but on an abstraction of this class. This principle allows for decoupling and more code reusability.
These principles represent the state of the art of code quality and following them permits you to write software that will be easily extended, reusable, and refactored.
I hope this article helps you to better understand what code quality is and maybe to improve your coding ability! Happy coding! 😄😄