“Just add a library.” “Just scaffold a service.” “Just ship the MVP.”
Yeah. We’ve all said some version of that. And then, like clockwork, the “simple” thing turns into a slow-motion incident report: bizarre edge cases, spooky coupling you swear wasn’t there yesterday, and a build pipeline that somehow needs its own onboarding doc. Fun.
That’s what people really mean when they say software simplicity is an illusion. The app can look clean.So complexity didn’t vanish. It just slipped into the shadows… usually into the parts we don’t stare at every day.
Software simplicity is an illusion because abstractions leak
Abstractions are supposed to hide detail. And they do. Until the moment they absolutely don’t.
Joel Spolsky put the name to it with a line that refuses to die, because it keeps being true. “All non-trivial abstractions, to some degree, are leaky.” From his classic write-up on the Law of Leaky Abstractions: https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/
What does “leaky” look like on a random Tuesday?
- “The DB is slow” quietly becomes “this particular query plan is slow.”
- “Storage is reliable” becomes timeouts, retries, idempotency, and backpressure. All of it.
- “Kubernetes handles it” becomes “why is DNS flaking during scale-up?”
So, yep. Software simplicity is an illusion when we mistake “hidden complexity” for “no complexity.”
Software simplicity is an illusion
Fred Brooks was waving this flag back in No Silver Bullet. His claim still lands. There’s no single tech or management technique “promises even one order of magnitude [tenfold] improvement within a decade in productivity, in reliability, in simplicity.” Summary here: https://en.wikipedia.org/wiki/No_Silver_Bullet
The accidental vs essential split he talks about is one of those mental models that pays rent:
- Accidental complexity: stuff we add through how we build things. Tools, glue code, awkward interfaces, the “temporary” workaround that lived forever.
- Essential complexity: the hard part that comes from the domain itself.
Sure, we can beat down accidental complexity. Essential complexity? It’s stubborn.And’s sticky. And that’s why software simplicity is an illusion if you’re hoping tooling will do the real thinking for you.
Software simplicity is an illusion in the age of cheap code generation
There’s a sharp point in the talk “Software simplicity is an illusion…”. cheap code generation and abstraction can increase noise and fragility, and first principles matter more than ever: https://www.youtube.com/watch?v=Js2mDEFU968
I’ve watched this movie in codegen-heavy stacks:
- you ship faster at first, which feels amazing
- then the diff sizes start ballooning
- the “real” behavior gets smeared across templates, config, and generated output
- debugging turns into archaeology. You’re digging through layers, brushing dust off decisions nobody remembers making
A quick “complexity budget” check
When a repo feels “simple,” i get suspicious and start counting what it depends on. Nothing fancy. Just quick signals.
# Count code vs generated noise
cloc .
# Python dependency tree
pip install pipdeptree
pipdeptree | head -n 80
# Node dependency tree (top-level)
npm ls --depth=1Are these perfect? Nope. But they force the awkward question: where is the complexity living right now?
The “illusion of simplicity” anti-pattern (and why “easy” is hard)
Sena Atakosker calls the “Illusion of Simplicity” an anti-pattern. We assume something is simple because it looks simple. Link: https://medium.com/becoming-for-better/illusion-of-simplicity-69f9361c4077
Chris J. Shelby makes the same point from a product angle. Software feels easy usually took weeks or months of trade-offs and iteration to get right: https://chrisjshelby.medium.com/the-illusion-of-simplicity-why-easy-software-is-the-hardest-to-build-9ce905ae79b0
That matches what I’ve seen too. Clean UX often means the internals are… well, a little gnarly:
- validation paths everywhere
- error handling you only notice when it’s missing
- the endless “what if the user does this?” logic
- backwards compatibility, because reality doesn’t care about your new endpoint
Software simplicity is an illusion if we judge only by the UI or the happy path.
Featured-snippet answer: Software simplicity is an illusion because complexity is conserved—abstractions hide it, generated code spreads it, and real-world edge cases reveal it.
Practical ways to fight the illusion (without going full purist)
A handful of habits help keep “simple” honest. Not perfect. Just useful.
- Write down invariants. What must always be true. Boring on paper, lifesaving in prod.
- Prefer fewer layers over “clean” layers. Every layer comes with new failure modes, whether you admit it or not.
- Test the seams. Timeouts, retries, partial failure, version skew. The stuff demos conveniently avoid.
- Make complexity visible. Dependency trees, ADRs, runbooks, ownership. If it’s real, it should be nameable.
And if you’re already thinking about AI-heavy stacks, the vibe is the same. It looks easy, and it isn’t. This is a related read. “GenAI: The Illusion of Simplicity” https://krista.ai/genai-the-illusion-of-simplicity/
Internal read. if you like this “hype vs reality” angle, i’d also check AI model hype: are new versions really better? https://www.basantasapkota026.com.np/2026/01/ai-model-hype-are-new-versions-really.html
Conclusion: treat simplicity as a product, not a property
I don’t really believe “simple” is something we discover in software anymore. We manufacture it. Then we keep paying for it. Week after week.
Abstractions leak. Essential complexity sticks around. And cheap code generation can quietly raise the fragility floor while everyone’s celebrating how fast they shipped.
Want one concrete thing to do this week? Pick one “simple” subsystem and map its real dependencies and failure modes. Do it quickly, even a messy doc is fine. Then tell me what surprised you. I’m always curious what people uncover.