The Microservices-for-Agents Advice Is Backwards
The advice going around right now is: if you want to run more coding agents in parallel, split your codebase into more services. More services, more isolated surface area, more agents working without stepping on each other. It sounds reasonable, and it’s spreading fast — Jake Gold’s post arguing that “there’s no such thing as a small software team anymore” hit the front page of Hacker News on August 19, and the underlying claim (fragment the codebase so agents can’t collide) is being repeated well beyond that one post.
It’s backwards. Not because independent deployability is a bad property — it isn’t — but because the thing everyone is treating as the scaling variable is wrong. The advice assumes the constraint is “number of engineers.” In the agent era, the actual constraint is “number of agents relative to the number of things they need to understand to avoid breaking each other.” Splitting a codebase into more services doesn’t shrink that second number. It hides it behind a network call and a contract that, in most codebases, nobody is actually enforcing.
What a service boundary actually buys you
A microservice boundary gives you three real things: independent deployability, failure isolation, and (in theory) an explicit contract between the two sides. The failure mode is that the third one is usually aspirational. In most codebases I’ve seen, service boundaries are documented in an OpenAPI spec that drifts, a proto file that’s half-updated, or worse, tribal knowledge about which fields are actually required versus nominally optional. A human engineer who’s worked in the codebase for two years has internalized the gap between the documented contract and the real one. A coding agent starting a task has not, and it has no way to find out short of reading the other service’s source — at which point you’ve paid the cost of the network boundary (versioning, service discovery, integration testing, deployment coordination) without getting the benefit you wanted, which was reducing what the agent has to know.
This is the actual mechanism people are missing: fragmenting a codebase into more services does not reduce the amount of context required to make a safe change. It relocates that context from “adjacent code in the same repository, enforced by the compiler and the type system” to “a remote system’s implicit behavior, enforced by nothing in particular.” An agent working inside a microservice can still write code that assumes the wrong thing about what’s on the other side of the wire. The difference is that a monolith with real internal boundaries can catch that mistake before it ships, and a network boundary between two loosely-specified services usually can’t.
The alternative: enforce the boundary, not the wire
The fix isn’t “don’t modularize.” It’s “modularize with enforcement, and don’t confuse the modularity with the deployment topology.” A modular monolith — one deployable, with module boundaries enforced at build time — gives an agent two things a naive microservice split doesn’t:
First, it gives the agent more real context per unit of work, not less. If an agent working in module A needs to understand something about module B, the actual code for module B is sitting right there in the same repository, under the same build, reviewable in the same pull request. It isn’t a hypothetical based on a spec file that may or may not reflect what module B’s code actually does today.
Second, and this is the part that actually addresses the “agents tripping over each other” problem, it structurally prevents the agent from reaching into module B’s internals even though it can see them. This is the piece that convention-based modularity (package structure, naming discipline, code review norms) has never reliably delivered, with human engineers or with agents: nothing stops a change from quietly reaching across a boundary that exists only as a convention, until someone notices in review — if they notice at all. Tools like Spring Modulith close that gap for JVM codebases: ApplicationModules.verify() runs at build time and fails if a module reaches into another module’s internals rather than its declared public API. Tach (tach-org/tach) does the equivalent for Python. Neither is Spring- or Java-specific as a pattern — they’re two independent implementations of the same idea: enforce the module boundary in the build, not in the hope that everyone (human or agent) reads the same internal wiki page before making a change.
That’s the actual reframe. The scaling question isn’t “microservices or monolith.” It’s: where do you want the enforcement to live — in a network boundary that costs you deployment complexity and buys you an aspirational contract, or in a build-time check that costs you a modularity discipline you have to actually adopt and buys you a boundary an agent (or a human) cannot silently violate?
LingoHub: a live counter-example, not a case study
The clearest example I can point to right now is LingoHub, which is a large Spring Boot monolith under active agent-driven development. It is not being split into microservices to support more agents working on it in parallel. The team is evaluating adopting Spring Modulith — specifically to formalize and enforce module boundaries that today are held together by good guidelines and code review, not by anything the build enforces.
The trigger for that evaluation is worth being honest about, because it’s less dramatic than the framing you’d expect from an argument like this. There was no incident — no near-miss, no bad agent commit that boundary enforcement would have caught after the fact. Spring Modulith has been getting more capable and more widely adopted, and that was enough on its own to make formalizing the existing informal boundaries look worth doing before a collision forces the issue rather than after.
I want to be precise about what this is and isn’t, because it matters for how much weight the example can carry. This is a forward-looking adoption decision, not a retrospective result. LingoHub is not running Spring Modulith in production today, and I don’t have a controlled comparison showing lower agent-collision rates in modular monoliths versus microservices anywhere — that data doesn’t exist yet, as far as I know. What this example actually shows is a live decision by a team doing real agent-scale work today, choosing to reach for stronger internal boundaries rather than network fragmentation as agent-driven work continues to scale. That’s informed practitioner judgment, made proactively rather than in response to a failure, and I’d rather say that plainly than dress it up as more than it is.
Where the advice is actually right
None of this means independent deployability stops mattering as you scale. At genuine hyperscale — Uber’s actual scale, thousands of engineers and, increasingly, thousands of agents working concurrently — a single bad commit inside one deployable can block or break the release train for every other team depending on that build. No amount of internal module boundary enforcement fixes that, because the problem isn’t “did this change reach into code it shouldn’t have.” The problem is “did this change make the shared build red for everyone downstream of it,” and the only mechanisms that solve that are a network boundary and a separate deploy pipeline that lets one team’s bad commit stay contained to their own service.
That’s a real threshold effect, not a hedge added to avoid an argument. The open question is where it kicks in, and it’s a considerably higher bar than most teams reading “split into microservices for agent parallelism” advice actually sit at. If you’re not running a build shared across thousands of engineers and agents where one bad commit can stall everyone else’s releases, the coordination cost you’re paying to get independent deployability is mostly the cost — the benefit that justifies it at Uber’s scale isn’t yet the constraint you’re actually facing.
The constraint this doesn’t remove
There’s a separate limit worth naming honestly, because it doesn’t go away no matter which architecture you pick. Simon Willison has written from his own experience running parallel coding agents that human review capacity is, for him, the tighter bottleneck — tighter than agent throughput or agent collision rate. Splitting a codebase into more independently deployable services, or enforcing stronger module boundaries inside one deployable, both address “can agents work without corrupting each other’s changes.” Neither addresses “can a human actually review everything an army of agents produces fast enough to keep merging it.” That’s a real, separate constraint, and it’s worth being clear that this piece is about the first problem, not the second — solving module-boundary enforcement doesn’t buy you out of the review bottleneck if that’s the one you’re actually hitting.
What this actually changes
If you’re an engineering leader being pitched “split into microservices so your agents can work in parallel,” the question to ask isn’t “how many agents do we want to run.” It’s “how much of what an agent needs to know is currently sitting in a boundary that exists only as a convention nobody enforces.” If the answer is “most of it,” the fix that actually addresses that is enforcing the boundary you already have — through something like Spring Modulith or Tach — not fragmenting the codebase into more pieces connected by contracts that are just as unenforced as the internal boundary was, except now with a network hop and a deployment pipeline in between.
Splitting into microservices for agent parallelism trades a problem you can fix with a build-time check for a problem you can only fix by building out full contract testing, service discovery, and deployment coordination — the kind of infrastructure that made sense when Uber had to solve “one team’s bad code shouldn’t block everyone else’s release,” and that most teams evaluating this advice today don’t actually need yet.
References
- Jake Gold, “There’s no such thing as a small software team anymore,” Aug 19, 2026: https://jacob.gold/posts/theres-no-such-thing-as-a-small-software-team/
- Spring Modulith: https://spring.io/projects/spring-modulith
- Tach: https://github.com/gauge-sh/tach
- Avery Pennarun, “Modules, monoliths, and microservices,” Tailscale: https://tailscale.com/blog/modules-monoliths-and-microservices/
- Simon Willison, “Embracing the parallel coding agent lifestyle,” Oct 5, 2025: https://simonwillison.net/2025/Oct/5/parallel-coding-agents/

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.