In software engineering, complexity is often seen as a sign of competence.
Indeed, a simple system looks suspicious, while a complex system looks serious.
What is the value of a decade of success?
In my final year of engineering school, I built a CTF platform. At the time, no software like CTFd existed. Everything had to be built from scratch.
It took me a lot of thinking to arrive at an architecture that looks simple in hindsight: serve static files, generated on demand, to reduce the attack surface. Standard Unix services glued the components together. Low-level containers isolated services from one another.
The first year was a bit chaotic, as any first attempt tends to be. Improvement after improvement, I managed to stabilize the system. A few well-scoped micro-services came to structure the critical parts. For ten years, the whole thing ran like clockwork. No major incidents. No outage caused by a poorly understood service going down.
Yet every time I presented the architecture, I heard the same questions with a skeptical tone:
- Why isn’t there Kubernetes?
- Why use the filesystem that way?
- Why not a simple REST API?
Here is the answer to the question about the value of a decade of success: I never managed to convince anyone. A decade of success was not enough. When I left, my work was thrown away.
The new solution is built on CTFd. In other words, a generic product that requires more computing power, offers fewer features, displays an austere interface, and runs on Kubernetes, of course.
Since then, I keep asking myself the question: why does the software industry value complexity over simplicity?
Complexity has become the default reaction
Today, faced with a technical difficulty, the reaction is almost always the same: add more. More machines, more software layers, more cloud, more abstractions.
CPU at 100%? Add more CPU.
The system is slow? Move everything to the cloud.
The architecture doesn’t suit anyone? Switch to microservices.
According to my observations, these decisions are often made before anyone has understood the problem. When a system becomes slow, the instinctive reaction is to add servers and resources, whereas an engineer’s reaction should be to ask “why?”.
Saying “it’s slow” is not a diagnosis. It’s an admission of the loss of control over your system.
A simple system is a mastered system
The most destructive phrase that now sets off alarm bells for me — one I encourage you to treat as a red flag whenever you hear it — is: “let’s keep it simple!”
Why?
Because whoever says it often confuses “simple” with “simplistic.” In general, they’re not from the field.
To be clear: I’m not advocating for a lack of technology. A simple system is not a rudimentary system. It’s a system where every element has a reason to exist.
A mastered system is one where:
- you know why the processor is saturated;
- you know why to add a network card;
- you know why a faster disk is necessary;
- you understand the details of costs, not just “10% less than last month” at random.
Does that seem obvious? Yet I see the opposite in many companies. Starting with cloud provider interfaces. They’re supposed to represent the state of the art, yet they are frustratingly slow.
When the providers selling you performance are not themselves performant, that should trigger a signal in our minds.
The paradox of professionalism
In many organizations, complexity has become a marker of seriousness. Does that resonate?
I experienced this firsthand. My Unix architecture, my static files, my lightweight micro-services: all of it was perceived as tinkering. While other event organizers struggled with their servers and the CTFd software, my system ran like clockwork.
Yet from the outside, “engineer’s tinkering” that works for 10 years can’t have been that complicated!
On the other hand, something built on Kubernetes, Kafka, and a service mesh will immediately be seen as “a real architecture.” Even if those who truly understand it are rare.
A simple system looks amateur. A complex system looks professional.
In my opinion, this phenomenon has several roots. I’ve identified several, and there may be more. There is mimicry: copying Netflix and Google architectures without considering their constraints. It’s the equivalent of building a three-Michelin-star restaurant kitchen to cook pasta.
There is fear of blame: if the system breaks and you’re using “industry standards,” no one will be pointed at.
There is the résumé effect: working with Kubernetes and Kafka boosts a career. Postgres and a monolith, much less so.
There is finally the abundance of cheap resources. Why save on storage when disk prices keep falling? Why save on RAM when adding more costs just a few dozen euros? Why save on computing power when it’s available on demand? Yes, keeping things simple requires time from skilled people — who are rare and expensive resources.
The custom doesn’t disappear — it just moves
When my successors replaced my system with the CTFd software in the name of standardization, the non-standard didn’t disappear. It changed location.
Sure, the core of the system became generic software. But everything that completes it — the orchestration, the scripts, the duct tape, the adaptations — became the new custom.
Guess what? That code is often worse: less coherent, more scattered, less thoughtfully designed as a whole. You replace a system conceived as a whole with an accumulation of workaround layers.
This example is common with modern architectures. You don’t eliminate “complexity” — you move it to less visible, less controlled places. Worse, you have to constantly keep up with the “standard” software’s evolution: adapting your customizations, fighting structural changes, praying for the goodwill of others.
The cloud as a lazy solution
As a logical consequence of this trend, the cloud is today the primary lazy solution. Not because it’s useless — it’s legitimate for certain use cases — but because it allows you to mask problems instead of solving them.
Faced with a technical problem, I see two paths.
The first: measure, understand, analyze.
The second: add resources, pile on abstractions, move the problem elsewhere.
Why has this second path become the norm?
Adding machines is often easier than understanding a program.
It seems to me that the laziness lies here. Not in choosing simple hosting or a lightweight architecture, but in the unwillingness to understand how the whole thing works and what is happening inside the system.
Minimalism is not the absence of complexity
Some systems are complex, and that’s perfectly fine. Google’s search engine, Criteo’s real-time ad auctions: these are surgical systems where every component is justified, sometimes multiple times over.
That is exactly what minimalism in engineering means: keeping only the complexity that is indispensable.
Complexity is not a problem. Unnecessary complexity is.
A company just starting out, with a few thousand users and a team of five developers, does not face the same constraints as Netflix. Yet many deploy the same architectures.
AI makes this problem even more urgent
Today, artificial intelligence tools can produce code and architectures at an unprecedented pace. An entire system can be generated in a matter of hours. As a result, producing complexity has never been easier.
In this context, the skill is shifting. It is no longer knowing how to code — it becomes knowing how to contain the complexity that gets produced. It is about forcing yourself to think, rather than rushing headlong toward the first proposed solution.
Artificial intelligence is a formidable tool for quickly pivoting toward alternative solutions or for exploring different approaches. But you still need the perspective required to choose the right one.
Machines are learning to produce complexity. Engineers must learn to contain it.
The role of the engineer
An engineer is not just a code producer. Their role is to understand systems, master resources and costs, and eliminate unnecessary complexity.
A good engineer often does less. A well-designed system looks almost too simple, and that is often why it goes unrecognized: success erases the perception of difficulty.
Today, the rarest skill in software is not writing code — it’s knowing how to avoid writing it.
Simplicity is a discipline
I don’t confuse simplicity with an absence of technology. Let’s say it is the result of demanding engineering work. This demanding work requires measurement, observation, reflection, and sometimes resisting the social pressure that pushes toward complexity.
In a world where people and machines alike can generate complex systems, the engineer’s responsibility is to keep those systems understandable.
Simplicity is not amateurism. It is what engineering produces when it matures.