A lot of software engineers have a misconception of what over-engineering is and how it is related to robustness. Some say that robustness can’t exist without over-engineering. And I totally disagree, a robust block of code (a code that handles abnormal cases) have nothing to do with an over-engineered block of code (a code intended to anticipate the future), But i can understand where such a misconception comes from. As software engineers we tend to overthink problems. We sometimes go around trying to find out solutions for possible future needs, and that doesn’t work as no one can predict the future. So first of all let’s clarify the concept of over-engineering, its relation to robustness, and go through why we need to avoid it and how.
What is over-engineering ?
Over-engineering is simply implementing more than you need. For example if I’m trying to create a car with the following features:
In an over-engineered version I would implement unnecessary “blocks of code” in our example “features” in-order to generalize the solution.
Which will probably grow to make the solution loses sight of it’s main task. Figure .1 shows exactly how over-engineering can change the purpose of the implemented solution, hence the car turned into a helicopter.
Over-engineering most common causes:
The main cause of over-engineering in my opinion is overthinking a solution to a point where additional features become essentials. What that really mean is: “over-engineering is the result of predicting the future (user needs) in a very bad way”. In software; predicting the future in a bad way can be the result of:
premature optimization is when you start optimizing your code without an actual evidence that optimizing it will effect the over all efficiency of the solution. For example if I have a block of code that is rarely executed, the optimization of such a block won’t effect the overall solution. Making it unnecessary to optimize it at the first place. Premature optimization can be a total waste of time. And it will introduce new bugs and problems to your solution whether you like it or not, “premature optimization is the root of all evil ”
Premature generalization or abstraction is abstracting things in a general form without the existence of a number of use-cases. While abstraction in general is a great tool for developers, premature abstraction on the other hand will cause you problems. Since your abstraction might not fit all of the cases in such an early stage, where the general form properties are not fully understood.
How to Avoid Over-engineering?
In conclusion here are few tips to avoid over-engineering:
- Don’t optimize unless its a clear optimization: avoid optimizing in general and try not to optimize unless the optimization is a 100% clear and required. Make sure that the result of the optimization is noticeable.
- Software profiling: profile your application and measure time and space complexity. Identify real bottlenecks, and shift your focus on the real issue.
- Delay abstraction: wait for at least 4 cases of duplication before drawing your abstract form. You need to allow duplication to grow to form a better understanding of the general case. And keep in mind abstracting small duplication away will make the code harder to maintain.
- Simplicity is the key : try not to over-complicate things and keep it simple. Focus on the actual problem and leave future cases for the future to reveal.