Technical
Simplicity as an Architectural Principle
Every system I have built that lasted was simpler than the industry consensus said it should be. Every system I have seen fail was more complex than its actual requirements. That is not a coincidence. Simplicity is not just a nice-to-have; it is the survival strategy for systems that have to run without constant attention.
What Simple Means
Simple is not the same as easy. A complex system can be easy to use (Google search) while being impossibly hard to build. A simple system can be hard to understand (Unix pipes) while being trivially easy to build.
I use a different definition: a system is simple when removing any part breaks it. That definition forces honesty. If I can remove a component and nothing changes, that component was accidental complexity.
The Three Signals
I know a system is too complex when I see:
- Abstractions with one implementation: interfaces, strategy patterns, factories that only ever produce one type. These are hedges against future flexibility that never arrives.
- Configuration for things that never change: environment variables for settings no one has ever flipped. If it is effectively a constant, make it a constant.
- Services that only talk to one other service: microservices that could be functions.
Each of these trades simplicity for imagined future flexibility. The future usually does not arrive.
A Real Example
A client had a system with 14 microservices for a SaaS with 400 users. The services were deployed with Kubernetes, orchestrated with Argo, and monitored with a Prometheus stack. The platform team was four people.
We replaced it with a Django monolith and a Postgres database. Three servers, one developer, one CloudWatch dashboard. Same features, same users. Operating cost went from $8,000/month to $200/month.
When Complexity Is Justified
Some systems genuinely need complexity:
- Google-scale traffic (yours probably is not)
- Hard real-time requirements (game engines, trading systems)
- Independent team velocity (if teams block each other, splitting is worth it)
If none of these apply, you do not need the complexity. And most teams do not have any of these constraints.
The YAGNI Principle
'You Aren't Gonna Need It.' Every feature you add for 'future flexibility' costs real time now. You pay the complexity premium on day one, and most of the time you never use the flexibility you paid for.
Add complexity when you need it, not when you anticipate needing it.
The Reversibility Test
Before adding a dependency, framework, or architectural pattern, ask: how hard would it be to remove this later? If the answer is 'trivial,' add it without worry. If the answer is 'this will be baked into the system forever,' pause and think harder.
The reversible choices are cheap to get wrong. The irreversible ones need more thought.
The Boring Technology Win
I default to boring technology: Postgres over specialty databases, Django or FastAPI over exotic frameworks, React over the framework of the month. Boring technology has fewer bugs, better documentation, and more people who can maintain it.
Being on the bleeding edge means you hit the bleeding edge. That is a cost you pay every week. It needs to be worth it.
See Dan McKinley's classic Choose Boring Technology essay for a deeper argument on the same principle.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read