SOLID principles are not WRONG


I am aware of the imposed necessity of bringing attention with titles (specially for talks), but one also needs to be aware that titles are, sometimes, the one and only thing that sticks.
And there, lies the need of them not being untrue.

Some weeks ago I read a tweet from Rob Connery recommending a Dan North's talk he attended while in a conference.

I have the most utter respect for these two individuals. They are respected professionals and, in my opinion, both brilliant speakers.
And so I gave the slide-deck a good read.
The reader might as well do the same. I'll be waiting.

Is it the context?

I have not been able to watch any videos of the talk, so there is a chance that I am getting it all wrong, but, you see, if one writes something and then tells the exactly opposite... what would the use of a script that it is not what the author meant?
So, from now on, I will be assuming the slide-deck is the foundation and the message conveyor of what was said in such talk.

My bias

I am a software engineer myself that takes software design very seriously as believe that design amounts to a big share of the success of a software system.
As I have spent majority of my career in a world of Objects, Object-Oriented Design is both part of my day-to-day job and also one of the topics in computing that I enjoy the most.

I have also dug a bit deeper into the realms of what lies behind the SOLID acronym, so I consider myself mildly knowledgeable about the topic and, as a side note, a bit of a fan of such principles having seen some of the benefits they report to systems built following their ideas.

Wrong They are NOT

When I first read the title (and not the content) I was honestly expecting Dan to have seen the proverbial absolute truth of Functional Programming that a lot of software engineers seem to have seen lately and I was expecting him bashing the principles for how useless they are in the functional paradigm and how superior is the functional world compared to the rancid world of objects in which SOLID have some sort of relevance.
Far from it, there is no mention in the slides to functional programming, so my first impression was utterly wrong.

After reading the whole content (twice) I honestly thought it was some sort of joke or sarcasm. Kind of twisted, but kind of funny at the same time.
However, some of the points make really good sense, so I doubt all of it to be a joke or sarcastic.

From the content of the slide-deck I will try to analyze some of the claims made for each of the principles:

Single Responsibility Principle

Dan calls this principle pointlessly vague, maybe due to the, let's admit it, somewhat vague definition of responsibility.

He questions our ability to predict what is going to change, because one definition of responsibility is "reason to change" and since we do not know what might change, we cannot possibly maintain that unknown "single" (or, at least, in the lows).
However, there are indeed ways to know with higher certainty than guessing what is likely to change. To my mind come two from my experience:

  • whatever has changed in the past
  • whatever the client says it won't change

The first is used (or, at least was) in very high performance systems, such as micro-processor caches, so I guess it might be of some use.
The second sounds more like a joke, but I found it to be scarily accurate. Imagine your client tells you there is a hard invariant in a system you are building. IT is the cornerstone of their business and strategy and it has to be maintained at all costs. It can't possibly change. No matter how hard you press your client to open a possibility of that key invariant to change... It just won't. 100% guaranteed. That moment is your moment to nod politely and make a note to pass to your boss: "a fancy dinner on a change invariant X before phase 2. u r on?".

There are places in the system in which you are probably to sniff future changes. The closer to the eyes (visually), the higher the probability. Do we want to recklessly mix very volatile elements with some that are not? Likely not. Regardless of their simplicity or their low complexity.

Open-Closed Principle

Dan calls off this principle for allowing unneeded code to exist in lieu of a futurible change. I cannot say he is wrong, but I still believe this principle is very useful. Let me tell you more.

Remember the heuristic I gave you about things bound to be changed? Well, one can take a gamble when designing the system, preparing it to be extended in an easier way when reality changes (and experience tells you it will likely change). It is not a particularly risky gamble, mind you, and one does not have to add a lot of scaffolding just in case. But getting ready for when the change comes is advisable.
A more specific example would be having a chain of responsibility instead of a list of _if_s. Certainly, with two links (a single branch) seems overkill. But knowing that now it is two, but it will grow to 10+, a lot of pain and rework in the future will be spared.
And that is because this principle. It is a principle and needs to be used and not abused. However I have the certainty that write simple code and replace it when it is wrong can receive more abuse than OCP.

Liskov Substitution Principle

Dan calls this useless based on the premise that inheritance should be avoided at all costs.
Well he is definitely right in that composition should be preferred. But that is not to say that inheritance does not have a place at all in designing Object-Oriented systems. And when inheritance is involved, one is a much better position if LSP is followed.

