What is the difference between over-engineering, under-engineering and right-engineering at coding/design perspective?

I found over-engineering: Coding too much like doing future requirement code and implementing simple logic as very complex code. Am I right?

and I do not understand under-engineering and right-engineering.

This terminology helps us to understand a design how is implemented in single word.

terms I found in this link

  • 5
    I never heard the other terms. Can you show where you saw them? To me, someone made them up to complement over-engineering.
    – Euphoric
    Jun 29, 2015 at 6:07
  • @Euphoric : added link to the question
    – Premraj
    Jun 29, 2015 at 7:02
  • I find this article helpful, which goes into some over-engineering scenarios, i.e. when a developer decides to implement an 'entity' type that can contain all future types - and the resulting disaster. To Wit: "business rules change often and the system should be able to handle these changes. The resulting [confusion] ... and complexity that the ERE created was unfathomable. " [sic] thedailywtf.com/articles/Soft_Coding Jun 29, 2015 at 14:43
  • "in order to implement a simple rule ... a developer must add or update anywhere between ten and thirty rows in the database. Although that may not sound so bad, imagine a floor full of developers concurrently working on this rules database. As difficult as it was to Soft Code the rules using C#, Soft Coding them in the database was monumentally more difficult and less productive." Jun 29, 2015 at 14:46
  • "In an effort to improve productivity, the Team ... is hard at work on a language syntax and parser that will allow developers to more easily maintain these database-stored rules. The idea is that it will be some sort of COmmon Business-Oriented Language that’s generic enough to code any rule and removes all of the “complexities” of “real” code like functions and that sort of thing. Imagine that." Jun 29, 2015 at 14:47

4 Answers 4


When you're doing too much design to solve a basic problem, you're over-engineering. For example, when you're using an abstract factory pattern “just in case” in order to create a very simple object where the business logic is easy enough to fit in four-five LOC, you're over-thinking the design (and violating KISS and YAGNI).

Note that it doesn't necessarily need to be overly complex. An abstract factory pattern has nothing complex in it as soon as classes are named correctly and the other members of the team know the pattern. This being said, it's still too much classes and code for a problem which can be solved without recurring to any specific pattern.

When you're not doing enough, you're under-engineering. For instance, if most of your Java code base is in static methods within static classes and the major part is in utility classes, you are not thinking enough about the design.

Notice that over-engineering and under-engineering is usually done by inexperienced programmers, through two different patterns:

  • The most inexperienced ones don't know design patterns enough and tend to not use them and not think too much about the design. They let their code grow with little or no design, finding such code simpler to read and understand.

  • Slightly more experienced ones who started to learn design patterns have a tendency of applying those patterns everywhere to show they know them. Should we create an object? Let's use a builder pattern with an abstract builder and a concrete one. Need to communicate between two objects? Let's use adapter pattern! And, obviously, fluent interfaces are fun, since it makes us write code like this:

    Product product = ProductBuilder()
        .setPrice(new PriceFactory().usingAmount(59).usingUnit(Unit.Dollar))
        .setTitle("Product 1"),
        .setDescription("Description goes here")

    instead of:

    Price price = new Price(59, Unit.Dollar);
    Product product = new Product(39, price, "Product 1", "Description goes here");

It requires much more skill and experience to find the golden middle, that is to use as much design as needed, but absolutely no more. This is what right-engineering term is about, although it's not used that much in the industry, for a good reason.

Over-engineering and under-engineering are the terms which are used to criticize someone else's code, like in “Dude, stop over-engineering your code, we can barely find our way through dozens of classes you add unnecessarily!” On the other hand, the golden middle of right-engineering of a developer won't necessarily be the same (and is usually not the same) for others. A recent answer shows how non-obvious is it to determine where to put a frontier between using a factory or moving the logic in a constructor. Thus, one can't assert that his code is right-engineered, because at least some of his colleagues would disagree.

  • 1
    I like how you specified the types of programmers who over-engineer and under-engineer. I was like: "Oh that's me 5 years ago...", "Oh and that's me 2 years ago" :)
    – Alexus
    Jun 29, 2015 at 17:57

"over engineering" means improving a solution when the cost of improving it is higher than the benefits of improving it. And "under engineering" means not improving a solution, when the benefits of improving it would outweigh the cost. Now guess what "right engineering" means...

Since a "simple" solution was mentioned, and was somehow correlated to inexperienced developers, sorry, but inexperienced developers often cannot find a simple solution. Experienced developers do find a simple solution if there is one, and it is often the "right engineered" solution, because it requires the minimal amount of work to get a working solution, it is often readable and maintainable because it is simple, it often (not always) is efficient because it doesn't waste time time on unneeded complexity.

Adding complexity isn't over-engineering either. Over-engineering, by definition, actually improves the product (just not enough to justify the cost of the improvement). The example given just added pointless complexity at no benefit at all.

And code isn't right-engineered when it's perfect. It's right-engineered when it reaches the point where the cost of improving it outweighs the benefits of improvement. If we can't even agree whether a change is an improvement or not, then it is very unlikely whether the change has benefits that justify the work of changing it.


I call the two extremes described "under-engineering" and "over-engineering"

They seem to refer to the sentence in the link above:

In my experience there are two developer character type extremes: the ones that always seek and settle with the simplest solution, and the ones that seek the perfect solution, perfect in terms of efficiency, readability or code elegance.

Seems like these aren't widely used terms, he's using them to explain the concepts in the rest of the post.

I could argue that:

The ones that always seek and settle with the simplest solution [...] constantly create mess

This is clearly not the definition I give to "simple solution".

These are interesting readings, thanks. I'm currently reading a book called "Just enough Software Architecture", by George Fairbanks. In that context I would probably define over-engineering (engineer too much) as spending too long in the design phase, although, you can engineer while coding too. The book emphasises a risk driven approach. Identify the risk, estimate the risk, prioritise tasks and engineer accordingly. You might find that interesting too.


I don't see these necessarily as opposites.

I think of over-engineering as providing options or provisions for capabilities that are not yet or not yet know to be necessary. For example, and method parameter that only has one value that is ever used; an abstract class that has only one subclass. These things add complexity to maintenance and cost time to develop, and may be never used. Even if some similar option is needed in the future, it can turn out that the implementation wasn't right and needs to change anyway. Best to refactor and introduce optionality when there are at least two options known to be used.

I think of under-engineering as not doing enough to handle the design; not in terms of options but in terms of quality. For example, not handling error conditions, or having race conditions. The code may run when the stars align, and, the even if stars align mostly, when they don't the code just breaks; it doesn't work.

By way of not seeing them as opposites, I think you can find both under- and over-engineering in the same project, the same file, the same method, even. Unused options, yet not robust, not stable.

Not the answer you're looking for? Browse other questions tagged or ask your own question.