

- Description
- Denver International Airport
- Source
- author not stated · original page
- Licence
- PD Public domain
Over-engineering
A ten-layer solution looks more professional than a two-layer solution, and that's exactly what makes it dangerous.
In brief
- What: we design bigger, more general, and more sophisticated than the need requires.
- Why: complexity is seen as seriousness, we want to “be ready for what comes next,” and the designer likes their own work.
- Detect: abstractions without a second use, options nobody asked for, a design that takes longer to explain than to build.
- Avoid: start from the current need, generalize only on the second or third real use, have the simplest solution defended in review.
Definition#
Over-engineering (over-engineering) means designing a solution that's more complex than the problem requires: too many layers, too many parameters, too much generality, too much precision. It's not a cognitive bias in the strict sense, but the result of a set of well-described tendencies: we treat sophistication as a sign of quality, overestimate future needs, and become attached to what we've imagined.
The best-known case is the second-system effect, described by Frederick Brooks in The Mythical Man-Month (1975): the designer delivering their second system pours into it all the ideas and features they had to leave out the first time, making it, according to Brooks, “the most dangerous system” they will design. The methodological countermeasure is called YAGNI (You Aren't Gonna Need It, from Extreme Programming): don't write what you don't need today.
Not every complex design is waste: some problems are hard (security, volume, regulations). The flaw appears when complexity does not meet any verifiable requirement, or answers a future requirement that no one has confirmed.
How it works#
Several tendencies combine:
- Sophistication as proof of seriousness: a multi-layer architecture, a rules engine, or an in-house framework impresses in review; a twenty-line solution seems “lightweight.”
- Optimism about the future: we imagine needs that will come later (other clients, other databases, other languages) and build for them, without measuring the cost of carrying that generality today, or the likelihood that those needs will actually materialize.
- The designer's enjoyment and image: an interesting problem is more motivating than a mundane one; a clever solution enhances its author. The The IKEA effect then reinforces attachment.
- Asymmetry of criticism: “it wasn't flexible enough” is said in meetings; “it's too complicated” gets said only later, when the team has already paid for it.
Complexity has a simple calculable property: the number of possible relationships between components grows much faster than the number of components. Between n components, there are up to n(n − 1) / 2 pairs that can influence each other.
Possible relationships between components
Loading the chart…
View the data
| Possible pairs | |
|---|---|
| 4 components | 6 |
| 8 components | 28 |
| 16 components | 120 |
| 32 components | 496 |
Where you encounter it#
In project management#
- Architecture: microservices, event bus, or workflow engine for an application used by forty people; a “database-agnostic” design even though the product will only ever use one.
- Premature generalization: an interface, a factory, and three inheritance levels for a case that has only one implementation.
- Excessive parameterization: everything becomes configurable, until configuration itself is a programming language that's harder to test than code.
- Imagined non-functional requirements: “it needs to handle ten times the current load” without a growth scenario or measurement.
- Tooling: a delivery pipeline and environments sized for a team ten times larger.
In management#
- Process: a five-level approval workflow for a decision worth a few hundred dollars; a four-page meeting-notes template for a fifteen-minute meeting.
- Organization: a forty-criteria evaluation grid, or a skills matrix that takes longer to maintain than to use.
- Methodological framework: adopting the most complete version of an agile or quality framework “to be serious,” when the team needs three practices.
- Reporting: a dashboard with thirty indicators, four of which are actually consulted.
A semantic model with dozens of intermediate tables, measures derived from measures, and hybrid schemas for cases that don't exist yet adds cost to every change. Measure the value of a generalization by the number of reports that actually use it.
Famous cases#
The Denver airport baggage system 1993-1995 (abandoned in 2005)#
Biases at play: over-engineering, optimism about complexity, escalation of commitment.
What happened. The new Denver International Airport was supposed to have a fully automated baggage handling system based on autonomous rail carts covering all terminals. The overall complexity (control software, synchronization of thousands of carts, hardware) proved so high that the system failed certification testing: bags were misloaded, misrouted, or fell off carts. The opening, first delayed by a few weeks, was ultimately delayed by more than a year. In 1994, the city decided to build a conventional system in parallel, estimated by the GAO at about $51M, and the airport opened on February 28, 1995. The automated system ultimately operated only partially (for United Airlines) before being abandoned in 2005.
What this illustrates
A system that is more ambitious than necessary doesn't just miss its goals: it blocks everything that depends on it. The fallback solution, conventional and more modest, was enough to open. The lesson is not “never automate,” but: what is complex must be validated step by step, and a simple plan B must exist before the schedule depends on plan A.
The second-system effect (Brooks) 1975#
Biases at play: over-engineering, overconfidence of the experienced designer.
What Brooks observes. In The Mythical Man-Month, based on his experience leading development of IBM's OS/360 operating system, Frederick Brooks devotes a chapter to the “second system.” A designer's first system is cautious: they know what they don't know, and they keep it short. The second is the most dangerous: it contains all the features and tricks the architect had to set aside the first time, and they indulge in adding them all. Brooks draws a discipline from this: the designer must assign each feature a maximum cost (in memory, in runtime), and the project manager must require an architect with at least two systems already under their belt, while remaining personally alert to these temptations.
What this illustrates
It's not inexperience that produces over-design, but confidence after a first success. In a team, an architect's “second product,” the “v2” of a tool, or the redesign of a successful system are moments when vigilance must be doubled: budget set in advance, scope defended, independent review.
FizzBuzz Enterprise Edition humorous project, public repository#
The FizzBuzzEnterpriseEdition repository (a collective project published on GitHub under the name EnterpriseQualityCoding) solves the FizzBuzz exercise, which fits in a few lines, with dozens of classes: factories, strategies, visitors, dependency injectors. It's a parody, but its patterns are all recognizable in real projects. It serves as a practical test: if your solution to a problem the size of an interview exercise looks like this, you may have a problem.
Detection signals#
- An abstraction has only one implementation and no second one is planned by the project deadline.
- “Just in case…,” “for later,” “this will be useful when we have…” in justifications.
- It takes more time to explain the design than to build it.
- Newcomers need weeks before they can make a simple change.
- Options, parameters, or fields that nobody uses since production release.
- The solution consumes more platform resources (CPU, licenses, administrators) than the problem it solves.
- A one-line change requires touching five files.
Avoidance reflexes#
- Start from a verified need. For each design capability, ask: who requested it, for when, and with what evidence? A need without a requester is a hypothesis.
- Apply YAGNI. Don’t build what you don’t need today, unless adding it later would clearly cost much more than now (a rare case, to be justified).
- Generalize on the second or third real use, not the first. Two cases sketch an abstraction poorly; three cases sketch it better.
- Have someone defend the simplest solution. In a design review, someone’s role is to explain why a simpler version would not be enough.
- Quantify complexity. For each added layer: development, testing, operations, and training cost. Show it next to the expected benefit.
- Deliver small, first. A first minimal version in production teaches more than ten weeks of design. This is Gall’s principle: a complex system that works is always evolved from a simple system that worked.
- Plan a simple plan B before committing to an ambitious solution, as in the Denver case.
- Clean up. Remove what is not used: an option never enabled in production for a year is a candidate for removal.
With AI: detect, fix, mitigate#
AI is a good design challenger: it can propose the minimal version and list unused parts. But code assistants have the opposite tendency: they readily produce “standard” layers, interfaces, and templates even when the problem does not call for them. Without instructions for restraint, AI can itself create over-engineering, and quickly.
Detect#
- Spot in the code abstractions with a single implementation, never-used parameters, and layers that only delegate.
- Compare a design to the need description and list what does not address it.
- Estimate the ratio between the number of concepts in the solution and in the problem.
Fix#
- Propose a minimal version that covers confirmed requirements.
- Write the rationale “why the simple version is not enough,” or determine that no such rationale exists.
- Describe the trigger conditions for generalization (“at the third client, we abstract”).
Mitigate#
- Have AI play simplicity advocate in every design review.
- Set a restraint rule in your code assistant instructions (no layer without a second use).
- Have it estimate maintenance cost for each option before accepting it.
Prompts to integrate into your practices#
1. Simple version advocate. To use in design review, on an architecture file.
Here is the proposed design for [feature / system]: [description].
Here are the confirmed requirements (with their source): [list].
Play the role of simplicity advocate. 1) Propose the simplest version that satisfies the confirmed requirements, describing it in fewer than fifteen lines. 2) For each element of the proposed design that is not in this version, say which requirement it addresses, or indicate that it addresses no confirmed requirement. 3) State what would become difficult if we chose the simple version, without exaggerating.
Do not try to validate the initial design.
2. Module complexity audit. On a code excerpt or a class list, after anonymization.
Analyze this code: [code or component list].
Identify: interfaces or abstract classes that have only one implementation, parameters or options never used in the provided calls, layers that only pass through a call, and cases where the number of files touched for a simple change seems excessive.
For each point, indicate your confidence (certain, likely, to be checked) and what would need to be checked in the rest of the repository before deleting anything.
How to integrate them#
- Before the review: prompt 1 is run by the author themself, who answers objections before the meeting.
- Day to day: put a restraint instruction in your code assistant configuration file, and review its proposals like those of an overzealous junior.
- In retrospectives: prompt 2 feeds a point titled “what we built that nobody uses.”
Precautions#
- AI can judge something unnecessary when it addresses a requirement it does not know about (regulation, operational constraint). Give it the requirements; do not let it decide by itself what to remove.
- The proposed “simple” version may ignore edge cases: test it.
- Do not send confidential code to an unauthorized tool.
Limits#
- Under-engineering also exists: a solution that is too minimal is expensive to rework when the need is real and foreseeable (security, compliance, personal data). The point is not to reject all anticipation, but to justify it.
- Over-engineering is not always a bias: it can result from contractual requirements, an imposed specification, or a lack of time to make it simpler (“I did not have time to write a shorter text”).
- There is no objective measure of the “right” complexity: judgment remains contextual, and two experts can honestly disagree.
- The Denver case figures come from the October 1994 GAO report; later assessments vary depending on what is counted.
Sources and verification#
- Brooks, F. P. (1975), The Mythical Man-Month: Essays on Software Engineering, Addison-Wesley (anniversary edition 1995) — chapter “The Second-System Effect.”
- U.S. General Accounting Office (October 1994), New Denver Airport: Impact of the Delayed Baggage System, RCED-95-35BR — dates, costs, and cost of delay.
- Gall, J. (1975), General Systemantics: An Essay on How Systems Work, and Especially How They Fail (reissued in 1977 under the title Systemantics: How Systems Work and Especially How They Fail) — the statement behind “Gall’s law.”
- Fowler, M., “Yagni,” martinfowler.com — origin and limits of the principle.
- Beck, K. (1999), Extreme Programming Explained: Embrace Change, Addison-Wesley.
- Knuth, D. E. (1974), “Structured Programming with go to Statements,” ACM Computing Surveys — the warning about premature optimization.
- EnterpriseQualityCoding, FizzBuzzEnterpriseEdition (GitHub repository) — parody.
See also#
Related biases#
Variants or cousins: not to be confused.
Counterweights and related reflexes#
What neutralises it.
- YAGNI et la solution la plus simple qui fonctionne (concept or method, no page)
- Les revues de conception contradictoires (concept or method, no page)
- The devil's advocate
- The pre-mortem