- Single Responsibility Principle
- Open-Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
SOLID used to be a cornerstone of my design toolbox. I used to strive to make my code SOLID. I used to teach others to do the same.
Today, SOLID remains important, but I don't strive to make my code SOLID. I rarely mention it when talking about design. And I definitely don't teach it to developers eager to learn good design techniques. It doesn't come with me in my toolbox. It stays in a dusty box up in the attic. I keep it because it is important, but I access it rarely.
SOLID causes problems. Problems big enough that warrant stowing it away in the attic. When I used to champion SOLID, those who resisted would point to these problems. I would dismiss these people as naysayers, resistant to change, or disinterested in code quality. But now I've learned that they were right all along.
If I could use one word to represent these problems, it would be unintelligible. Developers (myself included) applying SOLID frequently produce codebases that are unintelligible. These SOLID codebases have low coupling. And they are testable. But they are unintelligible. And often not as adaptable as the developers had hoped.
The main culprit is SOLID's focus on dependencies. Open/Closed, Interface Segregation, and Dependency Inversion each encourage heavy use of dependencies defined as abstractions (i.e. a C#/Java interface or Abstract Class). Open/Closed encourages abstractions for easy extensibility. Interface Segregation encourages more client-defined abstractions. Dependency Inversion says to depend on abstractions instead of concretions.
These all lead developers to create interfaces everywhere. They litter the codebase with interfaces like IFooer, IDoer, IMooer, and IPooer. Navigating it becomes a nightmare. You rarely know by inspection what piece of code is actually going to run. But it's ok. Because it's SOLID. It's great design!
To help manage the madness, we then introduce an IoC container. And a mocking framework for our tests. If it was intelligible before, now it's really not intelligible. You now literally can't find a call to 'new' anywhere in the code. Good luck reasoning about any piece of code now. But it's ok. Because it's SOLID. It's great design!
Is it great design if it's unintelligible? Is it great design if a developer can't easily reason about it? I don't think so. SOLID is helpful and important. But I don't think developers handle it well. Which is why I don't teach SOLID anymore.
Stay tuned for how to achieve what you're trying to gain with SOLID without the legibility baggage.
UPDATE: You can find the next part here.