In my earlier days as a nerdy developer, I often found myself trying to do my work in the smartest way. That is, I didn’t concentrate too much on predefined guidelines and absolute quality! However, this quirky ideology of mine changed a couple of years back when I started working with Magento 2.
Given the plethora of technical guidelines and resources available from Magento, the new eCommerce platform was initially quite challenging to learn. Magento is more focused on maintaining high-quality work among its developers as well as providing various means of guidance to the community. Once I started following Magento’s guidelines, I realized that it made things more accessible than ever before. I highly recommend utilizing the following principles in order to achieve the best quality coding in Magento.
This is a beginner’s guide to the SOLID principles, which I came across during my quest to follow the guidelines for good programming. Budding programmers and developers can use the SOLID method described in this article to further improve their Magento coding skills.
What are SOLID Principles?
In object-oriented computer programming, the term SOLID is a mnemonic acronym for five design principles that are intended to make software designs more understandable, flexible, and maintainable.
The SOLID Principles are as follows:
- Single Responsibility Principle (SRP)
- Open/Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
Why should you practice SOLID Principles?
After learning a thing or two about SOLID and applying the principles to my daily coding work, I found the results to be immensely gratifying. Nowadays, I regularly use these principles to guide my work. Following the SOLID principles allows you to:
- Maintain high coding standards.
- Make code that is scalable and repairable – regardless of the size of change requests.
- Create universally understandable code.
Let’s take an in-depth look at what these principles mean.
Single Responsibility Principle (SRP)
a class should have only a single responsibility
This one is pretty straightforward. A class should only have a single responsibility, and it should not do too many things. A class with multiple responsibilities makes it more complicated to change since it might affect more than one function at once. Meanwhile, a class with just one responsibility can be easily modified. This makes the class much more maintainable.
Examples in Magento 2
MagentoFrameworkEventManager – Responsible for dispatching the events.
MagentoFrameworkDataFormFormKeyValidator – Responsible for validating the form key.
So, the next time you write a class, make it responsible for only one action in order to make your code robust and manageable.
Open/Closed Principle (OCP)
software entities … should be open for extension, but closed for modification
Assume your client approaches you to write the code for calculating the sum of numbers. You write a class (Add) with a method (Calculate) to calculate the sum and give it to the client, who is delighted with your work. Some time later, the same client approaches you to add the multiplication logic.
Now you edit the same class (Changing Add to Operation) and two methods (Add and Multiply) with the respective logic. However, this is not the right approach because your client may then ask you to add subtraction or division, causing you to modify the source code for each request.
As the principle states, for any modifications, a class should be allowed to extend its behavior but not to change its source code. Instead, it’s better write an interface (Operation Interface) with a calculate method, which the classes (Add or Multiply) can implement. When the client approaches you for another operation like division, you can create a new class by implementing the interface.
Examples in Magento 2
To add any router, implement the MagentoFrameworkAppRouterInterface and add the same to the RouterList(in di.xml). Here, no modification has been made to the existing code even though the router is added.
Liskov Substitution Principle (LSP)
Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program
As per the object-oriented programming, when Class B extends Class A, Class B can be a substitute for Class A. LSP extends the same fundamental principle, with a significant change – Class B SHOULD be a substitute of Class A.
In the case of extending any Magento-native classes, you should follow the same structure. If you intend to remove any method or modify its parameters, then it will result in the violation of this principle. The violation may cause the application to break or produce unexpected results.
Examples in Magento 2
Assume a preference written for overriding the MagentoQuoteModelQuote::addProduct($product, $request, $processMode) method. Creating the class that extends the above, but modifies the addProduct() method by removing the $processMode parameter. This is a complete violation of the principle. So classes which already calls the addProduct() with three parameters will throw an error and cause the application to break.
Interface Segregation Principle (ISP)
Many client-specific interfaces are better than one general-purpose interface
This is another straightforward rule that focuses on splitting the big interfaces into smaller ones. The violation of this principle may force the implementation class to depend on the methods that they don’t use.
Assume there is a standard interface for compiling and rendering. When creating a separate implementation class for the compiler and render, based on SRP, the classes should be intended to use the other methods (in other words, compilers are forced to use rendering methods).
Examples in Magento 2
MagentoFrameworkViewElementBlockInterface – implemented in all the blocks for rendering HTML content.
MagentoFrameworkDataObjectIdentityInterface – may implement in blocks or models for caching purposes.
Assume that the Magento Core Team has combined both and can have only the BlockInterface. However, doing so forces all blocks to have cache methods that they might not use, which violates the principle.
Dependency Inversion Principle (DIP)
one should “depend upon abstractions, [not] concretions”
DIP focuses on decoupling modules, stating that:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
When Class A (high-level) calls Class B (low-level), Class A depends on Class B. But as per this principle, Class A should not depend on Class B; it should depend on abstractions(interfaces).
- Abstractions should not depend on details. Details should depend on abstractions.
Interfaces should not depend upon the implementation class, but the implementation should depend upon the respective interface.
Since the code is decoupled to change the entire implementation class, it’s not necessary to make changes in the high-level class. In order to follow the principle, the high-level module also needs to be altered with the low-level class.
Examples in Magento 2
Refer any native classes where they mostly inject the interfaces into the constructor instead of the implementation class to create the respective objects. Even when using the factory, it is recommended to create the factory for the interface.
Conclusion
These are the five simple and most commonly used design principles in the process of Object Decomposition. Magento strongly encourages its developer community to apply these principles wherever needed. So, the next time you code a new feature or modify an existing one, keep the SOLID principles in mind and apply them to achieve better quality and maintainability in your code.
Leave a comment to add your own input or examples of the SOLID principles, or to write about any other design pattern. Together we can make the community even better.
Contents