Microservices — and When to Split
Introduction
At Uber, around 2018, tracking down the root cause of one problem meant working through ≈50 services owned by 12 different teams. Their engineering blog says so, in those words — and Uber runs about 2,200 critical microservices, so that bug hunt was the architecture working as designed.
At Segment, the same pattern at smaller scale went worse. 140+ services, 140+ repos, 140+ queues — and three full-time engineers whose entire job had become, in their own words, "just keeping the system alive." They eventually deleted almost all of it, merged back into one service, and wrote the postmortem every architect should read: Goodbye Microservices.
Neither company was struggling with traffic. The previous lesson showed you a monolith carrying $5.1 million a minute — traffic was never the reason to split. And yet microservices are also not a mistake: Uber ships with thousands of engineers because of them, not despite them. The difference between the success stories and the horror stories is almost never whether a company split.
It's when — and above all where.
In this lesson: what a microservice actually is (four properties, not a size), the three pressures that genuinely justify a split, the axis rule that decides where the knife goes, the distributed monolith — the named shape of getting it wrong — and a simulator where you make the cut yourself and live with it.
Scope: the machinery a split demands — service discovery, gateways, sagas, meshes — gets a whole section of this course right after this one; today we only price it. Serverless and event-driven shapes are the next two lessons, and the closing lesson of this section (Choosing a Style: The Rubric) turns all of it into one decision framework.

Four Properties, Not a Size
The word micro has done a decade of damage, so start with the real definition. Fowler and Lewis, who wrote the canonical description in 2014, put it plainly: the style builds "a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms."
Unpack that and a microservice has four load-bearing properties:
- Independently deployable. Its own artifact, its own release schedule. Nobody waits for anybody. This is the whole point — it's the deploy train from the previous lesson, un-shared.
- Organized around a business capability. Orders. Payments. Notifications. Not "the API layer" — a thing the business would recognize as a thing.
- Owns its own data. "Microservices prefer letting each service manage its own database," as the original article puts it. Share a database and you've shared a schema, and shared schemas deploy in lockstep.
- Owned by one team. The service is the team's product, end to end — build it, run it, get paged for it.
Notice what's not on the list: small. Size is a side effect of drawing capability boundaries; it was never the goal. A 50,000-line service that one team owns and ships independently is a perfectly good microservice. Forty ten-line functions that must all deploy together are not.
Keep the four properties in hand — they're not just a definition, they're a diagnostic. Every failure mode in this lesson is one of these properties quietly going missing.
The Three Real Reasons (and the Fake One)
The previous lesson ended at a wall, and it's worth restating exactly what the wall was made of — because that's what a split is for.
Reason one: the team. One deployable means one deploy train shared by every engineer, and you watched the merge queue explode as headcount grew. A split hands each team its own train. This is the honest core of the microservice pitch — Uber's blog frames the entire trade as adopting microservices "for an operational benefit at the expense of performance." Operational benefit means: teams that ship without meetings.
Reason two: a divergent scaling curve. When one module needs a hundred times the capacity of the rest, cloning the whole artifact means paying for a hundred copies of everything. Client-Server to N-Tier gave you the test: does this part need its own scaling curve, its own failure domain, or its own security boundary? A module that passes gets its own tier — and a service is a tier with a team attached.
Reason three: a wall someone else requires. Compliance regimes that demand payment data live behind its own controlled boundary. The auditor is naming your boundary for you; the architecture is just complying.
The fake one: fashion. "This is how real companies do it" has produced more distributed monoliths than every other cause combined. If none of the three pressures above is present and nameable, the previous lesson's answer stands.
One more force belongs here, because it decides more architectures than any diagram: Conway's law. Melvin Conway, 1968: "Any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure." Your architecture will end up shaped like your org chart whether you plan it or not. Which is why a split is as much an org-chart edit as a code edit — and why modern teams run the law in reverse, shaping teams first so the architecture follows. If you split the code but not the ownership, Conway quietly glues it back together.
The Axis: Capabilities, Never Layers
So a pressure is real and you're going to cut. Now the question that separates the success stories from the postmortems — and the one Fowler and Lewis themselves flagged as the hard part: "It's hard to figure out exactly where the component boundaries should lie."
There is one reliably wrong answer, and it's the one that looks most natural on a whiteboard: cutting along technical layers. A frontend service, a business-logic service, a data service. It feels like architecture. It is — it's Client-Server to N-Tier wearing a costume. You've rebuilt tiers and called them services: every request still crosses every one of them, each hop now bills the ~200× boundary tax you measured, and no team owns a single outcome a user would recognize. Ship a feature and three "independent" services need coordinated changes — the deploy train is back, with a network inside it.
The right axis is the one the original definition insisted on: business capabilities. Orders. Inventory. Notifications. Each one a boundary inside which one vocabulary holds — where "an order" means exactly one thing — and behind which one team can own everything from endpoint to table. Domain-driven designers call this a bounded context; you don't need the full discipline today, just its instinct: a good service boundary is a place where the language changes.
And there's a practical shortcut that finds these seams for you: follow the couplings you already have. Look at your modular monolith's internal call graph. Some module pairs chatter constantly and share transactions — those are welded together, and a cut between them will bleed. Some modules only receive asynchronous events and answer to nobody in-line — those seams are already half-open. The best first split is almost always a module that's loosely coupled today, not the one that's most fashionable to extract.

