SOLID Principles is a coding standard that all developers can understand to properly build applications and to prevent poor development. It was proposed by Robert C Martin and is widely used in object-oriented programming. It allows the code to be more extendable, rational, and simpler to interpret when used correctly.
When the creator develops a program based on poorly designed programming, the software may become rigid and change with any modification. We must value SOLID Principles for these purposes.
It requires time to grasp, but writing code according to the standards improves code consistency and aids in understanding even the most well-designed applications.
Object Oriented Design is critical in software development since it enables the creation of modular, portable, maintainable, and reusable code. There are so many advantages of using OOD, but every developer needs to know the SOLID principle for successful object-oriented programming design.
SOLID is an acronym composed of the names of five design concepts aimed at improving the design, maintainability, and extensibility of software.
The SOLID coding standards will lead you to:
- Write maintainable code;
- Make it possible to add new features without disrupting current functionality
- Write code that is simple to interpret and understand.
SOLID concepts, in a nutshell, serve as UX principles for developers. A positive developer experience entails being able to navigate the code and appreciate what it does. Ultimately, this helps in less time spent debugging the code and more time designing the solution.
This principle is an expression of the following five principles:
- Single Responsibility Principle (SRP)
- Open/Closed Principle
- Liskov’s Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
Single Responsibility Principle (SRP)
The S in SOLID stands for the Single Responsibility Principle. Single responsibility implies that the class (or any person, for that matter, including a method within a class or a function in structured programming) should perform a single function. If your class is responsible for retrieving user data from the database, it should be unconcerned with data visualization. There are distinct duties that should be performed separately.
How do you ensure that the code complies with the Principle of Single Responsibility?
As compared to broad classes with common names, create small classes with very unique names. For instance, rather than classifying all functions into an Employee class, break them down into “EmployeeTimeLog”, “EmployeeTimeOff”, “EmployeeSalary”, and “EmployeeDetails”. Once you know where everything is located, it is much easier to find your code when you return one year later.
This theory says that “programme structures (classes, modules, functions, etc.) should be extendable but not modifiable,” which means that you should be able to expand the behaviour of a class without modifying it.
If developer A has to release an upgrade for a library or application, and developer B wishes to make a change or implement a function, developer B is permitted to expand the current class provided by developer A, but not to alter the class directly. This idea distinguishes original code from changed code, resulting in improved stability, maintainability, and the reduction of modifications in your code.
When you look at the names, the idea of Open/Closed would seem to be the most difficult. How is it possible for anything to be both accessible and closed at the same time? It does, though, have a relatively basic concept behind it, and if used properly, it will save you the most production time.
According to the Open/Closed Principle, a module should be open for addition but closed for alteration. You can easily introduce new functionality to a module by simply modifying the source code, but the extension is more difficult, so you would modify the design. The ultimate aim is to preserve all of the previously written code so that it over time becomes resilient to faults.
It’s like dealing with an open-source library when you use the Open/Closed Principle. when you are not modifying the source code of an open-source project Instead, you trust the inherent qualities and code to conform to them. When the library is repeatedly put to the test, it begins to act more or less the way it should. When developing software, you can often make a conscious effort to ensure that you avoid adding new functionality that will break any software that is already in place.
How do you ensure that the code adheres to the SOLID Design Principle of Open/Closed?
Let’s presume you choose to use different payment methods in an e-commerce module. Build a payment method class, including as many different choices as you want. This will work, but any time we introduce or modify a payment alternative, it would necessitate changing the class.
Instead, build a payable interface. There will be one class per payment choice. Now your core is completed (once you are finished, you can just leave it alone), but this will enable you to keep introducing new choices (features) (you can add new payment options by adding new classes).
Liskov’s Substitution Principle
Barbara Liskov adopted the concept in 1987, stating that “derived or child classes must be interchangeable with their base or parent classes.” This theory guarantees that every class that is a child of another class behaves normally when used in place of the parent class.
You may interpret this to mean that a farmer’s son could inherit farming skills from his father and be capable of replacing him if necessary. If the son wishes to become a farmer, he will succeed in replacing his father; but, if he wishes to become a cricketer, he cannot succeed in replacing his father, even though they all belong to the same family hierarchy.
A rectangle with four sides is a typical illustration of this theory. The height and width of a rectangle may be any value. A square is an equal-width and equal-height rectangle. Thus, we will apply the rectangle class’s properties to the square class. To do this, you must switch the child (square) and parent (rectangle) classes to conform to the idea of a square of four equivalent sides. But, since a derived class does not influence the action of the parent class, doing so breaches the Liskov Substitution Principle.
How do I ensure that my code compiles to the Liskov Substitution Principle?
If your programming language allows style hinting for interface methods’ return types, you may use it to prevent the problem of incompatible return types in different implementations. Nonetheless, it would not resolve all issues. Throwing an exception during the execution of a procedure that is not required is indeed a breach of the Liskov Substitution Principle in PHP. Thus, the only way to ensure that you adhere to this principle is by conscious programming. You should always have in mind what the system can do if you want to make the most use of a function.
Interface Segregation Principle
This is the first concept of SOLID that refers to interfaces rather than classes, and it is equivalent to the single responsibility principle. It states that clients should not be compelled to implement an interface that is irrelevant to them. Here, the primary target is to avoid large interfaces in favour of several small client-specific interfaces. You should choose several client interfaces to a single generic interface, and each interface should have a distinct feature.
Assume you visit a restaurant as a strict vegetarian. The waiter at that restaurant handed you a menu card that contained vegetarian and non-vegetarian options, as well as beverages and desserts. As a client, you can get a menu card that contains only vegetarian options, not anything that you do not consume. Here, the menu can be differentiated by consumer class. The universal or common menu card may be split into several cards rather than only one. Utilizing this theory results in a decrease in the number of adverse consequences and the frequency of required improvements.
According to the Interface Segregation Principle, you can never compel a client to depend on methods it does not use. Consider the case of the Single Responsibility Principle with this one.
Consider that you have a sizable Employee class that contains all of the methods necessary for managing personnel in your system. Then, you’ll have multiple RESTful controllers, one for each feature needed on your website (e.g. “EmployeeTimeLogController”, “EmployeeTimeOffController”, “EmployeeSalaryController”, “EmployeeDetailsController”, etc.). Now, both of these controllers depend on the Employee class to perform their assigned tasks. A change to the Employee class will trigger any of these controllers to fail since they are all dependent on it.
How do you ensure that the code adheres to the Principle of Interface Segregation?
Divide the Employee class into smaller groups that each have their interface. After that, adjust the controls such that they all depend on the interfaces they require. This way, you’ll provide a simple system under which the customer is just dependent on the processes it employs. Changing things in a certain class has little effect on the sections of the scheme that depend on it.
Dependency Inversion Principle
According to the dependency inversion principle, high-level modules do not rely on low-level modules and should instead rely on abstractions. Let’s look at a case to demonstrate this. Looking at your home, you can see that you’re using energy to power your desktop, computer, lamp, and other devices. To obtain power, they all use the same interface: the plug. The benefit of it is that you don’t have to be concerned with how energy is delivered. You trust that you will be able to use it when necessary.
Consider what would happen if you had to wire it up any time you needed to charge your phone instead of relying on the socket as an interface. When we depend on concrete applications of software, we do the same thing: we know so much about how things are done, making it possible to break the system.
How do you ensure that the code adheres to the Dependency Inversion Principle?
You may avoid relying on concrete classes by integrating the dependency injection approach with the idea of linking an interface to concrete implementation. This would encourage you to adjust the implementation of specific sections of the framework without destroying the system as a whole. Switching the database driver from SQL to NoSQL is a perfect example. If you depend on abstract interfaces to navigate the database, you can easily modify the individual implementations to ensure that the system functions correctly.
The SOLID design concepts are intended to serve as a framework for creating maintainable, extendable, and understandable applications. When used correctly, they can allow your team to spend less time debugging code and more time developing fun features.