Overengineering: What is it and how to make sure you don’t overpay
When building a software product, there’s no universal approach or a single ‘right’ way to do things. It takes the combined effort and expertise of the development and design team, and effective, direct communication with the client to create a product that performs according to expectations. But often, excessive engineering casts an expensive shadow over the development process.
By excessive engineering, or overengineering, we mean solving problems that are not relevant to a particular project. It can be well-intentioned or it can result from the team’s lack of experience or miscommunications. Either way, solving non-existent problems poses a serious challenge to the product. Overengineering may lead to a delayed release, budget inflation, and a poor-quality end product.
The need for programmers is growing, and accordingly, new professionals are starting engineering careers, and new tools and frameworks continue to flood the industry. So it’s safe to say that the overengineering issue isn’t likely to go out the window any time soon.
If you want to build a robust product that functions exactly how you imagined, you should be aware of this problem, know how to spot it, and more importantly, how to avoid it. In this post, we talk about why developers tend to overengineer and look at the practices that help eliminate redundant development.
What is overengineering?
The term itself has been a red flag for programmers for quite a while. Back in 2008, Max Kanat-Alexander, author of Understanding Software, noted that developers threw this word around all the time but there was no official definition. What he proposed as a definition is still the most referred to today:
When your design actually makes things more complex instead of simplifying things, you’re overengineering.
Now the term has a Wikipedia page, multiple implications, and a fair few memes dedicated to it. While its connotations can be subjective, the essence remains the same: overengineering is not about complicating things per se but rather about solving unnecessary problems.
Overengineering in development means writing code that solves problems the client doesn’t have.
It’s tempting to use one more tool, try another approach, or design an additional feature just in case or because a developer is keen to do so, but it overcomplicates matters if that extra tool, approach, or feature isn’t relevant to the product’s purpose.
This classic meme shows how far a project can stray from real needs.
Kanat-Alexander also distinguished the two most common overengineering practices:
- Useless extension. The example he gives is making a web server that supports every possible protocol when it only needs HTTP. Sometimes, a sales team tries to sell clients complex, expensive features they don’t need, and it’s never good for the end product.
- “Everything to everyone.” By going too generic, engineers can end up with an endless list of features and improvements that don’t add any value. Let’s say you want a simple task-tracking program that’s tailored to your particular workflow but development goes beyond your objectives and includes features for managing multiple teams, projects, and integrations.
Overengineering sounds bad in theory, and it’s even worse in practice. Let’s see how excessive programming, detached from reality and your business needs, can affect your project.
The traps and pitfalls of overengineering
An overengineered solution often leads to the following consequences:
- Missed deadlines and increased costs. Unpredicted and uncontrolled rounds of improvements on a product with unnecessary features pushes costs higher and extends the development timeframe. When the problem goes unchecked and developers completely miss the mark regarding the functionality that’s actually required, you might need to completely rewrite the solution.
- Functionality and/or design clutter. Every component you didn’t wish for and your target audience won’t use detracts from your product’s quality and value.
Sounds dreadful, right? Now, let’s see why it’s such a common problem and how to avoid it in web development.
Why do developers overengineer?
What creates the foundation for overengineering? There are several common reasons for fighting with the wind instead of catering to particular business needs:
- Striving for perfectionism. Perfectionism is believed to be on the rise, and in a competitive environment such as software development, specialists tend to work too hard and be too diligent.
- A proclivity for overcomplication. There are numerous threads on Quora, StackExchange, and other forums about programmers “enjoying complexity” and “intentionally overcomplicating code.” Complicating things is often inherent to a developer’s job and is often described as the norm, not the exception.
- Speculation on future needs. Sometimes teams build unrealistic expectations for the project, going above and beyond what the client specified. In a popular article on overengineering, Fagner Brack refers to the second-system effect that happens when a project’s stakeholders inflate expectations instead of focusing on the actual state of things.
- Poor management. Many factors related to communication with the client and inside the development team contribute to overengineering. If there are too many intermediaries and the client isn’t directly engaged in the process, their needs and requirements may be misunderstood or even ignored. In turn, this can create excessive rounds of development.
- Lack of expertise. Since there’s no single way to build each specific function, the same product can be developed very differently in terms of timeframe, budget, code readability, and effectiveness. If you don’t find a team with knowledge of the particular niche you’re in, you risk getting overcomplicated and barely reusable code.
Another classic meme about developers overcomplicating things.
As you can see, the factors that contribute to overengineering are divergent: from personal reasons like boredom at work and an individual programmer’s desire to broadcast their exceptional skills to team organisation reasons like inadequate communication, planning, or issues with prioritisation. But all these factors depend on the working environment in a development company and the methodologies applied to project management.
Let’s discover how development providers can address overengineering and what you, as a product owner or stakeholder, can do to eliminate redundant development.
How to deal with overengineering
To make sure your product is delivered on time and functions as specified, you need to carefully select a development team and be as involved in each stage of the process as possible. Here are the ingredients that make a recipe for development success:
- Clearly defined objectives. Developers should understand what you have in mind and be on the same track. Before starting a project, discuss its scope, types of users, its context of use, and any other important details. Explain what you want to achieve with the product and what it can offer in any given circumstances. Only when everybody involved in the process understands these basics can developers move on to actually building the product.
- A feasible plan for possible future needs. It’s important for a product to be scalable but it’s not a universal rule. Any “best practice” might not be the best choice for every project. You need to understand what your project might or might not need in the future. Are you planning to grow the user base or the number of integrations, or is the product’s scope limited to its current use? Ask yourself similar questions before creating a plan for future development additions.
- Iterative approach and continuous product evaluation. Reviewing the product only at its final stage is simply wrong. Learn how the developers you want to work with build their processes. For example, developers at MadAppGang build software based on Sprint planning, where each Sprint takes a week or two and results in a working prototype. Each new Sprint adds a new feature or improvement, but we don’t build anything new if something isn’t right with previously built components. An iterative approach helps keep track of your product and see it evolving according to your requirements.
- Direct communication with the team. It’s important that you’re part of the development process. At MadAppGang, we cooperate with our clients based on Agile methodologies, that means regular meetings to discuss the current state of development and any challenges that have arisen. When you know the technicalities of building each functionality, you can prioritise the features and make timely changes to the project.
- Transparent documentation of processes. It may happen that development team members change or you decide to extend the product with another team — this is when quality documentation becomes essential. For the code to be comprehensible to others and reusable for different purposes, a development company should maintain clear documentation.
As overengineering is actively discussed in the tech community, developers often share thoughts on how to avoid it:
- Communicating solution ideas with colleagues. With any ambiguity, it’s best to consult inside the team and with the client to make sure the solution won’t negatively impact the budget and release time.
- Writing tests before development. Many teams practice test-driven development (TDD) that helps prevent redundant coding.
- Forgetting about reinventing the wheel. There are many frameworks and libraries that facilitate development, so there’s no need to develop something from scratch that has been out there for years.
- Not designing too far into the future. Programming principles including KISS (keep it simple stupid) and YAGNI (you ain’t gonna need it) caution developers to be mindful of current requirements and not go the extra mile for something that’s a nice-to-have but that shouldn’t occur.
- Being conscious of each line of code’s value. This might seem idealistic, but any professional developer should bear this tenet in mind.
Remember these points when speaking to the developers you may hire. Most importantly, you should feel like the team understands your idea and your visions align. This way, you are likely to avoid overengineering, work in a healthy, cooperative environment, and get the best possible version of your product.
Building great software without overengineering
Coding solutions that don’t solve actual problems or ignore business requirements for the sake of technological advancement or complexity is overengineering. And it’s a pressing issue for many projects that get delayed or even ruined because development becomes unrealistic and strays far from the client’s vision.
As one developer succinctly put it, overengineering is like snoring: no one thinks they do it. It’s true that overengineering can be tricky to spot, but there are ways to avoid the issue. When searching for a development team, find out if they have similar projects in their portfolio, ask how they build their processes and how much you will be involved. The latter point is important because understanding your goals and communicating them to the team is half the battle.
At MadAppGang, we always learn the ins and outs of a project’s context and its goals so that we can deliver according to the client’s current expectations. We care about scalability, but we don’t predict possible future requirements without input. In our view, these can only be introduced by the client.
If you want to build a software solution, and you don’t want a bunch of unnecessary complexities, drop us a line, and we’ll discuss your needs and the scope of your project.