← All essays

Simplicity is not easy

Anyone can add complexity. Simplicity requires understanding what you can leave out.

"If the definition of a language requires fat manuals of hundreds of pages, this must be taken as a sure symptom of inadequacy."

Niklaus Wirth wrote this in 1971. He was describing what makes a good programming language. His answer: a small number of concepts that can be freely combined. Not more features. Fewer. Better.

Wirth created Pascal, the language I've been using for thirty years. He believed that complexity was a warning sign, not a badge of honor. Fifty years later, the React documentation runs to over a thousand pages. The TypeScript handbook is longer than most novels. We've moved in the opposite direction.

The paradox

When Wirth presented Oberon, his final programming language, he put a slide on the projector. It showed four lines: the new features they had added compared to Modula-2. Then he uncovered the rest of the slide. A dozen more lines. "And these are the features that we removed," he said, with a triumphant smile.

Adding features is easy. Any developer can stack functionality. Ship something, add more, ship again. The codebase grows. The documentation grows. The cognitive load grows.

But knowing what to remove requires something different. You have to understand the problem completely. Wirth removed the LOOP, EXIT, and WITH statements from later versions of Oberon. Not because he didn't understand control flow. Because he understood it so well that he knew these constructs weren't essential.

Why we choose complexity

Complexity feels like work. If your solution is hard to understand, it seems like you've solved something hard. Simple code feels almost like cheating. "Is this all?"

We confuse "difficult to understand" with "good." We mistake verbosity for thoroughness. We add layers because layers look impressive.

Wirth had a word for this: inadequacy. When something requires extensive explanation, it's not sophisticated. It's insufficient.

Code that explains itself

Wirth used to send code back to his students when it had too many comments. Not because he didn't value documentation. Because "the programs were thus not clear enough."

Comments are often a symptom, not a solution. If your code needs explanation, the code isn't clear enough. The best code reads like a well-written sentence. Not because there's no complexity, but because the complexity has been worked through and resolved.

This doesn't mean clever tricks or cryptic one-liners. It means choosing names that communicate. Structuring logic so it flows. Breaking things apart until each piece does one thing well.

The courage to say no

Every feature is a promise. To users, to future developers, to yourself. Every feature is also technical debt. Code that must be maintained, tested, documented, explained.

The hardest decision in software isn't what to add. It's what to leave out.

Wirth knew this. He didn't want to include the goto statement in Pascal. He added it under pressure from Algol programmers who couldn't imagine working without it. Years later, he called it one of his biggest mistakes. He had added something he knew wasn't necessary, and the language was worse for it.

The best products aren't the ones with the most features. They're the ones where every feature matters.

A small example

Consider assignment. In most languages, you write x = x + 1. Wirth found this absurd. The equals sign has meant equality for hundreds of years. How can x equal x plus one? It can't. That's nonsense.

So Pascal uses x := x + 1. The colon-equals means "becomes." X becomes x plus one. One symbol. Deliberate. Clear.

This seems like a tiny thing. It is a tiny thing. But it shows what thoughtful design looks like. Someone stopped to ask: does this make sense? And changed it.

The test

How do you know if something is simple enough?

Can you explain it in three sentences? Can you walk a new colleague through the architecture in an hour? Does the core fit in your head?

The description of Oberon fit in sixteen pages. The entire language. Not just the syntax, but the semantics, the type system, the module structure. Sixteen pages.

If your system can't be summarized briefly, it might not be well understood. By you or anyone else.

Where you end up

We assume beginners write simple code and experts write complex code. It's the opposite.

Beginners write complex code because they don't know what they can leave out. They add safety nets, redundant checks, layers of abstraction for problems that don't exist. They're not sure what's essential, so they keep everything.

Experts write simple code because they know exactly what matters. They've seen enough systems to recognize what's necessary and what's noise. They have the confidence to delete.

Wirth left an indelible impression as someone who elevated simplicity and turned it into an art. Not simplicity as laziness. Simplicity as the result of deep understanding.

Simplicity is not where you start. It's where you end up.

Marco Geuze

Marco Geuze

Building software for 30+ years. Founder of GDK Software.

More about me →