The Distributed Monolith: The Shape of a Wrong Cut
The failure mode has a name, and by the end of this section you'll be able to diagnose it in one glance at a deploy calendar.
A distributed monolith is what you get when the services are separate but the properties aren't: processes deployed apart that cannot change, fail, or ship apart. The previous lesson's two-by-two grid had a bottom-right cell — network tax, no walls. This is that cell, built with good intentions. Three signs, each one a microservice property from earlier in this lesson, quietly dead:
- Lockstep deploys. You can't release Service A without coordinating Service B. Independent deployability is gone — you've rebuilt the shared deploy train and added a network to it.
- A shared database. Two services reading the same tables means one schema change fans out across both. Data ownership is gone, and with it independent evolution.
- Synchronous call chains. One user request threads through four services in a row. Latency is the sum of every hop; availability is the product of every link — the arithmetic you did in Client-Server to N-Tier, now applied four times per click.
The result is precisely the worst of both worlds: every cost of a distributed system — the hops, the serialization, the partial failures, the on-call surface — with none of the autonomy the split was supposed to buy. A monolith with extra steps.
How do teams end up here? Two roads. They split before the boundaries were discovered — cutting concrete before the seams revealed themselves, exactly the mistake Fowler's monolith-first evidence warns about. Or they split the code and kept the database, because that part was hard — and the shared schema quietly welded everything back together underneath.
Two Companies, Two Endings
Both of this lesson's case studies did the fashionable thing. The numbers went opposite directions, and the reasons are the lesson.
Uber: the premium, affordable. Around 2,200 critical microservices, and honest public accounting of what that costs: fifty-service bug hunts, "a latency spike in the nth dependency" cascading upstream, simple features spanning teams. Their own verdict on the trade — operational benefit, performance cost — and their own warning: the experience is "a strong argument against a premature adoption of a microservice architecture." But here's the part worth studying: their fix was not more splitting. DOMA, their current architecture, groups services into coarser domains — "a collection of one or more microservices tied to a logical grouping of functionality" — and it cut feature-onboarding time from three days to three hours. Even the biggest success story in microservices spent years redrawing its boundaries coarser.
Segment: the premium, bankrupting. Their split axis tells the whole story: one service per destination — per third-party integration — for queue isolation. Reasonable-sounding, and note carefully what it wasn't: it wasn't a capability boundary. It was 140 copies of the same capability, each with its own repo, queue, deploy pipeline, and drifting versions of shared libraries ("eventually, all of them were using different versions"). Autoscaling 140 distinct load patterns was "more art than science." Three engineers ran nothing but life support. When they collapsed it back to one service, shared-library improvements went from 32 a year to 46, and the test suite went from an hour to milliseconds. Their words: "It turned out this was a false advantage."
Same pattern, opposite endings, and the difference is exactly the two variables this lesson keeps insisting on. Org size: Uber has thousands of engineers to amortize the premium; Segment's premium landed on three. Axis: Uber's services map to capabilities a team can own; Segment's mapped to instances of one capability. When you hear "Netflix does it," both variables come attached.
The Premium, Itemized
From Design to Production asked whether you were tall enough for this ride; here is what the ride actually costs. Every convenience the monolith gave you for free becomes a system you must now build, run, and be paged for — and each one is a coming lesson in this course, which tells you how seriously to take the list:
- Finding each other. Services move, scale, and die; hardcoded addresses don't. You need Service Discovery.
- One front door. Clients can't juggle thirty endpoints. You need API Gateway & BFF.
- Following one request. Your stack trace is now a murder mystery across a dozen processes. You need Correlation IDs and Distributed Tracing.
- Transactions.
BEGIN … COMMITacross services doesn't exist. The order-and-payment consistency the monolith's one database gave you for free becomes Saga: Orchestration vs Choreography. - Data ownership. Who may read whose tables, and what happens when they can't — Database per Service.
- The escape route. Getting from here to there without a big-bang rewrite — Strangler Fig & Anti-Corruption Layer.
And underneath all of it, the meter from Client-Server to N-Tier keeps running: every seam bills its ~200× per call, every chain multiplies failure probabilities.
None of this is an argument against splitting. It's the price sheet — and the reason the decision deserves a simulator rather than a slogan.

