Does following SOLID lead to writing a framework on top of the tech stack

frameworkssolid

I like SOLID, and I try my best to use and apply it when I'm developing. But I can't help but feel as though the SOLID approach turns your code into 'framework' code – ie code you would design if you were creating a framework or library for other developers to use.

I've generally practiced 2 modes of programming – creating more or less exactly what is asked via requirements and KISS (typical programming), or creating very generic and reusable logic, services, etc that provide the flexibility other developers may need (framework programming).

If the user really just wants an application to do x and y things, does it make sense to follow SOLID and add in a whole bunch of entry points of abstraction, when you don't even know if that is even a valid problem to begin with? If you do add these entry points of abstraction, are you really fulfilling the users requirements, or are you creating a framework on top of your existing framework and tech stack to make future additions easier? In which case are you serving the interests of the customer, or of the developer?

This is something that seems common in the Java Enterprise world, where it feels as though you're designing your own framework on top of J2EE or Spring so that it's a better UX for the developer, instead of focusing on UX for the user?

Best Answer

Your observation is correct, the SOLID principles are IMHO made with reusable libraries or framework code in mind. When you just follow all of them blindly, without asking if it makes sense or not, you are risking to overgeneralize and invest a lot more effort into your system than probably necessary.

This is a trade-off, and it needs some experience to make the right decisions about when to generalize and when not. A possible approach to this is to stick to the YAGNI principle - do not make your code SOLID "just in case" - or, to use your words: do not

provide the flexibility other developers may need

instead, provide the flexibility other developers actually need as soon as they need it, but not earlier.

So whenever you have one function or class in your code you are not sure if it could be reused, don't put it into your framework right now. Wait until you have an actual case for reusage and refactor to "SOLID enough for that case". Don't implement more configurability (following the OCP), or entry points of abstraction (using the DIP) into such a class as you really need for the actual reusage case. Add the next flexibility when the next requirement for reusage is actually there.

Of course, this way of working will always require some amount of refactoring at the existing, working code base. That is why automatic tests are important here. So making your code SOLID enough right from the start to have it unit-testable is not a waste-of-time, and doing so does not contradict YAGNI. Automatic tests are a valid case for "code reusage", since the code in stake is used from production code as well as from tests. But keep in mind, just add the flexibility you actually need for making the tests work, no less, not more.

This is actually old wisdom. Long ago before the term SOLID got popular, someone told me before we try to write reusable code, we should write usable code. And I still think this is a good recommendation.

Related Topic