SOLID principles are a set of five design principles ( mnemonics acronym known as S.O.L.I.D ) in the object-oriented paradigm. They were first introduced by Robert C Martin. These concepts are in practice since early 2000 and still applicable to the modern design process.
This article will get brief details of SOLID principles, their benefits, and a high-level glimpse of each SOLID principles.
1. SOLID principles benefits
When applied together, these principles become a guideline to develop robust software products that are easily maintainable, testable, scalable, and extensible.
Design principles help reduce errors, easy code refactoring, make the code more efficient, and help achieve iterative development methodology – for example, agile.
2. Design Principle or Design Pattern?
When we talk about design principles, most developers refer to the terms Design Pattern and Design Principles interchangeably. However, there is a difference between the two.
Design Principles are more on suggesting the right and the wrong way of designing a particular system. In short, they just denote what to do for a particular problem statement as a solution.
Design Patterns, on the other end, represent a reusable solution to commonly occurs problems. The design pattern shows how to solve a particular problem in a given design context by suggesting clear methodologies.
The difference between Design Principles and Design Patterns lies in one sentence – Desing Principle talks about What part while Design Patterns talk about How part.
3. SOLID Principles details
SOLID principles are most popular among the set of design principles in the object-oriented world. This article gives a brief explanation of each of these principles. I will be writing a separate article dedicated to explaining each principle with more in-depth details.
The SOLID principles cover the following five design principles. Each letter of this acronym represents the design principle name. This is how the S.O.L.I.D is formed jointly.
- S – Single Responsibility principle
- O – Open-closed principle
- L – Liskov substitution principle
- I – Interface Segregation principle
- D – Dependency Inversion principle
We will briefly see each of these rules to understand why they are so important to adopt for a good developer.
3.1 S – Single Responsibility Principle
The Single Responsibility principle or in short SRP talks on:
A class should have one and only one reason to change
This means a class should do a single responsibility or job. While designing the software product, often we write a Class that handles multiple things.
At first glance, you might think this is a good idea. However, this seems true until you reach a certain level of complexity. When the application is growing, you will really feel it difficult to maintain it if you don’t follow this principle.
Adding multiple functionalities in a single class will introduce coupling between the functionalities. In this scenario, changing one would affect and may break several other functionalities. This required additional effort to fully test the code before deploying to production and maintaining every change.
3.2 O – Open-closed Principle
The Open-closed principle talks more about the structural part of your application. It states:
Your program should be open for extension and close for modification
Here the program is referred to as an object or an entity. In a programming language like Java, a class is a basic building block of an application.
In the context of Java (or any other object-oriented programming language), this principle states that the class should be designed so that it’s easily extensible at the same time restricted to modify itself for introducing new features or functionality.
This principle gives assurance that no one can change already tried, tested, and fully functional code. To adopt this principle, you should abstractly write code to accommodate the further change in extending the existing code.
3.3 L – Liskov Substitution Principle
The Liskov Substitution Principle (known as LSP) focuses on the relationship between superclass and subclass. In conjunction with the open-close principle, the Liskov substitution principle talks about:
The object of superclass should be substituted by the object of its subclass
This should happen without breaking an application. This means the object of the subclass should behave exactly in the same way as its superclass object. To achieve this, you need to make sure about the following things
- The overridden method should take a similar parameter as defined in the superclass.
- Make sure the subclass imposes a less restrictive validation rule than the superclass.
- The return type of the method in a subclass must be a subtype of the method’s return value in the superclass.
This rule can be verified by calling all the subclass instances to ensure the application works without any glitch and performance issues.
3.4 I – Interface Segregation Principle
In the same context of the Single Responsible Principle, this principle talks about:
A client should not implement an interface if it doesn’t use it
In other words, the design should not force a client to implement the interface; it doesn’t really need it. This mostly occurs when the interface contains more than one un-related method.
To achieve this principle’s solution, you should break a single interface into multiple interfaces in either a hierarchical or independent manner. In short, many small and client-specific set of interfaces are more preferable to big or fat interfaces with many methods.
3.5 D – Dependency Inversion Principle
The Dependency Inversion Principle gives a suggestion of using abstraction in place of concrete implementation. It talks about
- High-level modules should not depend on low-level modules, and both should depend on abstraction.
- Details or concrete implementation should depend on abstraction rather than an abstraction that depends on details.
Seeing this principle’s name, one can think that this principle asks to change the direction of dependency, but in reality, it’s not. Instead, it suggests managing the dependency between high and low-level modules abstractly.
The SOLID principles that we talk about here are inter-related with each other. For example, if you apply the Open-closed principle to make your class open for extension and close for modification, you need some sort of abstraction in between. Again that abstraction should follow the Liskov Substitution Principle (LSP).
Then ultimately, you need to design the high and low-level modules so that they abstractly interact with each other. That is what Dependency Inversion Principle is. In short, the Dependency Inversion Principle asks to separate the modules from each other and, at the same time, do bind them together in an abstract way.
Design principles greatly help designers enhance usability, influence and improve the perception, increase the confidence level, and boost adoption capabilities. All these qualities will ultimately help build a robust application that is easily maintainable, testable, reusable, and extendable.
SOLID Principles are among the most popular design principles that must be considered while designing a system. Adopting these principles with continuous usage will surely help to build sustainable software products.
As an exercise, you can find some real-world use cases to apply these principles to understand the concepts in more detail.