A personal appeal.
- Overengineering works against results. Shifting the focus away from results is never good — for personal projects, corporate codebases, or anything in between.
- Overengineering over indexes on things you know. Overengineering invents new constraints instead of tackling real ones. The made-up constraints we tell ourselves are usually ones we already know how to solve (known-knowns vs unknown-unknowns).
- Overengineering is not elegant. Overengineering yields complicated solutions. All other things equal, a machine with fewer moving parts is better than one with many.
- Overengineering is fragile (simplicity is antifragile). Generalizing abstractions rarely creates the optionality that we convince ourselves it does. Overengineering leads to over-specification, which ironically leads to greater coupling.
- Overengineering increases maintenance costs. More engineering means more knowledge that needs to be transferred to coworkers, future contributors, a larger surface for bugs, and continued upkeeping costs.
- Overengineering is indirection. All problems in computer science can be solved by another level of indirection, except for the problem of too many layers of indirection.
- Overengineering is NPV negative, even for real concerns. What’s the net present value of fixing an esoteric edge case? What will happen in the failure mode? How often does the event occur? Overengineering is never a reasonable allocation of resources.
- Overengineering is a precise bet on the future. The more assumptions you make about the future, the more it should be discounted.
- Overengineering misses deadlines. There has never been an overengineered product that was delivered on the deadline.
- Overengineering does not work towards product-market fit (therefore, it works against it). Overengineering is never customer-centric.