Don't read developer blogs if you want to become a good developer
: Duen Oosthuizen
A blog looking at errors most authors seem to make when writing about SOLID principles.
Yes, pretty ironic title I know, but I think it’s a reasonable one.
I didn’t really care about approaches to programming when I was in university. I just assumed design principles and development methodologies are just rules enforced by squares to ruin my fun. Thankfully I saw the light when I started my first development job.
I would continuously experiment, I still cared about writing good code, but believed I’d find my unique techniques in making software more maintainable and reliable. This was a pretty arrogant view, considering how little experience I had in actually pushing out a product that real consumers would use. I soon found out that it takes a lot of mistakes to find reliable approaches to coding, and that’s not fun when a boss is breathing down your neck. My small dev brain grew three sizes the day I realized that maybe people who have been in the industry for decades, might have something meaningful to say in terms of writing good code.
So from that day, I decided that I would start learning from popular figures in the industry, people who have laid the groundwork for practices that are still followed to this day. Naturally, that lead me to start reading some of Robert C. Martin’s work.
I’m glad I decided to do it properly, because when I found myself reading about blogs about SOLID principles a few months later - it became shockingly clear how little research bloggers do. To illustrate my point, I’ll go over all 5 SOLID principles and name some of the common mistakes I see in almost every blog.
So come along as I take you on a journey of frustration and cringe, into the ugly world of developer blogs.
Single Responsibility Principle
It’s very common to misinterpret a text, at least for me. So I usually revise concepts every few months to make sure I’m not talking complete nonsense. Dev bloggers don’t really seem to do that.
“Do one thing and do it well.”
This a quote I see just plastered over dev blogs, it honestly gives me chills with the confidence that it’s stated. Because it assumes that little nugget of information is enough to infer the entire concept of the principle.
After the blogger has found this cute little term, he/she quickly decide on what they think this means and starts typing away. But what is one thing? Well, according to most blogs, a thing is defined as a lower-level detail, that meaning - dependencies that execute the explicit instructions implied by more abstract business rules. So something like a database operation would be a lower-level detail because it only functions the serve a specific part of a broader concept of the business rules. Bloggers usually separate these lower-level operations and state that these should just be divided between different classes. Thus each lower level dependency being “... one thing…”. So something like an Employee class that uses its lower level dependencies, like a file and database handler, would have to be split into two classes, each only performing one of those operations.
First of all, I can see that people writing these blogs authors, don’t really practice what they preach - writing software like this would take a lot of time without much pay-off. Second of all, if we look in his book Clean Architecture, where Robert C. Martin carefully lays out the definition of each principle, we can see just where everything went wrong. Robert starts with a simple, but much more telling definition:
“A module should have one, and only one, reason to change.”
Already, you can see a bit of a shift, as this is not equivalent to “Do one thing…”. He then expands on the intention of this statement and rephrases the definition to:
“A module should be responsible for one, and only one actor.”
In other words, a module (being a source file), should only contain code that’s responsible to a specific party. So our Employee class we mentioned earlier, would have no restrictions on the amount of lower-level dependencies it can have, as long as it’s all relevant to an actual employee using the system. What if employees can’t access the system? What if the Employee class is used to provide services to administrators of the system? Well then as long as the Employee class doesn’t contain code that’s not relevant to an administrator, the Single Responsibility Principle isn’t broken. What if the Employee class contains code used by both the administrator and the employee? Then it needs to be broken up into two classes, as it will then be responsible for two actors.
The Open/closed principle
What’s funny about this one is how most devs seem to interpret it, completely conflicts with the definition of Dependency Inversion, which is the “D” in SOLID.
“software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”
This definition isn’t as wrong as the previous one, as it only slightly confuses the average reader. I guess the main problem here is using the word “extension”. Because then every OOP junior makes the mental leap of thinking “extension” refers to inheritance. So then, we get blogs where you’re basically told to enact polymorphism, by using child classes to override methods of parent classes. These parent classes can then have multiple implementations without affecting the integrity of the business rules, well at least according to these authors.
Again, the problem here is that it breaks dependency inversion. All dependency inversion really is, is not having concrete dependencies in your classes. These should be replaced with abstract dependencies. Concrete dependencies are volatile and thus make business rules volatile when business rules depend on them. So polymorphism through concrete class inheritance is a bad idea.
The solution? Implement an interface, or inherit an abstract class, instead and you’re doing the same thing - without breaking Dependency Inversion—that simple.
Liskov Substitution Principle
“Let ϕ(x) be a property provable about objects x of type T.
Then ϕ(y) should be true for objects y of type S, where S is a subtype of T.”
As this is the official definition, it’s kind of impossible to really misinterpret this one. Well if you can read that because I can’t.
When it comes down to it, it basically means that any references to a type should be replaceable by a subtype, without breaking operation of the method or class it’s used in. So far I haven’t really seen anyone completely mess this one up.
Interface Segregation Principle
“interface segregation principle states that no client should be forced to depend on methods it does not use.”
It really boggles the mind how people mess this one up. Basically, the methods the definition refers to are interface methods. Classes should not depend on interfaces that contain methods that they don’t use.
Now somehow, at least two blogs have interpreted this as “only use one method per interface”, though I’m paraphrasing. The internet was a mistake.
Dependency Inversion Principle
I already gave you an explanation, so I’m not going to just going to provide you with the good news: Nobody messed this one up, and hopefully, you have a better understanding of SOLID now.
Examples of some of the blogs I’ve found: