SOLID principles: The Definitive Guide (Part I)
SOLID principles tell you how to arrange your functions into classes and how those classes should be interrelated.
SOLID is an acronym that stands for five principles of software design: Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion.
Robert C. Martin introduced it. Clean Architecture.
When SOLID principles are applied correctly, your software infrastructure will tolerate changes, be easier to understand, and focus on reusable components by reducing complexity, coupling, and dependency.
Let’s start with the first principle.
SOLID principles: Single Responsibility Principle (SRP)
… “a class should only have one reason to change“
This principle states that a class should only have one responsibility.
For instance, imagine an online store that issues its cards for its customers, and from the beginning, the Payment and Card teams are in mutual agreement to apply for interest and to lock cards from customers who are in late payments for 14 days or more.
In the following code, we have the first design of the Payment Class, which supports both requirements.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Payment {
public static final int MAX_DAYS = 14;
public void batch(List<Customer> customers) {
for (Customer customer : customers) {
int nDays = latePaymentDays(customer);
if (nDays >= MAX_DAYS) {
applyLatePaymentInterest(customer);
lockCard(customer);
}
}
}
}
The Problem: A Class has more than one responsibility
But suddenly, the Cards team wants to change the validation to 10 days. However, the Payments team manages other policies related to when interests by late payment are applied. As a result, the Payments team disagrees with the Cards team. Moreover, both teams are stuck on how to proceed.
This scenario is a clear example of how this Class design violates the Single Responsibility Principle. The Payment class has more than one reason to change and breaks the Payments team’s business logic if they accept the Cards team’s requirement.
The following figure shows the Class with different responsibilities:
The solution: Create a Class with only one responsibility
What do we need to do?. In this scenario, we can apply the Single Responsibility Principle
Firstly, we move the lockCard() responsibility to a new Card Class. This technique is most known as refactoring
1
2
3
4
5
6
7
8
9
10
11
12
public class Card {
public static final int MAX_DAYS = 10;
public void batch(List customers) {
for (Customer customer : customers) {
int nDays = Payment.latePaymentDays(customer);
if (nDays >= MAX_DAYS) {
lockCard(customer);
}
}
}
}
After that change and following Clean code principles, we can see how it looks the new Payment Class (refactored as well):
1
2
3
4
5
6
7
8
9
10
11
12
public class Payment {
public static final int MAX_DAYS = 14;
public void batch(List<Customer> customers) {
for (Customer customer : customers) {
int nDays = latePaymentDays(customer);
if (nDays >= MAX_DAYS) {
applyLatePaymentInterest(customer);
}
}
}
}
Finally, new changes to the MAX_DAYS variable will only depend on the requirements of every team separately. The following figure shows the Classes for different actors, without conflicts.
Therefore, the Payment Class is only responsible for supporting to the Payments team, and the Card Class is solely responsible for supporting the Cards team.
Also, when new features arrive, then we need to distinct in which Class to include it. Moreover, this is related to the Cohesion concept, which help us to group similar functions inside a Class, and that have the same purpose served by that Class.
In conclusion, once you identify classes that have too many responsibilities, use this refactoring technique to create smaller classes with single responsibilities and focused only on one business actor.
Use this principle as a tool when translating business software requirements into technical specifications. Programmers must understand these design decisions before programming.
Now that you’ve learned the Single Responsibility principle, it’s time to learn the Open-closed principle to design flexible systems and avoid future software maintenance costs.
Any software design is generally a matter of opinion. There is no definitive Guide. – codersite.dev