Nguyen Le Phong

Complexity Is Inevitable, Simplicity Is Sustainable: Lessons from Large-Scale Systems — and Life

Early in my career I believed a “great” system meant the newest tech, the most abstraction layers, and the cleverest “magic code.” Years inside large-scale distributed systems taught me the opposite. Complexity is the inevitable price of growth — but simplicity, the kind that comes from clarity, is what lets a system (and a life) survive people leaving, tech ageing, and requirements shifting. A warm, office-relatable look at essential vs. accidental complexity, the compound interest of technical debt, why staying simple is the harder choice, and how the same idea quietly steadies a busy modern life.

Complexity is the inevitable price of growth. Simplicity is the quiet investment in the future. One is what you pay to get big; the other is what lets you stay alive once you are.

In my first years as an engineer, I held one belief with almost religious conviction: a “great” system was a place where the newest technologies gathered, where abstraction layers stacked floor upon floor, and where the more “magic code” there was, the more it proved the brilliance of whoever wrote it.

Then years spent wrestling with large-scale distributed systems taught me a very different lesson.

At the scale of tens of millions of users, a line of code is never just “correct or wrong.” It is also operating cost. It is latency. It is the user’s experience and, in the end, the business result. After countless refactors, tear-it-down-and-rebuilds, and sleepless nights chasing problems I had created for myself, one paradox kept showing up:

Complexity is inevitable when things grow. But simplicity is the foundation of sustainable growth.

This is a warm, office-sized look at that paradox — why complexity always arrives, the trap that quietly rots systems from the inside, what “simple” really means, why staying simple is the harder choice, and how the very same idea steadies a busy modern life.

1. Why complexity is inevitable

Every great system begins with something tiny: a few APIs, one database, and a small team sitting around the same table. But the law of growth never lets us stand still.

When traffic multiplies, when the business demands speed (time-to-market), and when constraints around SLA or Security & Privacy tighten, the system is forced to evolve. That is when complexity shows up — uninvited. It arrives wearing many costumes.

Where it growsIn the systemThe everyday parallel
InfrastructureSharding, Replication, Multi-level Caching, Multi-regionOne shared drive becomes many offices, with backups, branches, and copies kept in sync
ArchitectureEvent-driven, Async processing, Distributed transactionsOne to-do list becomes many teams handing work off to each other across time zones
Security & ComplianceData Encryption, RBAC/ACL, Audit Logging, legal constraintsOne office key becomes badges, sign-in logs, NDAs, and yearly audits
ProcessBackward compatibility, Zero-downtime migration, CI/CD AutomationRenovating the shop while it stays open, without ever turning customers away

And here is the part we love to forget: complexity also comes from people and organisations. Team A needs speed; Team B needs safety. Ops needs stability; Product needs features. Those competing interests turn a software architecture into a tangled map of compromises — and no diagram ever shows that part.

So complexity is not a mistake. It is the natural consequence of solving harder and harder problems. This is what we call Essential Complexity — the irreducible kind that is baked into the problem itself.

A useful reframe

You can’t “delete” essential complexity any more than you can wish away the traffic lights a growing city needs. The goal isn’t a system with zero complexity — it’s a system whose complexity is all earned, every piece there for a reason you can name out loud.

2. The trap of uncontrolled complexity

If complexity is inevitable, why do systems still end up on the operating table for a full “tear it down and rebuild”? The answer is its evil twin: Accidental Complexity — the complexity we add by accident, that the problem never asked for.

Systems rarely collapse because they got big. They collapse when:

  • Temporary, good-enough-for-now solutions “fall asleep” and quietly wake up as the official architecture.
  • Abstraction layers stop hiding complexity and start being the complexity — a tax you pay on every change.
  • The effort to ship a feature goes wildly out of proportion: a few lines of code, but hours to understand where they even go.
  • The code is so entangled that one small change sets off a butterfly effect of cascading bugs.
A feature should cost only its essential complexity, but in a neglected system it actually costs the essential part plus a thick accidental layer on top. That extra layer is the part discipline can give back. TWO KINDS OF COMPLEXITY Essential the problem itself What it should cost Essential same as before Accidental self-inflicted tangle What it actually costs the part discipline gives back
Essential complexity is the floor you can’t go below. Accidental complexity is everything piled on top — and that pile is exactly where simplicity earns its keep.

When that pile gets tall enough, the system tips into a state of stagnation. It becomes a frightening black box: hard to understand, hard to debug, hard to extend, hard to onboard anyone into, and — most telling of all — everyone becomes afraid to change it.

