top of page
  • Writer's pictureShai Yallin

Not The Design We Want, The Design We Deserve

All too often, developers and tech leaders spend much time agonizing over upfront technical designs. We dive into the deepest trenches of architecture and try to predict every possible future requirement in order to come up with future-proof designs. But this obsession with overengineering is misguided - the design we end up with is almost never the design we actually needed.

This urge to blueprint everything upfront stems from a fear of uncertainty and the desire to be prepared. "What if we need to support 10 million users tomorrow? What if the CEO suddenly demands XYZ features?" We convince ourselves that upfront design is the responsible choice, in part because in past projects we got burned as the design failed to foresee the changes in requirements and was unfitting to solve the problems we faced as our systems matured, and in part because of our need to feel in control, to demonstrate prerequisite planning, to showcase technical prowess. 

The real cost? Innumerable wasted effort creating designs that look impressive on whiteboards or in online charts, but do not map to actual business or technical needs. I've seen teams spend months elaborately modeling services and entities upfront, then having to cram unforeseen requirements into bounded contexts that were too rigid and strict. Instead of flexibility, we get bogged down in paralysis and technical debt. Over-engineered systems are harder to understand, modify, and evolve responsively. As our system matures, changes become more and more costly due to the need to work against a mismatching design.

A simpler path is to start with the most minimal, naively underdesigned system to meet immediate needs, 

then continuously evolve and refine the design through a iterative cycle of real user feedback → system changes → refactoring. Rather than fusing vaporous requirements to code from the start, marry design to demonstrable facts extracted from user behavior. Codify the now, not the theoretical future. Refactor relentlessly to accommodate new understandings and changed requirements.

This Emergent Design through refactoring is the antidote to overdesign. Test-Driven Development provides the perfect catalyst - concrete examples drive design, which effortlessly evolves as new examples gradually change implementation and new refactoring opportunities become apparent.

You're focusing on the wrong things when overdesigning everything upfront. Stop trying to predict an uncertain future. Start delivering what users want today, with the confidence that your design will naturally emerge as you learn. Embrace not getting the design you want upfront - but getting the design you truly deserve through an iterative, evidence-based cycle. The future is unwritten, designs are temporary - spent effort fighting that reality is wasted.

96 views0 comments



Feeling stuck? dealing with growing pains? I can help.  

I'll reach out as soon as I can

bottom of page