And there are times in which inheritance cannot be avoided. Some frameworks are meant to be used via inheritance (exceptions, graphic libraries,...). One can argue that is not an optimally designed system, but when there are few feasible options to replace it, bitting the bullet is no sin. Once bitten, one is better off knowing about LSP to prevent mischiefs such as downcasting.
Would it be nice that a concrete exception threw when trying to display a message? Probably not. Knowing about LSP would make you think twice about doing such thing.

Oh, and I strongly disagree that objects hierarchies should be avoided altogether. They should be pondered heavily, but in occasions, hierarchies are the simplest solution. Wasn't it simple the way to go?

Interface Segregation Principle

For this principle, I think Dan is more accurate than with any other. Writing simple role-based code leads to ISP.

But that is not the same as saying ISP is wrong. Small, focused components. Sounds easy and yet, one has to be reminded.

Dependency Inversion Principle

Dan call it the wrong goal principle. I have to agree that design of small components is a better goal than reuse, but I strongly disagree on DIP leading to dependency on DI frameworks. If anything, well applied, DIP leads to depend even less on DI frameworks (just use it in the composition root and off you should go).

One can go very far with new. But just so far. Good luck testing external systems (tickers, sensors,...) that you new-ed up when a certain behavior is needed for testing the system. Not everything needs to be abstracted, but for certain situations, abstracted dependencies are the way to go.

Old Man's babble

Let me tell you a story...

I was a consultant. We were building a new portal and there was this integration to an existing datasource. Same behavior, same data, it was already working. The estimation time for that task was set to the minimum. What could possibly go wrong?
The datasource system was indeed simple. Unfortunately, simple as it was, it was doing way too much and in the wrong places. The system was a stored procedure, retrieving some data, performing some simple transformations and ... wait for it... generating the HTML that was displayed. Yes, HTML. Tables. With embedded styles. In a stored procedure. At that point, the minimal estimation time was already not achievable and I was the bad news bearer to the client. The very same client that paid big bucks for that system to the same company my company was co-working with: "sorry, can't do in allocated time because, with all due respect, the system is shite".

It was a simple system, easy enough to reason about at the time of writing.
I am sure it fitted inside the head of the perpetrator at that time.
Definitely the code was changed "easily" and deployed even more easily (cowboy edit to live database and boom! magic is unveiled) when changes were asked.
There was neither inheritance to composition. Simple, I told you.
The client was dependent on only small surface: make a query and assemble the strings. No need to invert simplicity.

Despite ticking all simplicity marks they managed to crap over SOLID principles big time.
The system had too many responsibilities of different nature: querying, a bit of logic and presentation. SRP off the board.
As far as any change was needed, the heart (and brain and kidneys and...) of the system had to be changed. Not open in any sort of definition of openness. OCP violated.

Would the end result of the system be better had the developer read about SOLID? Probably.
It could have been worse too. Over-complicated, obscure code.
SOLID is not a recipe one follows to get consistent tasty meals. It is a set of principles which catchy mnemonics to be reminded about desirable characteristics of well-designed software. The cook still matters.

Responsible talking

SOLID principles are heuristics, reminders of a nicer world. Not all of them need to be applied and certainly not all at the same time.
Dismissing them and providing a uber-vague heuristic (just write simple code) places ourselves in no better position.
Write simple code helps less to write better code compared with what SOLID resonates.
The goal is the same, but one is a subset of the other. SOLID code should strive for simplicity.
When guidance is offered, specific is to be preferred.

Worse yet. Imagine the reaction of someone who is not too experienced (or too lazy) in software design reading just the headline (like majority of human beings would do): SOLID principles are wrong therefore I won't even bother reading more about them. Who would ever bother reading about something that is wrong?
Such person would miss a great opportunity to read about cohesion, coupling, viscosity, rigidity,... and many others concepts to be discovered when further reading about SOLID. I am afraid those concepts would not appear as easily when tied to simple.

Calling them wrong is a fantastic disservice to an already challenged area of knowledge.
Poorly designed systems vastly outnumber carefully designed ones. I refuse to think that is because SOLID principles are wrong.
I would venture to say that, in a poorly designed systems, the perpetrator is less likely to have heard or applied SOLID than in a better designed one, even if such principles have not been followed "by the book" (hint: there is no book).

We all fancy a witty comment. But one should be careful with the message which remains. And I believe SOLID is wrong is a terrible message to remain.