This is the moment Technical Debt stops behaving like “debt” and starts behaving like compound interest. Every shortcut you didn’t pay down quietly charges you again, and the total slips past the team’s Cognitive Load — the amount of the system any human can actually hold in their head at once.

The “temporary” trap

Nothing is as permanent as a temporary fix that worked. The sticky note you left on Monday is still on the monitor a year later, and now three other things depend on it. Accidental complexity almost never arrives as a big bad decision — it accumulates one reasonable shortcut at a time.

3. Simplicity: the key to staying alive

When we talk about simplicity, the first thing to get straight is what it is not: simple is not crude. Simplicity isn’t “less code” or “less technology.” In system architecture, simplicity shows up as one thing above all — Clarity.

A system you’re afraid ofA system you understand
Complex business flows live only in one senior’s headComplex flows are drawn in models clear enough for many people to share
Behaviour depends on hidden assumptions and “you just have to know”Behaviour is predictable, written down, not folklore
When it breaks, nobody knows where to even start lookingWhen it breaks, you can localise it and know which part to watch first
Every engineer solves the same thing their own personal wayThere’s a standard way to do common things, by default
One small change ripples through the whole systemYou can change one part without a chain reaction
Nobody’s sure whether the DB, the App, or “somewhere” owns a ruleResponsibilities are bounded: the DB does the DB’s job, the App does the App’s

Clarity is what keeps a system simple enough to develop on confidently and reliably. And over time, it does something even more valuable: it dramatically lowers the cognitive load of running and maintaining the thing.

As a system grows, disciplined simplicity keeps its complexity below the team's cognitive-load limit and stays understandable, while unchecked complexity crosses that limit and becomes an unmaintainable black box. complexity time / growth → the team’s cognitive-load limit disciplined simplicity → stays understandable unchecked complexity ↗ crosses the line → stagnation
Two systems can be the same size. The one whose complexity stays under the line of what people can hold in their heads is the one that survives.

That is the real prize. When a system is clear, a newcomer — and even the “old hand” who built it but has long since forgotten the details — can look back and understand why it was designed this way, and then keep maintaining and evolving it. Instead of just learning, nervously, how to “make it run.”

The throughline

Only when humans truly master the system does the system get a chance to survive. People are the platform everything long-lasting is built on — not the framework, not the cloud, not the cleverest abstraction.

4. Simplicity is a hard choice

Making something complex is easy: add a layer, add a technology, and you’re done. Keeping something simple is brutally hard. It demands discipline and a constant willingness to weigh trade-offs:

When you’re tempted to…The seductive pathThe simple, disciplined path
Build for a need that might come“Let’s make it fully flexible now, just in case”YAGNI — build it when the need is real, not imagined
Reach for a shiny new toolAdopt the hype tech everyone’s tweeting aboutChoose the “boring” but proven tech you can still operate calmly at 3 a.m.
Make everything configurableInfinite knobs and options “for flexibility”One good default; add a knob only when a real case demands it

In short, choosing simplicity means daring to say “No” to features you don’t need yet, daring to sacrifice a little fake flexibility in exchange for real stability, and daring to pick the boring-but-effective option over the exciting-but-risky one.

Honestly? Reaching simplicity has never been easy — not even for me. Not every solution I ship arrives at its ideal, lean form on the first try. Caught between the hard limits of resources and time, the road to simplicity is always full of detours. But here’s how I’ve made peace with it: simplicity isn’t a final destination — it’s a compass. It’s the thing that keeps me coming back to refactor the system after every new lesson.

Try this in your next review

Before adding a layer, an option, or a dependency, ask one question out loud: “What real, present problem does this solve — and what does it cost the next person who has to understand it?” If you can’t answer the first half clearly, you’ve probably just found some accidental complexity before it was born.

Because in the lifetime of any system, the technology will age, the people will move on, the management will change, and the business requirements will shift. The only thing that stays behind is your architectural decisions — and their consequences.

5. From systems to life

The longer I do this work, the more I realise this way of thinking isn’t only true on the job. It’s true of my own life.

Modern life is itself a kind of distributed system: too much information, too many relationships, too much pressure, too many variables. That complexity is inevitable — we can’t escape it. And if we let ourselves get swept along, trying to “scale” ourselves to handle everything at once with no control, we tip into overload and burnout fast.

So there are moments when the wise move is to pause for a beat and think more carefully — or to accept starting over, so the next steps can be steadier and reach further.

“Simplicity is sustainable” isn’t just a working principle for me. It’s a philosophy of living I’m still learning to follow.

