DEV Community

Mircea Sirghi
Mircea Sirghi

Posted on • Updated on

SOLID principles mismatches

I observed that SOLID principles bring a lot of confusion when described by various authors. Sources are different, starting from the author doesn't truly grasp the concept, follows other authors but slightly changes the objects and words as to prove authenticity, sometimes when one principle is explained with information related to another principle.

Here I would like to bring together my observations on SOLID and what confusions arise if followed.

Let's start with Single Responsibility. As it sounds, any object should be able to do only stuff that is related to its meaning.

If we take a Book object for example, by following Single Responsibility we should not find the printing method in it as it is the property of another object that prints stuff. So a Book should be responsible to just hold the data but not responsible to print itself. After we encapsulated book data, we still want to be able to print it. And here is the problem, we may have other printable objects. So we create generic print method as part of Printer object that besides books can print any printable object. A nuance we observe in print method is that there are lots of "if" statements to handle the print for each type. Remember Cyclomatic Complexity issue in Sonar ?

To avoid Cyclomatic Complexity problem let's use Open Closed principle to create a Printable interface, all printable objects should implement it. Problem solved. But wait, we have just broke the Single Responsibility principle because basically we implemented Printable interface to implement its print method. This is against Single Responsibility principle.

To solve braking Single Responsibility through Open Closed we can create a method in Printer object per each printable type. Problem solved. Buy wait, we have to duplicate lot of printable methods, and the most important Open Closed states - open for extensions closed for modifications, well we applied modifications here. Now we have the chance to go deeper into the mud. We can solve it through Strategy Pattern. Create a strategy per each printable type. Problem solved, now we just took a print method from each printable objects, to create more objects that will print our objects. Sounds like Single Responsibility is not that useful in this scenario.

Let's try with Liskov Substitution. Printable base class here(interface can be used as well). We create a BasePrintable, Book and all other printables extend BasePrintable. We brake Single Responsibility from the start, Liskov does not go well with this principle, as we have to implement the print method from BasePrintable class. We move back to generic print method in the Printer object. Problem solved. But wait, within printing context we follow Liskov principle, but Book has pages, hard cover, title, table of contents, however, take for example Postcard object that doesn't have this stuff. By following Liskov principle, we broke the Liskov principle.

Interface Segregation must solve the issue. Indeed. Lets consider BasePrintable as an interface, we segregate it into BookBasePrintable, PostcardBasePrintable, etc.. Now we are even, we follow Open-Closed, Liskov. We have just duplicated BasePrintable code into multiple abstractions. Considering we have our generic print method that takes BasePrintable as a parameter in our Printer object. Single Responsibility is still broken, to solve it we can use again Strategy Pattern. However there is no simplification. It becomes even more complex. Instead of having a BasePrintable implemented by each printable object and a Printer object with a print method that takes a BasePrintable as a param, we created lots of interfaces, objects, patterns, just to be able to print those objects. However the geeks have the chance to bring up their argument: "but we follow SOLID".

Applying Dependency inversion and I am done! We create BasePrintable abstraction, we create BookBasePrintable, PostcardBasePrintable, etc., add the Print class with injectable BasePrintable subtype. Though, to print a book or a postcard we need the right Object from Context to handle it. So in Context we have an object per each printable type. Then the duplication is just hidden it is not solved. We also have a Factory Bean injection or we create a separate bean for each printable type and handle the right instance through "ifs", actually, we are still under the "if" statement realm either way. However, from all others, it is the most clean way linking things, it follows loose coupling which enables tests focus on exactly what BasePrintable is doing, subsequently enabling to test each class in particular, which is a lot more easier then testing each combination. It follows Interface Segregation, Open Closed, Liskov and Single Responsibility.

SOLID principles have their drawbacks. It is sometimes simple to avoid them and make it stupid simple instead of blindly following them as to demonstrate clean code, or whatever...

Top comments (0)