Most engineers overestimate how much complexity they need to solve today’s problems.
We’ve been taught to prepare for scale. To architect for flexibility. To abstract away the details that might change later.
But there’s a hidden cost to every abstraction layer, every parameterized configuration, every "future-proofing" decision we make.
Complexity Has a Cost #
Every line of code you write:
- Takes time to understand when someone (or you, six months later) reads it
- Can introduce bugs in subtle and unexpected ways
- Requires maintenance as requirements change
- Multiplies context that someone needs to keep in their head
The more complex your system, the higher the cognitive load on every person who touches it.
And cognitive load is the real bottleneck in engineering—not CPU or memory or network latency.
Why We Build Complex Systems #
We usually build complexity for one of three reasons:
1. Premature optimization
We optimize for a scale that doesn’t exist yet. We shave milliseconds off hot paths in code that runs once per day. We architect for millions of users before we have thousands.
2. Over-generalization
We build abstractions that handle "all possible cases" instead of the cases we actually have. We parameterize configuration that will never change.
3. Defensive programming
We add error handling for exceptions that shouldn’t happen. We validate inputs that can only come from trusted sources. We add layers of redundancy everywhere.
All of these have their place—but most projects suffer from too much, not too little.
The Simplicity Test #
Before you add a layer of abstraction or a configuration option, ask:
- Do I need this today? If not, don’t build it.
- Will this be easier to add later? For most things, yes. Abstraction layers are easier to add when you understand the problem better.
- Who will understand this? If only you can reason about it, it’s too complex.
What Simple Systems Look Like #
The best systems I’ve worked on had a few things in common:
- Clear boundaries - Each component has one job
- Obvious data flow - You can follow how data moves through the system
- Minimal indirection - If something happens, you can trace why
- Explicit over implicit - The code shows you what it does, not what it might do
None of these require less code. Sometimes they require more. But they’re easier to reason about.
The Reality #
The most expensive systems aren’t the ones with the most features. They’re the ones nobody understands.
Before you write your next architectural decision, ask yourself:
Am I solving a real problem today, or preparing for a problem that might never come?
Often, the answer will surprise you.
Start simple. Add complexity when you feel pain, not when you anticipate it.
Your future self will thank you.