This blog post is a reply to Dan’s presentation Why Every Element of SOLID is Wrong.
Dan’s presentation is crammed full with straw man argumentation in which he misinterprets what the SOLID principles are about. After refuting each principle he proposes an alternative, typically a well-accepted non-SOLID principle that does not contradict SOLID. If you are not that familiar with the SOLID principles and cannot spot the bullshit in his presentation, this blog post is for you. The same goes if you enjoy bullshit being pointed out and broken down.
What follows are screenshots of select slides with comments on them underneath.
Dan starts by asking “What is a single responsibility anyway?”. Perhaps he should have figured that out before giving a presentation about how it is wrong.
A short (non-comprehensive) description of the principle: systems change for various different reasons. Perhaps a database expert changes the database schema for performance reasons, perhaps a User Interface person is reorganizing the layout of a web page, perhaps a developer changes business logic. What the Single Responsibility Principle says is that ideally changes for such disparate reasons do not affect the same code. If they did, different people would get in each other’s way. Possibly worse still, if the concerns are mixed together and you want to change some UI code, suddenly you need to deal with and thus understand, the business logic and database code.
How can we predict what is going to change? Clearly you can’t, and this is simply not needed to follow the Single Responsibility Principle or to get value out of it.
Write simple code… no shit. One of the best ways to write simple code is to separate concerns. You can be needlessly vague about it and simply state “write simple code”. I’m going to label this Dan North’s Pointlessly Vague Principle. Congratulations sir.
The idea behind the Open Closed Principle is not that complicated. To partially quote the first line on the Wikipedia Page (my emphasis):
… such an entity can allow its behaviour to be extended without modifying its source code.
In other words, when you ADD behavior, you should not have to change existing code. This is very nice, since you can add new functionality without having to rewrite old code. Contrast this to shotgun surgery, where to make an addition, you need to modify existing code at various places in the codebase.
In practice, you cannot gain full adherence to this principle, and you will have places where you will need to modify existing code. Full adherence to the principle is not the point. Like with all engineering principles, they are guidelines which live in a complex world of trade offs. Knowing these guidelines is very useful.
Clearly it’s a bad idea to leave code in place that is wrong after a requirement change. That’s not what this principle is about.
Another very informative “simple code is a good thing” slide.
To be honest, I’m not entirely sure what Dan is getting at with his “is-a, has-a” vs “acts-like-a, can-be-used-as-a”. It does make me think of the Interface Segregation Principle, which, coincidentally, is the next principle he misinterprets.
The remainder of this slide is about the “favor compositions about inheritance” principle. This is really good advice, which has been well-accepted in professional circles for a long time. This principle is about code sharing, which is generally better done via composition than inheritance (the latter creates very strong coupling). In the last big application I wrote I have several 100s of classes and less than a handful inherit concrete code. Inheritance has a use which is completely different from code reuse: sub-typing and polymorphism. I won’t go into detail about those here, and will just say that this is at the core of what Object Orientation is about, and that even in the application I mentioned, this is used all over, making the Liskov Substitution Principle very relevant.
Here Dan is slamming the principle for being too obvious? Really?
“Design small , role-based classes”. Here Dan changed “interfaces” into “classes”. Which results in a line that makes me think of the Single Responsibility Principle. More importantly, there is a misunderstanding about the meaning of the word “interface” here. This principle is about the abstract concept of an interface, not the language construct that you find in some programming languages such as Java and PHP. A class forms an interface. This principle applies to OO languages that do not have an interface keyword such as Python and even to those that do not have a class keyword such as Lua.
If you follow the Interface Segregation Principle and create interfaces designed for specific clients, it becomes much easier to construct or invoke those clients. You won’t have to provide additional dependencies that your client does not actually care about. In addition, if you are doing something with those extra dependencies, you know this client will not be affected.
This is a bit bizarre. The definition Dan provides is good enough, even though it is incomplete, which can be excused by it being a slide. From the slide it’s clear that the Dependency Inversion Principle is about dependencies (who would have guessed) and coupling. The next slide is about how reuse is overrated. As we’ve already established, this is not what the principle is about.
As to the Dependency Inversion Principle leading to DI frameworks that you then depend on… this is like saying that if you eat food, you might eat non-nutritious food such as sand, which is not healthy. The fix is not to reject food altogether, it is to not eat food that is non-nutritious. Remember the application I mentioned? It uses dependency injection all the way, without using any framework or magic. In fact, 95% of the code does not bind to the web-framework used due to adherence to the Dependency Inversion Principle. (Read more about this application)
That attitude explains a lot about the preceding slides.
Yeah, please do write simple code. The SOLID principles and many others can help you with this difficult task. There is a lot of hard-won knowledge in our industry and many problems are well understood. Frivolously rejecting that knowledge with “I know better” is an act of supreme arrogance and ignorance.
I do hope this is the category Dan falls into, because the alternative of purposefully misleading people for personal profit (attention via controversy) rustles my jimmies.
If you’re not familiar with the SOLID principles, I recommend you start by reading their associated Wikipedia pages. If you are like me, it will take you practice to truly understand the principles and their implications and to find out where they break down or should be superseded. Knowing about them and keeping an open mind is already a good start, which will likely lead you to many other interesting principles and practices.
I actually agree with Dan’s post on most of this. I still like the ‘single responsibility’ and ‘dependency injection’ principles, but ther others are heavily anchored in inheritance, which in my experience, almost always makes things way more complicated than they need to be.
Open/closed: Very much an inheritance idea. I feel it’s almost always better to not use inheritance and write code as compositions of very small functions.
Liskov substitution: Again, this makes sense if you’re practising inheritance, but is that a good idea?
Interface segregation: Developers following this can end up writing large classes with lots of specialised interfaces. This is not simple code. Just write really small classes or even functions. Dependants only depend on the classes/functions they need. Simple to read, simple to change, simple to test.
If with “inheritance” you mean “code reuse via inheritance”, as I suspect you do, then I fully agree that it is almost always a bad to go down this path. I very much disagree that the 3 principles in question are about abusing inheritance like this. In fact, they do quite the opposite, and lead you to composition-based designs.
* Open/closed: composition allows you to extend the behavior of a system without modifying it. Higher order functions are an example of this, no objects needed
* Liskov substitution: this has nothing to do with code reuse via inheritance. It has to do with subtyping. Getting this right is important when you do composition. If you just reuse code from base classes instead of using subtyping for polymorphism, following this principle won’t help you much. And indeed, people writing such badly designed code tend to not get this principle from what I’ve seen.
* Interface segregation: …
I recommend you have a closer look at the definitions of the principles.
I agree with you completely.
I think even abstract base classes are a code smell most of the time.
In a short comment you break down SOLID into the good, the bad, the awful.
North otoh spent how much time incoherently stating nothing and just tossing insults. He is a smug simpleton w and i feel like ive seen code
Solid is the religion of the software engineers. Dogmatic nonpractical way of programming and a waste of time