and foundation behind them
Let’s start with Extreme Programming
I like to correlate SOLID principles with XP principles. Just to remind you, full XP chain is formed of values, principles and practices — in exactly this order, from the most fundamental elements to derivatives. Values are what drives us, what defines us and our behavior. Principles are certain rules that comply with values. Practices are some activities based on principles. Neither principles nor practices have no sense without values.
If SOLID are just principles, what are the values?
Before delving into this philosophical discussion, I want to say what mental image I see when I hear the word “program code” — at least, when I’m involved in domain logic implementation. To me, program code is a representation of business processes in some programming language. Ideally, there is a bijection between them. It’s a business-IT alignment that is manifested in a lower level than SOA — in program code. That’s why OOP is a better fit for that than, say, procedural programming: it has all the tooling for representing entities from real life’s domains. Yes, I’m talking about objects. So modeling correct abstractions, representing real life processes, is apparently the most essential part in object-oriented software development. I would say that it is its values.
Are SOLID principles necessary and sufficient?
Let’s take a look at all of them in turn.
Single Responsibility Principle
Being rather ambiguous, it basically tells that the object should be cohesive. If a class is cohesive, if there is a single higher-level purpose, if its responsibilities conform to its name, the SRP would come out naturally.
The practical consequence of applying OCP is that if any behavior, which is part of some class, can change, than its implementation should hide behind an interface, so you won’t have to modify any code of that class. This has a name already — it is loose coupling.
Liskov Substitution Principle
It is basically a definition of Polymorphism, more precisely — Subtyping. I love them both, but I love encapsulation and composability as well. So why there are no “e” and “c” letters in SOLID abbreviation?
All in all, it’s about loose coupling, again.
Interface Segregation Principle
Following the definition, it goes against fat interfaces, the ones that have lots and lots of implementing classes. So once again it’s about loose coupling.
Dependency Inversion Principle
Ok, here, besides loose coupling, there is a concrete (and mechanical) guideline on how to modularize your software.
So, I can’t see anything revolutionary in SOLID. It’s all about low coupling and high cohesion.
SOLID principles and encapsulation
High cohesion and low coupling are concepts broad enough so that encapsulation I believe can be derived from them. Just in case — by encapsulation I usually mean information hiding as well, which is not ubiquitously accepted.
Take a look at the following code:
public function call(IC $c);
public function __construct(IB $b, IC $c, int $d)
$this->b = $b;
$this->c = $c;
$this->d = $d;
public function someBehavior()
What makes objects of class A and interfaces IB and IC highly encapsulated? None of them expose their internal structure or pure data: no public access to instance variables, no getters, no constants, no public static properties. Instead, all of the internal data is used internally, resulting in objects created by class A being very cohesive. Besides, no other objects’ data is required for object A. Instead, it relies only on behavior exposed by interfaces IB and IC. And class A doesn’t bother about their concrete implementation, which apparently resides in some other module. That makes the whole system very loosely coupled.
I would consider an extent to which a class is encapsulated as a more tangible gauge of whether this class is good or bad — in case high cohesion and loose coupling seem a bit abstract concepts. At least to my taste, encapsulation is way less ambiguous and vague notion than SOLID.
SOLID principles and reusability
Originally, OOP was never about reusability. Again, it comes up naturally when your model is decomposed correctly. Reusability is a consequence of such decomposition. Putting it in the first place can hardly lead to correct abstractions, and to maintainable code. And you could get a feel of what was OOP like originally by reading some good books about Smalltalk. Don’t worry, they are more about good object design than on Smalltalk.
SOLID is not a comprehensive set of axioms that the whole OOP is based upon. It’s a good gauge of already built design, but arguably not the best set of principles to pursue while actually building it. I believe high cohesion and loose coupling are way more clear beacons.
Moreover, one shouldn’t forget that each one is meant to be a principle, not a core value of good software. So it doesn’t make any sense to apply any of them purely mechanically, without identifying correct abstractions.