The Quiet Case for Boring Software
by Babak Nabiee, Founder, BNAB Consulting

There's a version of software development that lives on conference stages and X threads — the one where every app needs microservices, every deploy needs Kubernetes, and every database query needs a cache in front of a cache. It's a good story. It sells tickets.
It's also wrong for most businesses.
I run a small development shop. My clients are restaurants, entertainment venues, and small-to-midsize operators who need software that works on Monday morning. None of them have ever asked me for a service mesh. What they ask for is usually some version of: "Can you make this problem go away?"
The answer, almost always, is yes — with a monolith.
What over-engineering actually costs
When a developer over-engineers a small project, nobody sends an invoice marked Complexity Tax. The cost shows up later, and it shows up everywhere.
It shows up when a simple change to a point-of-sale report takes three days instead of three hours because the data now lives across four services. It shows up when the only person who understands the deployment pipeline takes a vacation. It shows up in the AWS bill, which doubles for a system that serves a few hundred users. And it shows up — most painfully — when the business owner stops trusting that their own software can be changed at all.
For a Fortune 500, complexity is a cost of doing business. For a bar in Houston with twelve bartenders and a busy Saturday night, complexity is the business's software slowly eating its own margin.
What a monolith actually is
A monolith is one application, with one deployment, and usually one database. That's it. It's not a dirty word. It's how almost every piece of successful software on earth started — and a lot of them are still running that way, quietly, profitably, without drama.
For a small or midsize business, a monolith means:
- One repo your developer can fit in their head.
- One thing to deploy, one place to look when something breaks.
- One database where your data actually lives, in one piece, and where a normal SQL query answers most business questions.
- One set of logs. One set of metrics. One pager.
This is not a compromise. This is an advantage. When something breaks at 2 a.m. on a Friday, the person fixing it has a chance of actually fixing it — not chasing a request through five services to figure out which one dropped it.
When complexity is the right answer
To be fair: there are cases where splitting things up is the right call.
If you have multiple teams who need to ship independently without stepping on each other, microservices can be worth the overhead. If one part of your system has radically different scaling needs from the rest — say, a video transcoder bolted onto a ticketing app — carving it out makes sense. If you're integrating a third-party system whose uptime you can't trust, isolating that integration behind a boundary is good hygiene.
But notice what those cases have in common: they're driven by a real, measured constraint. Not a blog post. Not a hypothetical future scale. Not the fact that the architecture diagram looks more impressive with more boxes on it.
The honest test is this: can you name the specific pain the complexity is solving, and is that pain worse than the complexity itself? If you can't answer that question in one sentence, you probably don't need the complexity yet.
The AI shift — and what people are getting wrong about it
A lot of the old excuses for over-engineering were really excuses for slow development. "We need microservices because the codebase is getting hard to navigate." "We need this framework because writing the CRUD endpoints takes forever."
AI has quietly demolished most of those excuses. Boilerplate is essentially free now. Writing the hundredth version of a login flow, a CSV importer, or an admin panel takes a fraction of the time it used to. That changes the math.
The new temptation — and I see this constantly — is to take that speed and spend it on more architecture. More abstractions. More services. Because the AI can keep up, right?
Wrong move. The right move is to take that speed and spend it on the business. Ship the feature. Talk to the owner. Watch what the staff actually do on a busy night. Fix the thing they complained about last week. The part of the work where a human judgment call meets a real problem — that's still the part that matters, and it doesn't scale by adding more Docker containers.
AI is a reason to build simpler, not more elaborate. The constraint was never "we don't have time to write the code." The constraint was always "we don't know what's worth building."
The boring version usually wins
Most of the software I'm proudest of is, by modern standards, almost embarrassingly plain. A Go backend. A single Postgres or Firestore database. A native mobile app. Deployment in a single command. No message queue it doesn't need, no cache it hasn't earned, no service split it can't justify.
It ships. It stays up. It gets changed quickly when the business changes — and small businesses change constantly. When a venue owner walks in on a Monday and says "we need to track this new thing starting tonight," the boring system can actually do that. The over-architected one usually can't, because changing it means changing five places and coordinating two teams, even if the two teams are the same one person wearing different hats.
What this means if you're hiring a developer
If you run a small or midsize business and you're trying to evaluate a developer or a shop, here's a cheat sheet that will save you money:
Ask what their default architecture looks like for a project your size. If the answer involves more than one database, more than one deployment, or the word "orchestration," ask why. Make them justify the complexity against your specific problem, not against a generic one. A good developer will tell you when complexity is worth it. A great one will tell you when it isn't — and save you the bill.
Boring is not a lack of skill. Boring, done well, is the skill.
That's the whole philosophy. Build the smallest thing that solves the real problem. Ship it. Watch it work. Add complexity only when something specific and measurable forces you to.
Everything else is theater.