Overengineering is a word that a software engineer will hear about from time to time through his/her whole career. I recalled a design case that I encountered a few months back that perfectly explain what is overengineering in practice.
The Definition of Overengineering
On Wikipedia, Overengineering is defined as “the act of designing a product or providing a solution to a problem in an elaborate or complicated manner, where a simpler solution can be demonstrated to exist with the same efficiency and effectiveness as that of the original design.” I would like to simplify it as: choose a more complicated solution to resolve a problem when there exist simpler ones.
How to avoid overengineering
The tricky thing is, in practice, normally it is hard to identify overengineering in the system that is designed by yourself.
From my own personal experience, except harness yourself with rich knowledge and hands on experiences, the best option is to leverage collective wisdom, i.e. consult as many people as you can.
Case Study
A few months ago, my team had a design decision to make for a web system that is under developing. The scenario can be simplified as:
- A group of users, on peak time, the QPS was estimated as around 5K, would request and compete for a limited number of resources (the number of the resources would be less than 500) in a pool.
- Users would request the resources via RestAPI call. The users’ requests would be served in First Come First Serve style, non pre-emptive.
- The individual resource itself has a rate limiting, if it receives more than 20 requests per minute, then it will return an error and become unavailable for a few minutes.
- VIP users could be assigned a resource exclusively and still under the “20 requests per minute” rule.
- According to internal tests (from the ones who were not from the dev team), the possibility that requests from the user might take more than 3 seconds to finish was high (roughly more then 98%).
The design is targeted for resolving two issues of the scenarios:
Resources competition.
How should the system handle the case that multiple users competing for the limited number of resources?
A single resource received more then 20 requests per minute.
How should the system handle the situation that a resource receives more then 20 requests per minute from a VIP user?
One of my colleague instantly proposed using message queues as the core of the solution. To be specific:
for “Resources Competition”
- All the user requests should be put into a message queue and be pulled out in FIFO style.
- A worker would pick a request and assign a resource once there is any available ones in the pool.
for “More than 20 Requests issue”
- Assign a message queue for each resource, store the requests sent from the user into a message queue, a worker pull requests from the queue in FIFO style.
- Only let the requests be pulled out from the queue under the rate of 20 per minute.
The solution is shown below.

Add graph
Everything seems perfectly “reasonable” right now. However, in the evening of the same day, I gave the problem a second thought, then I realised that message queues might be an overengineering solution.
Resources Competition
From User Experiences Perspective
- Resources Competition. On the one hand, let us assume if a message queue is not used here, then once all the resources are assigned, a user will receive an error for the resource request and the user will be informed by a message that he/she should retry after a few minutes. On the other hand, if a message queue is adopted here and all the resources are assigned, then a user’s request will store in the queue and the user will need to wait for the response for unforeseeable time, which does not improve user experiences compare to the first case.
From System Performance Perspective
Well, it is obvious that introducing message queue will not improve system performance.
Therefore, for “Resources Competition”, adopting a message queue is an overengineering option.
More than 20 Requests issue
I was thinking about forcing a user to wait for 3 seconds as an alternative option, i.e. each time the user consumes the resource and takes less than 3 seconds (60 seconds / 20 = 3), then force the user to wait until 3 seconds passed (3 seconds count from taking the ownership of the resource to release it), it ensures that the user will not trigger the 20 requests per minutes error.
From User Experiences Perspective
Consider the fact that more then 98% of chance that a user’s request will take more than 3 seconds to complete, it means that forcing a user to wait for 3 seconds passed if a request takes less than 3 seconds will not significantly impact user experiences.
From System Performance Perspective
One resource per message queue add heavy burden on the backend system while it does not improve the system performance in any means compare to the forcing wait method.
Therefore, for “More than 20 Requests issue”, using message queue solution is an overengineering option too.
With the arguments and conclusions in mind, the other day, I successfully convince the team to avoid adopting message queue which relief the backend dev team :).