As a software developer for a decade, I've come to realize that myself and a significant percentage of programmers are not prioritizing good practices, or at least, these concerns are not among our top priorities.
However, I decide revert this and learn to become a better professional.
I’m writing these articles as my personal notes and hope motivate you to be a better programmer as well.
So let’s start for the beginning: SOLID principles!
The SOLID principles are a set of five design principles intended to make software designs more understandable, flexible, and maintainable. They are:
1 - Single Responsibility Principle (SRP): A class should have only one reason to change, meaning it should have only one responsibility or job.
We all did the mistake to have a huge class that do more than one thing and different things with different contexts.
public class UserManagementSystem
{
public void AddUser(User user)
{
// Add user to the database
}
public void DeleteUser(User user)
{
// Delete user from the database
}
public void SendEmailToUser(User user, string message)
{
// Send email to the user
}
public void GenerateReportForUser(User user)
{
// Generate report for the user
}
}
In this example, the UserManagementSystem class is responsible for multiple tasks: adding/deleting users, sending emails, and generating reports. This violates the SRP because the class has multiple reasons to change: if the database structure changes, if the email service changes, or if the report generation logic changes. It would be better to separate these responsibilities into distinct classes.
2 - Open/Closed Principle (OCP): Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means that you should be able to add new functionality without altering existing code.
public class Shape
{
public string Type { get; set; }
public double Area()
{
if (Type == "Rectangle")
{
Rectangle rectangle = new Rectangle();
return rectangle.Length * rectangle.Width;
}
else if (Type == "Circle")
{
Circle circle = new Circle();
return Math.PI * Math.Pow(circle.Radius, 2);
}
// More shapes and calculations can be added here, but violates OCP
else
{
throw new InvalidOperationException("Unsupported shape type");
}
}
}
public class Rectangle
{
public double Length { get; set; }
public double Width { get; set; }
}
public class Circle
{
public double Radius { get; set; }
}
In this example, the Shape class contains a method to calculate the area based on different shapes such as rectangles and circles. However, if a new shape is introduced, such as a triangle, the Area() method in the Shape class would need to be modified to accommodate the new shape. This violates the OCP because the class is not closed for modification; instead, it requires modification whenever a new shape is added.
3 - Liskov Substitution Principle (LSP): Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. In other words, derived classes should be substitutable for their base classes without altering the desirable properties of the program.
4 - Interface Segregation Principle (ISP): A client should not be forced to depend on interfaces it does not use. Instead of one large interface, it is better to have smaller, specific interfaces.
5 - Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions. This principle promotes loose coupling between software modules.
Top comments (1)
Amazing!