And to be clear, simple here doesn’t mean denying or running from a complex world. Simple is the ability to control complexity:

  • Knowing how to clear away the noise to focus on what is most essential.
  • Knowing how to refuse the short-term “satisfactions” that quietly cost you long-term value.
  • Only by holding on to simplicity do we keep the clarity and stamina to walk through the most complex stretches of a life — and from there, find a happiness that lasts.

Key takeaways

  • Complexity is the price of growth. As traffic, teams, and constraints grow, infrastructure, architecture, security, and process all get harder. That’s essential complexity — not a failure, but earned weight.
  • The killer is accidental complexity. Systems rarely die from being big; they die from “temporary” shortcuts that became permanent, abstractions that stopped helping, and tangled code where one change breaks five things.
  • Technical debt turns into compound interest. Once complexity passes the team’s cognitive-load limit, the system becomes a black box everyone’s afraid to touch.
  • Simple is not crude — simple is clarity. Predictable behaviour, clear boundaries, standard ways of doing things, and changes that stay local.
  • Staying simple is the harder choice. It takes discipline: YAGNI, boring-but-proven tech, one good default — and the courage to say “no.”
  • People are the real platform. Tech ages, people leave, requirements shift; what remains is your architectural decisions and their consequences. A system humans can master is one that gets to last.
  • The same lesson steadies a life. You can’t avoid life’s complexity, but you can control it — clear the noise, refuse cheap short-term wins, and keep enough clarity to go the distance.

You won’t get to choose whether complexity arrives — in your systems or in your days. It always does. But you do get to choose what you do with it: whether you let it pile up unexamined, or keep gently refactoring toward something clear enough to hand on. Complexity is what you pay to grow. Simplicity is what you invest so that what you built — and who you are — can still be standing long after the hype has moved on.

你觉得这篇文章如何?

常见问题

What’s the difference between essential and accidental complexity?
Essential complexity is baked into the problem itself — the irreducible difficulty you take on the moment you serve tens of millions of users, honour strict SLAs, or meet real security and compliance rules. You can’t delete it any more than a growing city can delete its need for traffic lights. Accidental complexity is the extra weight you add by accident: a “temporary” shortcut that became the architecture, an abstraction that no longer hides anything, code so entangled that one change breaks five things. The healthy goal isn’t zero complexity — it’s making sure all the complexity you carry is essential and earned, with no accidental pile on top. Simplicity is, very literally, the work of shrinking that accidental layer back down.
Does “keep it simple” mean avoiding new technology or shipping fewer features?
No — and that’s the most common misreading. Simple is not crude, and it doesn’t mean less code or less tech. In architecture, simple means clear: behaviour you can predict, boundaries you can point to, standard ways to do common things, and changes that stay local instead of rippling everywhere. You can adopt a powerful new technology and still be simple, as long as it earns its place and a normal engineer can reason about it. What simplicity rejects is complexity that nobody can name a reason for — flexibility “just in case,” options nobody uses, and clever magic that only its author understands.
How do I know my system has too much accidental complexity or technical debt?
Watch the gap between effort and outcome, and watch people’s fear. Warning signs: a few lines of code take hours just to find the right place to put them; a small change triggers a cascade of unrelated bugs; only one person understands a critical flow; onboarding a new engineer takes painfully long; and — the loudest signal — the team is quietly afraid to touch certain areas. When the system has grown past what any human can hold in their head (its cognitive-load limit), technical debt has crossed from “debt” into compound interest. That fear-to-change is your cue to start refactoring toward clarity, not to keep piling on.
Isn’t choosing “boring technology” just being afraid of innovation?
Not at all. Choosing boring, proven technology is a bet on stability and on the humans who have to operate the system — including you, at 3 a.m. when something breaks. Hype-driven tech can be genuinely better, but it also carries hidden costs: immature tooling, thin documentation, few people who can debug it, and surprises in production. The disciplined move isn’t to refuse all new tech; it’s to make new tech earn its risk against a clear, present need rather than adopting it because it’s trending. Innovation that you can operate calmly and hand to the next person is worth far more than novelty you’re afraid to touch.
How does this systems lesson apply to everyday, non-technical life?
Modern life behaves a lot like a distributed system: too much information, too many relationships, too much pressure, too many variables. That complexity is inevitable, and trying to “scale” yourself to handle all of it at once, without control, leads straight to overload and burnout. The same principle helps: clear away the noise to focus on what’s most essential, refuse short-term satisfactions that quietly cost you long-term value, and don’t be afraid to pause or even start over so your next steps are steadier. Simplicity in life isn’t escaping a complex world — it’s the ability to control complexity, and that control is what gives you the clarity and stamina to find a happiness that lasts.