- Noah Jacobs Blog
- Posts
- On Overengineering
On Overengineering
You're building a business, not a product.
2025.02.09
LXXXVI
A couple weeks ago, a mentor of mine told me:
Building a product and building a business are not the same thing.
He is very very right.
Once you have a product that users derive value from, you don’t necessarily make more money by making the product better. As a matter of fact, just because you have a valuable product, it does not necessarily mean you will make any money at all.
The business itself is an entity (an organism, if you will) that you are trying to grow. Having some product or service is a necessary part of that, but not sufficient.
You need to, you know, sell the thing.*
While product development never stops it is subservient to building the business.
Overengineering happens when you add more complexity than your business or users need. It’s like hunting for a squirrel with a 50 caliber rifle—overkill.
*Really, though, your goal is likely not even just to sell the product, but to build a system for selling the product (See: On Money Tree Farming).
The “Just Right” Refactor
Yesterday, I spent a lot of time refactoring a very core part of our code base.
The logic had gotten us from 0 customers to 10 customers, but it needed an overhaul to get us from 10 customers to 100 customers.
For the last month or so, I was very conscious that the current solution was going to become a problem, and was brainstorming different ways to redesign the system.* However, I never took the jump and actually solved it–the change was going to be very complex and take a whole day.
This week, though, the current solution almost became a problem for our users**. This made it obvious that if we had 15 customers, not 10, the current solution would likely break.
So, this weekend, I ended up making a huge change that, with some hardening, should take us from 10 to 100 or even 200 users.*** If I would have done this three months ago, it undoubtedly would’ve been overengineering. Three months ago, we didn’t need to support more than ten users. Yesterday, though, it felt just right.
Now, I could’ve engineered a change that would’ve taken us from 10 to 1,000 or 10,000 users****; I’m fairly confident I know how to do that. But, if I did this now, it also would’ve been over engineering. It would be way too early to justify the hours spent & the added complexity.
The business needs something that can get it to 100 users before it needs something that can get it to 1,000 users.
And, the best part is, the longer we wait to upgrade the tech stack again, the more we’ll know about what the next solution should actually look like. The longer you wait, the more informed decisions you can make.
That being said, waiting even longer to push the change I just made likely would’ve have gave me more information to make it better, but would run an increasing risk of having the issue cause harm to the business.
As in all things, balance and timing matters.
*The crux of the problem was that users could submit “jobs” of highly variable size, and we were running a fifo pipeline with five workers, where each worker could do one job at a time.
**One user was entering A LOT of very small jobs… blocking other user’s jobs.
***Breaking jobs into small tasks that get distributed to workers with separate queues & concurrent pools of tasks. Also, merge tasks when possible & batched some other functions / reduced redundant resource use.
****Horizontal scaling across machines with roughly the current setup…
Overengineering is Relative
Since the product serves the business, overengineering is a relative term.
Overengineering is another way of saying that a solution is “overkill” for the current or reasonable projected future state of the business.

Overengineering is simply the extra complexity that does not actually provide value to the user or business; so, for a given task, the level of overengineering is just all of the engineering that doesn’t provide value to the users.
However, there is an interesting asymmetry, here. A piece of software that can efficiently serve 1,000 users can also serve 10 users, but a piece of software the can serve 10 users, can not necessarily serve 1,000 users.
This is why awareness of what the business needs as an entity is so important.
Hunting
If you were going hunting, but did not know what you were hunting for, you would have no choice but to bring a 50 caliber rifle, as it can kill anything you would possibly hunt (barring perhaps whales).
However, if you only needed to kill a deer, this would certainly be overkill, as a much smaller rifle would be sufficient.
In other words, knowing that the target is a deer (100 users in the next 6 months) rather than a elephant (10,000 users in the next 6 months) allows you to rightfully reduce the caliber of the weapon you use (a system that can scale to a couple hundred users) and saves you from carrying around a bigger, harder to user rifle (code that scales to 10,000 users) than you need.
The gun is not chosen for the guns sake, just as the product is not built for the product’s sake.
The gun is chosen for the hunt, and the product is built for the business, which in turn is built to provide value to the users.*
*I have been using business & users somewhat interchangeably through this post—this is why: the business exists to provide value to the users.
The actual Outcome
It is unlikely that the product’s complexity ever actually tracks the “real” required complexity perfectly at any given time, but I think it is very possible to keep the two things reasonably close. I also think that if you are not conscious of the fact that you are building a business and are only aware of the product, you will end up with wayyyy more complexity than you need.

The jagged dark red graph is perhaps what we can reasonably hope for. The bright red graph is to be avoided, just as spending too much time below the blue line is to be avoided.
The tighter the feedback loop between the product and the business, the less overengineering will be done.
While the easy answer is to bias towards slightly over engineering, becausee if you under engineer and find out about it, that is a problem. That being said, it is likely a “champagne problem” in that it means the business is growing more than you planned on. Now, you should have resources to quickly solve the issue.
On the other hand, overengineering is more insidious in that it is harder to catch if you’re not paying attention.
I’ll leave you with a quote from an anonymous person in a cryptic group chat I am in:
“Selling a theory or model in an abstract sense is basically trying to delegate risk to your users.”
When you overengineer a solution, you make the business & users pay the price for complexity they likely don’t need.
Live Deeply,
