Part 1. Overengineering: definition, stats, notable cases
There are timeless questions in the world: which came first – the chicken or the egg, where does space end, and why do teams make even simple tech problems three times more complex than needed? Figuratively speaking, instead of building a regular highway bridge over a river in Africa, they construct a Brooklyn Bridge with restaurants. No one remembers why anymore, but most importantly – no one considered that the metal’s heat resistance needs are different from New York’s.
It’s not just startups that fell into this trap – even giants did in the early days of e-solutions. Businesses don’t like to recall such things, and often, it’s a trade secret. But it’s known that in the 2000s, BMW released a complex iDrive system that made the car almost impossible to use without instructions. And the FBI, due to uncontrolled development, “buried” its most ambitious database, and after “burning through” 170 million dollars, had to restart the project from scratch.
In general, such mistakes are expensive. So expensive that NASA listed overengineering – both in hardware and software – in their top 10 major threats to projects.
And what about the stats?
Not many relevant studies are out there. But last decade’s data, which people still quote today, shows that almost a third of banking software features are overengineered. More recent data backs this up: Pendo’s 2019 report shows up to 80% of features in average software were rarely or never used. And public companies blew nearly 30 billion dollars developing them.
But! Here’s the thing – not everyone in tech sees this as a problem.
Overengineering is a “holy war” topic even within companies. Some managers fight it, others don’t acknowledge it, and some even think it can be useful.
The international expert community doesn’t have a unified opinion either. It seems they tend to see it as harmful but define it differently, what exactly counts as overengineering, where its boundaries are, and how to work with it.
For example, the well-known theorist Martin Fowler writes: “There is a notion that design is something you can trade off for greater speed. If it were the case that putting effort into design reduced the effectiveness of programming, I would be against it.”
In general, Fowler is for compromises. He thinks that both overengineering and tech debt are sometimes needed for business, although you need to consider the specific situation.
The pioneer of continuous delivery, Brit Dave Farley, sees a big difference between “quality design” that leaves room for change and “overengineering that tries to precisely predict” the future. In other words, between “building a house with the possibility to add rooms” and “building 10 extensions from the start” that may not even be needed.
Meanwhile, American Robert Martin “cuts straight” in Jobs’ style: “Simplicity is the ultimate sophistication.” At the same time, he insists on architectural perfection as he sees it: clean code, framework independence, modularity, and SOLID – even if it’s more expensive and complex at the start. His belief is that good design is laid down from the beginning. And pays off in the long run.
Roughly speaking, the Brits Fowler and Farley here are flexible pragmatists, not fitting the stereotype of “over-regulated” Europeans. While Uncle Bob is more like the sheriff of strict US corporate rules from the 90s.
Though Fowler was making his career back in “pre-startup” America, and Martin, seemingly an “old school engineer,” stood at the origins of Agile in the 2000s.
Well, even gurus contradict themselves sometimes. That’s why today’s topic about relativity is quite something, and from us – we’ll do what we can – different opinions. So, draw your own conclusions, friends.
By the way, speaking of the Old World. We’re recording our podcast right there, so we’ve collected the opinions of some European practitioners.
What do they consider overengineering?
The first comment comes from Maxim Leykin, Head of Engineering at the Estonian company Bamboo Agile.
“I wouldn’t say there are exact criteria, but at least there are markers that can make you think about potential overengineering. The first marker is an attempt to ‘reinvent the wheel.’
For example, if a client asks to develop a new marketplace mobile solution or hotel booking system, we should assume there must be many open-source frameworks that can be easily and quickly customized per client requirements, and the overall effort will be 10 times less than developing it from scratch.
Another marker is an estimate given by the developer for the task. If it seems enormously big, there’s a good chance that the task is overestimated due to an overengineering approach, and this is where a solution architect or engineering manager should step in effectively.
And the third marker is ‘buzzword magic.’ There are certain buzzwords nowadays, like ‘microservice architecture,’ ‘AI-based solution,’ ‘voice assistance,’ and sometimes a willingness to use these trendy approaches can also lead to overengineering.”
Maxim Leykin, Head of Engineering at Bamboo Agile
Maxim’s colleague, CEO of Bamboo Agile Sergey Zubovich, approaches the question differently, seemingly not fully acknowledging either overengineering or “excessive simplicity.”
“I appreciate the point about overengineering, where solutions become unnecessarily complex. However, my recent experience has made me rethink this. In many cases, I would prefer to call this approach ‘not-an-engineering’ rather than ‘overengineering.’
What makes a great engineer? Whether in tech or traditional fields, the ability to build a solution that corresponds to functional, budget, and time requirements, the ability to find the right balance between competing factors, and in an ideal world, the ability to ensure that their solution will serve for hundreds of years with proper maintenance.
It is impossible to have all the indicators turned up to a maximum. That is why following this approach leads to a long list of trade-offs. Those who try to include everything in their solution and do it right away without aligning with reality are probably neither ‘engineers’ nor ‘over-engineers.”
Sergey Zubovich, CEO at Bamboo Agile
Marten Sytema, CTO and founder of the Dutch service Catermonkey, suggested in the Frashcode podcast to separate overengineering, which he sees as excess engineering solutions, from perfectionism. Sytema thinks the latter can be even riskier, for example, when it comes to deadlines.
“You always have like perfectionism, maybe that’s the word – overengineering is something else is perfectionism. But ‘perfecting things’ is not always like ‘perfect,’ because then, often, the time scale is ignored in perfecting something. And by not meeting time goals, because you’re perfecting, technically, you’re failing in a way.”
Marten Sytema, CTO, the founder of Catermonkey
A non-European but also well-known developer, Eliran Turgeman, explains overengineering from the “grassroots” – as a choice to code “too future-proof” and “not making it future-proof at all.” In his article, the Israeli author gives the example of customizing shopping baskets, where special-purpose code can quickly become confusing, but code that is too general can quickly complicate things. We’ll discuss what Turgeman suggests as a way out a bit later.
Part 2. Is overengineering always a bad thing?
So, we seem to have figured out what overengineering is about.
But is it really such a problem? Should we fight it, or can we, for example, use it?
In 2019, a team of researchers from several countries – USA, Britain, Sweden, and Italy – published a report, “Software Development Beyond Customer Requirements.” And, you know, they didn’t mention the phenomenon was definitely harmful. Rather, it has both pros and cons. Like, on the one hand, overengineering provides flexibility in the face of uncertainty, on the other – it quickly becomes irrational. And so on.
The main idea here – overengineering can theoretically be managed.
But that wasn’t the end of the story. Three years later, one of the authors, Italian researcher Giacomo Marzi, released a new report. This time, he was much more critical of overfeaturing, which he linked, among other things, to IT overengineering. Citing industry examples, he called it a “pathology” that leads to feature fatigue, delays, and overall quality issues.
Therefore, according to Marzi, the right strategy for overengineering is to fight it.
By the way, in this work, the Italian researcher relied on a greater number of parameters, including market data, so, in essence, the report is broader than his and his colleagues’ earlier study.
Okay, that’s what theorists think. What do practitioners say?
Some believe much depends on the stage of a company’s development. For example, CodeScene founder and Your Code as a Crime Scene author Adam Tornhill argues that, in the early stages, overengineering might not be a problem at all. Instead, the real issue could be a lack of it. And brings up an example from his own experience.
“In the first days of CodeScene, we decided that we wanted to be very simple to get started with the tool. I don’t want you as a potential user to start to install databases left and right, so we choose an embedded database.
But then we found later, as we scaled up and start to take on large enterprise accounts, that we simply couldn’t meet our needs with an embedded database because it’s really hard to do a backup of it. It’s really hard to do a restore of it and all that. We kind of have to rethink that space and make sure we could support external databases that you connect to and all of that.”
Adam Tornhill, author, the founder of CodeScene
According to Tornhill’s experience, the solution chosen today almost always looks poorly thought out two years later. And this is more distinctly noticeable in startups.
Maxim Leykin from Bamboo Agile thinks similarly and considers under-engineering even more dangerous than over-engineering – regardless of the company’s size. He provides an example from a project where his team had to decide how to technically notify mobile clients about new events from the backend.
“There were three options: long polling, web sockets, and push notifications. We went with the third one since it seemed like the simplest and fastest approach. Later, we regretted it when we realized that push notification delivery on mobile platforms wasn’t stable enough. Plus, iOS had limitations on receiving notifications when the app was running in the background. So we had to switch to web sockets and spend additional time on implementation while the time spent previously on configuring push notifications was wasted.”
Maxim Leykin, Head of Engineering at Bamboo Agile
Here’s another example where over-engineering was rather appropriate. Maxim recalled developing an Android app for configuring hydraulic machines via NFC.
“Initially, they asked for an extremely simple solution that would support three particular models of machines, and all parameters had to be set manually in the app. Instead, we proposed developing some kind of web interface to be able to prepare configuration files with machine parameters using a Graphical User Interface, validate them automatically, and only then upload them to the mobile app. Our arguments focused on the versatility and reliability of the solution, whereas the client just wanted to keep the project budget as low as possible. After quite lengthy negotiations, they accepted our proposal, and about a year later, they got five new machine models with different configuration parameters. Thanks to our pre-validated scheme, we saved much of their and our time to accommodate new hardware.”
Maxim Leykin, Head of Engineering at Bamboo Agile
According to Maxim, this solution was inspired by a simple thought: he imagined a heavy hydraulic press falling due to a typo on a smartphone.
But such cases are rather an exception. Therefore, he usually doesn’t consider himself a fan of complications.
Maxim’s colleague from Bamboo Agile, Sergey Zubovich, is tougher in his assessments. Throughout his entire practice, he has not encountered a case where overengineering, or, as he says, not-an-engineering, has led to anything other than budget exhaustion, deadlines being missed, maintenance difficulties. Or all of the above at once.
Part 3. Combating overengineering: strategies from industry leaders and experts
Okay, if we agree that over-engineering is still a problem – what are its causes, and how do we fight it?
Remember the 2019 study? Its authors came to an interesting conclusion: overengineering is more of a psychological phenomenon than a technical one. And directly depends on the personality types of the engineers.
After surveying 307 specialists, they identified three components of predisposition to overcomplication: cognitive, emotional, and behavioral.
Developers with an “intuitive” thinking style tend to keep adding new features to a product, relying on subjective judgment. In reality, the features might be interesting but are often barely used.
“Rationalists,” on the other hand, gravitate toward logical and universal solutions – and get carried away trying to “please everyone” or account for every possible scenario.
Personal emotional attachment to a project amplifies both types of excess. Experience, however, works differently: for some, it reinforces reliance on outdated practices, while for others, it improves risk assessment based on past mistakes.
The survey authors advise considering these characteristics when assembling development teams. And Giacomo Marzi, having explored the issue further in 2022, formulated more precise recommendations. They fall into three categories: managerial, process-related, and technical.
As managerial recommendations, Marzi suggested:
- avoiding uncontrolled expansion of both the project and the product;
- managing requirements flexibly while ensuring their validity.
To achieve this, he recommended integrating into processes:
- both Agile and Stage Gate methodologies with a focus on cross-functionality;
- clear criteria for core MVP principles;
- strict task prioritization.
And on the technical side:
- testing prototypes at early stages.
- following overall minimalism in development.
- thoroughly analyzing each feature before implementation.
Essentially, Marzi’s key approach is a balance between flexibility and control, with a focus only on the essentials.
Other theorists argue that not only methodology and processes matter but also team structure.
In 1967, programmer Melvin Conway formulated a law stating that companies design systems mirroring their communication structures. Simply put, the more complex and distributed the team, the more complex and fragmented the project.
Can it be challenged? Of course – the law is quite old.
On the other hand, in 2015, MIT and Harvard Business School published a study confirming its relevance.
And industry leaders seem to be taking it into account. Not long ago, Jeff Bezos’ approach to team structuring at Amazon was widely discussed.
“We try to create teams that are not larger than can be fed with two pizzas. We call that ‘the two pizzas team rule.”
Jeff Bezos, entrepreneur, the founder of Amazon
It must be said, the rule has faced plenty of criticism. Its core idea is that truly effective decisions come from teams small enough to be fed with two pizzas. Still, former Amazon seniors Colin Bryar and Bill Carr write in their book that, while the approach has, in their view, lost some relevance, it still works well in development – specifically as a way to prevent overengineering.
Elon Musk has his own views. It’s well known for demanding that teams at Tesla and SpaceX don’t get stuck in their own ideas, but actively share them with each other. The billionaire calls this a fight against “silos.” However, both Bezos and Musk advocate for simplicity – not just in communication but in everything. They often urge both managers and engineers not to spend months on decisions that can be reversed.
“If the design takes a long time to build – it’s a wrong design. Over and over, it’s like a tendency to complicate things. The best part is no part, the best process is no process. It weighs nothing, costs nothing… Can’t go wrong.”
Elon Musk, entrepreneur, the founder of SpaceX and Tesla
Meta founder Mark Zuckerberg became famous in his time for a different approach. In Facebook’s early days, his teams used the slogan “Move fast and break things” – releasing code daily, consciously allowing mistakes. But also outpacing competitors. In these wild races, Zuckerberg saw the key to learning through action, which later translated into another motto: “Done is better than perfect.”
But times change, and in 2014, Zuckerberg announced the “maturation” of his views.
“As the company grew, we were producing so many bugs that going back and fixing them was actually slowing us down more than we were speeding up. So, I still thought, okay, like moving fast, this is still like a really important thing. We’ve got to change how we do it. So, we kind of evolved to building a somewhat less sexy phrase: ‘Move fast with stable infrastructure.’ And then, basically, the new bet was we were going to invest disproportionately in building up good infrastructure and abstractions inside our company. That way, the average engineer who comes here is going to be much faster and more productive at getting things done than in other places.”
Mark Zuckerberg, entrepreneur, the founder of Meta
It seems, Zuckerberg, like other new-wave tech leaders of the 2000s, largely followed the ideas of popular analysts at the time, blending them with his own complex experiences and those of his competitors.
Let’s look at these generally.
Martin Fowler advocates for evolutionary development. His main principle is continuous code refactoring, but gradual and only when truly needed. A classic example is Twitter’s story: their first Ruby on Rails monolith handled only 200 requests per second. Of course, problems came later – by the time they switched to microservices, the load had grown to 12,000 tweets per second. But the company had managed to develop a business model and find resources for reengineering.
Brit Dave Farley, with his automation credo, suggested that instead of trying to “predict the future” – we should create an infrastructure that quickly implements changes when needed. Netflix has something similar: their architecture isn’t super-reliable but can self-recover after failures. Their Chaos Monkey tool deliberately “breaks” production, but it always recovers – on average in 7 minutes. And this happens constantly. In essence, Netflix is a large crash test site. Did you notice anything while watching your favorite series?
Robert Martin, known as Uncle Bob, immediately offers a strict criterion: if you spend more time on design than implementation – you’re already in the overengineering zone. Even Google, with their strict standards, considers the simple solution to be the best. In their internal documentation, there’s one requirement: a new developer should be able to understand your code within a sprint. Can’t do it? Then something’s wrong.
Bottom line. The “classics” understand engineering quality differently. But they almost always agree on one: “simpler and less” is almost always “better.” The rest are details.
Taking this as a base and roughly combining all approaches above, we’ll highlight several key principles from experts – based on their literature.
The first is the principle of proven necessity.
Here’s how Robert Martin explains it:
“You only put in the abstractions that you need, that you provably need. You will find that you will put a lot of them in just because you’re writing tests. The tests will need a lot of abstraction, so you can decouple your production code, get inside it, and access it from unit tests. And then you’ll also find from time to time that there are changes that people make, and you’ll look at your code and go, ‘Man, I didn’t protect myself from that.’ So, that’s when you do it – go back, refactor, put that abstraction in. It’s pretty reactive. There’s a little bit of upfront design work at every iteration. A little bit of abstraction, you think you’re going to need, but not very much.”
Robert C. Martin, author, co-author of the Agile Manifesto, software development expert
More of Martin’s philosophy is reflected in the already mentioned SOLID principles – essentially, he was the one who defined them.
Fowler’s vision, on the other hand, aligns more closely with another well-known concept, YAGNI, or “You aren’t gonna need it.”
The second principle is the balance between speed and quality.
According to Fowler, technical debt is acceptable when it allows for faster validation of business hypotheses. This is also the basis of extreme programming and its related practice, pair programming.
The third is “a nod to Farley” – automation as an alternative to excessive design. The focus is on systems that are easy to test, deploy, and recover. A well-known classic example is Amazon.
The fourth, and most important, is a focus on the present. All three authors agree that trying to anticipate future needs more often creates problems than solves them.
The Israeli author and Microsoft developer Eliran Turjeman illustrates with a practical example how these principles work in action. We mentioned him earlier: in his article “Finding the Right Balance,” he presents a case on configuring shopping carts in an online store and describes three approaches with screenshots.
The first is straightforward – using specialized code.
Developers create a separate method for each case of item removal: one deletes an item by ID, another clears the entire cart, and a third removes out-of-stock items. The code works, everything is simple and clear.
But then a new requirement appears, and another method is added. Another requirement – another method. Over time, the class grows with methods that are essentially identical, increasing cognitive load for developers.
This results in underengineering – in this case, solving each new task with a separate method without considering future code maintainability.
Approach two – the bloated standard solution.
After getting burned by the first version, developers create a super-universal deletion method. It takes not just a deletion condition but also an external service for rule validation, additional filters, and event handlers. Not bad. But now, to simply remove an out-of-stock item, you have to write something like: ‘delete where item is out of stock, rule service = null, filter = standard, handler = null.’ And this is already overengineering, a solution so generic and flexible that simple operations become hell.
Approach three – the conditionally balanced.
One deletion method takes only a condition – the rule that defines which items to delete.
Want to delete an item by ID? Pass the condition ‘where ID equals given.’
Remove out-of-stock items? Condition ‘where item is out of stock.’
Clear the cart? Condition ‘delete all.’
The code remains relatively simple, quite understandable, yet flexible enough for all real scenarios.
Ok, let’s return to Europe. We asked our fellow practitioners to share how they would advise avoiding over-engineering.
Maxim Leykin, Head of Engineering at Bamboo Agile, Estonia:
“There is no one-size-fits-all rule. Each project is different. However, in general, to avoid over-engineering, it’s useful to stay informed about the best modern trends and practices like service-oriented or event-driven architecture in software design. Always think about reusing something instead of writing it again, and discuss ideas and approaches with other team members before coding. I know that many teams practice test-driven development, which helps prevent redundant coding, though I’m not a big fan of test-driven development myself. Still, it might be the way forward.”
Maxim Leykin, Head of Engineering at Bamboo Agile
Maxim’s colleague, CEO Sergey Zubovich, believes that simpler solutions are always more open to becoming complex than vice versa.
“’Old-school’ engineers prefer to invent each particular screw under the hood and, for example, apply such things as Kubernetes and microservices wherever they can, not really caring whether they are necessary or not. Often, this way, they solve the non-existent business case of migration from one cloud provider to another. This is just a specific example, and you might disagree here.
In general, I would advise always keeping in mind the keep-it-simple-stupid (KISS) principle and CAP theorem, which stands for Consistency, Availability, and Partition Tolerance.”
Sergey Zubovich, CEO at Bamboo Agile
Bamboo Agile’s Engineering Manager, Vasilij Ninko, advocates for an evolutionary path following Fowler’s principle. In his opinion, the key criterion for a technical solution’s success, how well it allows the business to develop, becomes clear only in a year-and-a-half perspective.
“I believe that if a system can operate in a simpler way, it should. This doesn’t mean it should be crude or lack the ability to evolve. In fact, it’s an exaggeration to claim that everything magical needs to be built from the start without room for adjustment later.
Partly for this reason, I don’t think it’s useful to blindly follow all client requirements. Any task can be viewed as isomode general or simpler.”
Vasilij Ninko, Engineering Manager at Bamboo Agile
Vasily cites a Polish payment system that serves most of the country’s banks and online stores using only two microservices. But, he reminds us: simplicity must be deliberate. That’s why he advises caution with low-code development.
Part 4. Conclusion
So, friends, let’s sum it up.
Of course, there will be no unambiguous answers: we have presented rather general views.
But let’s try to summarize the key points.
Over the past decades, two polar approaches have developed in the tech industry. One is to anticipate everything from the start; the other is to do only what’s needed now. As is often the case, the truth lies somewhere in the middle.
And there are no universal rules of the game.
What do theorists and practitioners from different countries agree on?
First, there is no universal solution. What is overengineering for a startup is critical for an enterprise system. What’s optimal for one niche is impossible for aviation or banking software.
And even what’s brilliant in functional simplicity now may ruin your system in 2 years.
Second, not only is overengineering harmful, but so is its opposite extreme. It’s useful to consider the psychological aspect too.
Third, and perhaps most importantly, success lies in a delicate balance. Between Netflix’s “let it fail but recover quickly” and Google’s “figure it out in a sprint.” Between early Twitter’s “monolith” and Amazon’s service-oriented architecture. The balance is fragile and individual but nearly always rests on three pillars:
- understanding current, not future, business requirements;
- ability to change quickly when needed;
- common sense in risk assessment.
“How to achieve this “Zen” is a topic deserving of another podcast. For now, let’s take Martin’s “time-based” criterion as a rule of thumb: “If you spend more time designing than implementing, you’re probably overcomplicating something.”
And if you made a mistake… Well, you can avoid mistakes only if you do nothing. The key is to recognize it – and fix it in time. And that’s what we wish for you.