Drive It: Make the Cut
Time to hold the knife. Below is the food-delivery marketplace you've been designing all course, as a modular monolith with its real internal couplings drawn — how many calls cross each seam, which seams share a transaction, which carry only events.
Try this first: read the signals panel and decide whether this system should split at all — then go against your own verdict and cut something anyway, because the point is to feel the difference. Extract notifications and watch the verdict: the only coupling crossing that boundary is asynchronous events, so nothing breaks and the spiky scaling problem leaves with it. Now put it back and extract inventory instead — four synchronous calls per checkout and a shared transaction now cross a network, and the verdict names what you just built. Then try extracting just the storefront, and see why a layer is not a capability. Watch the request dot the whole time: it pays every boundary you draw.

The Decision This Lesson Enables
Compress everything into the playbook you'd defend in a design review.
1. Confirm the pressure, and let it name the boundary. "We should use microservices" is not a pressure. "The notifications module needs 10× the capacity on game nights and its team waits forty minutes in the merge queue" is — and notice it arrives with the boundary's name inside it. If no sentence like that exists, the previous lesson's answer stands: stay, and add walls in code if coupling is the complaint.
2. Cut along a capability, at a seam that's already loose. One bounded context, one team, its own data. Prefer the module whose only inbound coupling is asynchronous — extraction there is cheap today and reversible tomorrow. Never cut through a transaction or a chatty synchronous conversation unless you've priced the saga you're signing up to build.
3. Split ONE thing, and keep the monolith majestic. The strangler-fig pattern — full treatment in Strangler Fig & Anti-Corruption Layer — exists precisely so you can extract incrementally and back out cheaply. A split of one loosely-coupled module is an experiment; a big-bang decomposition is a bet you can't unwind.
4. Re-check the four properties after the cut. Independently deployable? Own data? One team? One capability? If any answer is no, you haven't split — you've distributed.
Under interview follow-up, this position defends itself the same way the last two lessons did: with named quantities. The boundary tax is measured. The premium is an itemized list. The two case studies bracket the decision from both sides — and the sharpest sentence you can say in a design review remains: "which pressure names this boundary, and what crosses it?"
Mental-Model Corrections
"Microservices are how you scale traffic." Traffic was solved a lesson ago by cloning — $5.1M a minute through one codebase. Microservices scale organizations: independent teams, independent trains. Uber's own framing is an operational benefit bought at the expense of performance.
"Micro means small, so smaller is better." Size is a side effect. The unit is a business capability one team can own; Segment's 140 tiny services were too small to be owned and too many to be operated, and Uber's fix was grouping services coarser. Optimize for ownership, not line count.
"Netflix and Uber do it, so we should." Both variables come attached: thousands of engineers to amortize the premium, and capability-shaped boundaries. Copy the pattern without the org size and you get Segment's three engineers on life support.
"Split along technical layers — frontend, logic, data." That's a tier diagram with service names. Every request crosses everything, no team owns an outcome, and the deploy train returns with a network inside it. Capabilities, never layers.
"Microservices are more reliable — if one fails, the rest keep running." Only if the failing one isn't in your request path. A synchronous chain multiplies failure probabilities per the arithmetic from Client-Server to N-Tier; isolation arrives with the machinery — timeouts, circuit breakers, sagas — not with the split itself. Reliability is in the premium, and the premium must actually be paid.
Key Takeaways
- A microservice is four properties, not a size: independently deployable, capability-shaped, owning its data, owned by one team. Lose any one and the split is cosmetic.
- Split for teams, curves, or compliance — never fashion. The pressure that justifies the split also names the boundary. No nameable pressure, no split; the previous lesson's monolith stands.
- Cut along capabilities at already-loose seams. Layer cuts rebuild tiers with extra steps. The cheapest first extraction is the module whose only inbound coupling is asynchronous events.
- The distributed monolith is the named failure: lockstep deploys, a shared database, synchronous chains. All of the network's costs, none of the autonomy. Diagnose it by checking which of the four properties died.
- The premium is an itemized bill — discovery, gateway, tracing, sagas, data ownership, strangler — and every item is a coming lesson. Uber can amortize that bill across thousands of engineers; Segment's three couldn't. Org size is part of the architecture.
You now hold both ends of the spectrum: the monolith defended, the split priced and aimed. The next two lessons finish the style palette with two shapes that change the unit of deployment itself — starting with Serverless, where the unit shrinks to a single function and the bill shrinks to zero when nobody's calling.