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:

  1. The requirements in that area will change.
  2. The abstraction, out of all possible abstractions, will happen to be the right one to cover the change.
  3. Adding a new case to the abstraction is simpler than changing the caller(s).
  4. At that future time, the programmer will choose taking on technical debt over adding the abstraction as needed. (This mainly applies if the requirements can change while the callers can’t, the practical likelihood of which varies with the situation.)
  5. The mental cost of rebuilding the abstraction, paid repeatedly throughout the life of the codebase, is outweighed by the interest paid on the technical debt, paid only until it’s corrected.

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.]

blog comments powered by Disqus