Abstractions have a cost. Your project, team, and you will carry the cost of that abstraction for its lifetime.
We don’t like to say that, because as developers we love abstractions, but every single abstraction carries a cost, and that cost affects everyone that develops, tests, or uses the application.
Most of the time, we believe (or it is demonstrable that) these abstractions provide more value than they cost.
Sometimes we do this without any evidence that that’s the case.
I was reviewing a codebase recently and most of the codebase was T4 template generated. Every controller and model was generated from a T4 template; with logic inside those templates that through user input determined what was generated and how it was generated.
I have no doubt when these abstractions were introduced, the team thought they’d save lots of time.
One year later, that application is no longer maintained; and in fact, within a few months of release it was no longer maintained.
What sort of value did they get out of a complex abstraction for only 3 months of maintaining it?
It’s hard to tell, but my immediate guess is “not much”.
Abstractions have a cost.
In another project I worked on, the firmware for Jewelbots, there were almost no abstractions. While I had the privilege to have an SDK to use for the System-On-Chip we sourced for our Jewelbots, there were breaking changes every release, and the little abstractions that were present would wildly change. I was so close to the metal that I would have wished for an abstraction or ten.
Where’s the balance?
First off, if someone says “this abstraction will save us X time”, you should ask them to prove it before implementing it system wide. That seems a bit adversarial, so maybe there’s an easier way?
We talk about software design as this abstract thing; divorced from the day to day realities of software development. We treat software as if we’re in the frontier west, living out of wagons and running from one gold rush to the next. We’re so busy adding on what we might need that we forget what we do need: Software that we know works. Software that we know we can change without having to rewrite it because it’s too complex to change. What we’ve forgotten is that while we treat goldrush software as an ideal, we’re asking billions of people to put their trust in our software. We build abstractions that don’t make things better for our customer, and only make things marginally better for ourselves, while ignoring the concepts that will help both ourselves and our customers.
If you’re willing to spend 3 months on code generation, or 3 months on some fancy Entity-Attribute-Value machination that makes it ‘easier to add new features without a database update’ (God help us all), you should be willing to build your software through Test Driven Development. Not only will your software come out better designed, and with fewer bugs, but you’ll also achieve a balance to the abstractions you want to create; by creating abstractions that are easily testable (and thus, easy to change).