How (not) to write Factorial in Java will hit home for any software developer who’s had to deal with over-engineered code.
I’ve come to view layers of abstraction as costing technical rent. It’s a concept worth distinguishing from technical debt. Rather than pushing a cost into the future, technical rent involves paying a manageable up-front cost by building the abstraction in code, and then needing to pay a similar cost each time programmers revisit the code, by rebuilding the same abstraction in their heads.
The worst part is when the layer of abstraction is justified as an intervention against potential technical debt: a small cost now to avoid interest payments in the future. In reality, the small cost has to be paid over and over, even if it turns out that the requirements never change in the particular direction that the abstraction anticipates.
You could call it defensive abstraction. The logic hides several assumptions:
Occasionally the abstraction does actually provide enough benefits to outweigh its future costs, but failure to recognize the existence of those costs leads to poor decisions.
[Expanded from a comment I made on Hacker News.]