Every software engineer dreams of building something vast. A platform. An ecosystem. A cathedral.
You’ve probably done this yourself. Started with a whiteboard. Drew tidy boxes and arrows, layers stacked like geological strata. The design looked elegant, complete. Every module had its place. Every API had its purpose. The sort of diagram that wins nods in meetings.
And then, when you tried to build it, nothing happened. Not a dramatic collapse—just a machine that never quite started. Always almost running, never alive.
I used to think this was a failure of execution. Bad planning, maybe. Insufficient resources. But after watching it happen dozens of times—to me, to brilliant engineers, to well-funded teams—I realized something else was going on.
The problem wasn’t the execution. It was the approach.
There’s this law in systems theory called Gall’s Law. It says:
A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system.
Most people nod when they hear this and then ignore it. But if you actually follow it, it changes everything about how you build.
Here’s what I think is really happening.
When you design a complex system from scratch, you’re trying to solve every problem at once. You’re building an ecosystem in your head and hoping it will work when implemented. But you’re missing the one thing that actually matters: feedback from reality.
Real systems have quirks you can’t anticipate. Load patterns that don’t match your assumptions. User behaviors that break your elegant abstractions. Edge cases that reveal fundamental flaws in your design.
You can’t discover these from a design document. You can only discover them by building something and watching what breaks.
But there’s a deeper issue. Complexity isn’t something you assemble like Lego blocks. It’s something that grows, like a tree. And trees don’t start as fully-formed giants. They start as seeds.
Look at the systems we admire. Google wasn’t conceived as a planetary-scale infrastructure project. It was two graduate students with a better ranking algorithm running on a single server under a desk. Facebook wasn’t designed as a global social graph. It was a directory for one college campus. Netflix didn’t begin as a streaming service. It was a website for mailing DVDs.
These systems became complex because they survived long enough to grow. Their creators didn’t scale to hundreds of millions of users overnight. They added one feature, one server, one team at a time. Growth guided by real constraints, real feedback, real problems.
This is what Gall’s Law predicts: systems that work start simple.
So why don’t more people do this?
Because it feels wrong. Starting small feels like aiming low. It’s embarrassing to build a toy when your vision is a city. Engineers are trained to think in abstractions, to design elegant architectures. There’s pride in getting it right from the beginning.
But elegance emerges from iteration, not intention. The first version’s job isn’t to be elegant. It’s to exist. To survive reality long enough to learn what the second version should be.
This is hard for engineers to accept because we’re used to problems with right answers. But system design isn’t like algorithm design. There is no right answer until you have real users and real data. Everything before that is just educated guessing.
I’ve seen this play out over and over. Teams that spend months building sophisticated architectures, only to discover their fundamental assumptions were wrong. Meanwhile, the team that shipped a scrappy prototype is already on version three, learning from real usage patterns and iterating toward something that actually works.
It’s not that careful design doesn’t matter. It’s that the most important design decisions can only be made with real information. And the only way to get real information is to build something real, however small.
The fastest way to build something big is to stop trying to build something big. Build something small that works. Then grow it.
This approach has a paradoxical property: it’s both slower and faster than the alternative. Slower because you’re not trying to solve everything at once. Faster because you’re not spending months building the wrong thing.
The teams that understand this have an enormous advantage. While others are stuck in design review meetings, they’re shipping and learning. By the time the grand architecture is ready, they’ve captured the market.
Every complex system you admire was once a crude little program that barely worked. The difference is that it survived long enough to evolve. Evolution, not design, created the complexity we see.
If you want to build a cathedral, don’t start with cathedral blueprints. Start with a hut. Make it livable. Add a room when you need it. Then another floor. Then a tower. One working piece at a time.
Because here’s what Gall’s Law is really saying: complex systems work only when they evolve from simpler systems that work. It’s not just advice about software. It’s a fact about reality.
Most engineers resist this because it requires giving up control. You can’t plan the whole journey from the beginning. You have to be willing to discover it as you go.
But that’s not giving up control. That’s trading the illusion of control for something more valuable: a system that actually works.
And in the end, that’s the only kind of system worth building.