Start Boring. Scale Deliberately.
My take on monoliths, microservices, and the agentic world.
Good design hasn't.
AI coding agents are doing real work in real codebases. And it turns out they're remarkably good at it, when they can see the whole picture. The thing that's good for junior engineers is also good for AI agents: being able to see the whole codebase without filing a ticket to another team.
Monorepo. Monolith.
Monorepo
Shared types. Visible contracts. Cross-cutting call sites. Refactor across domain boundaries in a single PR. Your agents, and your humans, can see everything.
Monolith
Function calls instead of network hops. A single deployment surface. “What does this change affect?” is still an answerable question. Better yet, make it modular. More on that below.
Starting here isn't naive. It's the choice that keeps your options open.
What's actually pushing your architectural decisions.
Conway's Law
Your org chart is quietly writing your architecture. Siloed teams build hard walls. If your microservices diagram looks like your reporting structure, that's not a coincidence. It's causation. Reorganize first, then decide.
Legacy headwind
Every historical decision is a current pushing against you. The temptation is to escape it by starting something new alongside the old. Usually you're not escaping the mess. You're duplicating it.
Greenfield temptation
“What if we just extracted this one piece and did it right?” This is how most premature extractions start: a service spun up to escape technical debt, not because the physics demanded it. The new thing feels clean until it has to talk to the old thing.
A microservice is not a domain boundary.
Treating a microservice as the way you express a domain boundary is a shortcut. These are three separate problems.
Where does your code live?
Monorepo vs. polyrepo. A collaboration and context decision.
How is your code deployed?
Monolith vs. microservices. A deployment and scaling decision.
Where are your domain boundaries?
A design decision. Enforceable inside a monolith.
You don't need a network call to draw a boundary.
Before you pay the deployment tax, ask whether softer tools get you 80% of the discipline.
Package structure
Module-level isolation.
Ownership files
CODEOWNERS and team accountability.
Import constraints
Explicit rules on who talks to whom.
Code review conventions
Human enforcement of domain boundaries.
Separate deployment is the strongest enforcement, and the most expensive. Match your enforcement to your actual problem.
The modular monolith.
A modular monolith lets an organization keep things simple while it scales. It is the pragmatic alternative to distributed microservices.
Shopify
With 2.8 million lines of Ruby, Shopify explicitly chose a modular monolith to handle Black Friday at global scale.
Stripe
Powering hundreds of billions in payments with over 20 million lines of Ruby, Stripe continues to operate as a successful monolith.
Uber
After scaling to 4,500 microservices, dubbed the “Death Star” by engineers, Uber is now consolidating back to “macroservices.” That is the complexity cost.
“Don't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile.”
The bar should be high.
Microservices become the right answer only when a piece of your system has genuinely different physics.
A different scaling law
40 GPU instances and two t3.mediums aren't the same problem.
A different availability SLA
That seam is real. The physics demand a hard wall.
Different team ownership
A genuine need for autonomy, not just a preference.
That's surgery with a clear indication, not architecture for architecture's sake.
Every extraction is a CAP theorem decision.
You're making it at the architecture level, and this is what you pay.
Network latency
Where you once had a function call.
Distributed failure modes
Partial outages, retry storms, cascading failures.
Versioned contracts
APIs that must be maintained across independent release cycles.
Harder observability
Traces span processes and logs need correlation. Context windows shrink for your agents, and your AI tooling loses the picture entirely.
Don't fight it.
The paddler doesn't fight every current. They read the water, use force deliberately, and correct only when the physics demand it. Your monolith is the boat. Your service boundaries are reading the current correctly. Extraction is a correction maneuver: precise, intentional, earned.
Microservices solve scaling problems. Monorepos solve collaboration problems. Service boundaries solve design problems. Know which problem you actually have. Don't pay the distributed systems tax until the scaling math forces your hand.
Five questions to take back to your team.
- Should the CTO be making this decision? Or is this an engineering leadership decision that CTOs often wrongly grab? What's the right level?
- Is your microservices architecture actually driven by scaling physics, or by org chart? Conway's Law cuts both ways.
- How do you know when you've extracted too many services? What's your signal?
- If you started today with AI coding agents as a first-class team member, would you make the same architectural choices you made three years ago?
- Who owns the decision to consolidate? Extraction is celebrated. Consolidation is quiet. Why?
Nate-Land Studios