Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax
Before this topic teaches you how to strangle a monolith, stand up an API gateway, or slice a BFF, it owes you the prior question the other 102 pages assume you have already answered: should this system be more than one service at all? The honest default for a small team is no — and being able to say why, crisply, is a stronger signal in a staff interview than reciting the Strangler Fig steps. This page is the advance organizer: it gives you the thesis, the tax, and a defensible decision procedure so the mechanics that follow have a destination worth reaching.
The thesis in one line: microservices are an organizational scaling technology, not a performance one. They buy independent deploy cadence, team autonomy, and blast-radius isolation. They do not make a request faster — the opposite. The moment you split a module into a service, an in-process function call becomes a network round trip: nanoseconds become milliseconds, arguments get serialized and copied, and a call that used to either fully succeed or fully fail can now time out, be retried, arrive twice, or half-complete while the network is partitioned. You are trading a performance and correctness cost for an organizational benefit. If you are not buying the organizational benefit, you are just paying the tax.
The distributed-systems tax, itemized
"Tax" is not rhetoric; it is a concrete bill that arrives the day you cross the first process boundary, and it is owed per service, forever:
- The network is now in your data path. Every hop adds latency and a new failure mode. A synchronous chain of five services multiplies both: p99 latencies compound, and any one service being down takes the whole request down unless you engineer around it (timeouts, retries, circuit breakers, bulkheads).
- Consistency goes from free to hard. Inside a monolith, a single database transaction makes "debit the wallet and create the order" atomic. Split payments and orders into two services with two databases and that atomicity is gone. You now reach for a saga (a sequence of local transactions with compensating undo steps) or TCC, and you must design for the window where the system is inconsistent. Distributed transactions (2PC) exist but are slow, block on coordinator failure, and are widely avoided.
- Observability must span services. A stack trace no longer tells the story. You need distributed tracing (correlation IDs across hops), log aggregation, and per-service metrics just to answer "why was this request slow?" — questions a debugger answered for free in the monolith.
- Operational multiplicity. N services means N deploy pipelines, N sets of dashboards and alerts, N on-call surfaces, N places to patch a CVE, and versioned contracts between every pair that talks. This is a fixed cost that scales with service count and is mostly paid by humans, not machines.
Conway’s Law is why the org, not the machine, drives this decision
Melvin Conway’s 1968 observation: a system’s structure mirrors the communication structure of the organization that builds it. Two teams that must coordinate on every change will produce two tightly coupled components regardless of the diagram you drew. The corollary that matters here: service boundaries that do not match team boundaries fight the organization and lose. If three teams share ownership of one service, or one team owns six services that must deploy in lockstep, you have manufactured coordination overhead without the autonomy that justifies it. The modern prescription is the Inverse Conway Maneuver (Skelton & Pais, Team Topologies): decide the architecture you want, then shape teams into loosely-coupled, service-sized units so the org naturally produces it. Boundaries are a socio-technical decision, not a purely technical one.
Monolith-first: extract on pain, not on prophecy
Martin Fowler’s guidance (MonolithFirst, Microservice Premium) is the load-bearing heuristic: start with a well-modularized monolith and extract a service only when a real, present pain signal forces it. The reasoning is that microservices carry a premium — the tax above — that only pays off past a certain scale of system and team. Early on you almost always have the boundaries wrong, because you do not yet understand the domain. Getting a boundary wrong inside a monolith is a refactor the compiler helps you with; getting it wrong across services is a data migration, a contract renegotiation, and a coordinated multi-team deploy. Cheap-to-move boundaries are a feature, and the monolith is where they live.
The discipline that makes this work is the modular monolith: one deployable, but with hard internal module boundaries — each module exposes an explicit API, owns its own tables (no reaching into another module’s schema), and is enforced by the build (package visibility, an architecture-fitness test, or a tool like ArchUnit). A modular monolith is a microservices architecture with the network turned off: if the seams are clean, extraction later is mechanical. If the seams are muddy, no amount of network will fix them — you’ll just distribute the mud.
Extract a module into its own service when — and only when — a concrete signal appears:
- Independent scaling. One module’s resource profile diverges hard from the rest — e.g. video transcoding is CPU-bound and bursty while the rest of the app is I/O-bound — and scaling the whole monolith to serve it is wasteful.
- Independent deploy cadence. One module changes ten times a day while the rest changes weekly, and coupling their release trains is slowing everyone down or making deploys risky.
- Different runtime or technology. A module genuinely needs a different language, a GPU, or a specialized data store that doesn’t belong in the main process.
- Team contention on one deployable. Multiple teams are stepping on each other in the same release, and the deploy has become a coordination bottleneck. (This is the Conway signal — and often the first one that truly justifies the tax.)
- Independent fault isolation. A module must fail without taking the core down (or vice-versa), and in-process isolation isn’t enough.
Notice what is not on the list: "we might need to scale someday," "microservices are best practice," "it’ll look good in the design doc." Those are prophecy. Extraction on prophecy is how you buy the tax years before the benefit.
A traced decision: same product, opposite right answers
Two teams are building the same thing — an online store with catalog, orders, payments, and shipping. Watch the org variable flip the answer.
Case A — the 5-person startup
Five engineers, one shared understanding of the whole domain, boundaries still shifting weekly as they learn what customers want. Walk the extract-on-pain checklist: independent scaling? No — traffic fits comfortably on a few app instances behind a load balancer. Independent deploy cadence? No — everyone ships the same app, and coordinating five people is a Slack message. Different runtime? No. Team contention on one deploy? There is one team. Fault isolation? A well-structured monolith with timeouts around external calls is plenty.
None of the signals fire. Splitting into eight services would hand five people eight pipelines, eight on-call rotations, cross-service tracing, and a saga for checkout — a full-time distributed-systems tax paid by a team that should be finding product-market fit. Right answer: a modular monolith. Keep the seams clean so extraction is cheap later, and spend the saved effort on the product. This is the answer to "why not a monolith for a 5-person team?" — because the tax has no benefit to pay for yet, and clean modules preserve every future option at a fraction of the cost.
Case B — the 300-engineer org
Now the same product at scale: 300 engineers across ~30 teams, the domain well understood and stable, checkout traffic 100× the catalog-admin traffic, payments under a compliance boundary that shouldn’t share a process with anything else, and a single daily deploy that has become a 30-team coordination summit where one team’s bug blocks everyone. Walk the same checklist and nearly every signal fires: teams contend on one deployable (Conway pain), modules scale independently, payments needs isolation, cadences diverge wildly.
Right answer: services, drawn along team boundaries. Here the organizational benefit — 30 teams deploying on their own cadence without a summit — is exactly what the tax buys, and it is worth it. The point is not that one answer is smarter; it is that the deciding variable was the organization, not the technology. Same product, same requirements, opposite architectures — and both defensible.
The distributed monolith: the tax with none of the benefit
The failure mode that punishes premature or badly-drawn splits is the distributed monolith — services that are physically separate but logically fused. You paid the entire distributed-systems tax and got none of the autonomy or isolation it was supposed to buy. It is strictly worse than the monolith you started with. Detect it by these tells:
- They must deploy together. Releasing service A requires releasing B and C in lockstep, or nothing works. Independent deployability — the whole point — is gone.
- Long synchronous call chains. A single user request fans through A→B→C→D synchronously; one slow or down service fails the request. You’ve turned N reliable components into a product of their availabilities.
- A shared database. Two services read and write the same tables. Now neither can change its schema without breaking the other, they contend on the same locks, and the "boundary" is a fiction — the coupling just moved to the data layer where it’s harder to see.
- Chatty, fine-grained calls. Rendering one screen makes dozens of cross-service calls because behavior that belongs together was scattered across services split by technical layer.
The root cause is almost always splitting along the wrong axis — by technical layer (a "controllers service," a "DAO service") or by prophecy, before the domain boundaries were understood. The fix is to re-draw boundaries around business capabilities and team ownership, or, honestly, to merge back to a modular monolith until the seams are clear. Recombining is a legitimate, senior move, not an admission of failure.
Selection & trade-offs: three points on a spectrum
This is not monolith-versus-microservices; it’s a spectrum of granularity, and the interview-grade answer names where each wins.
Modular monolith — one deployable, hard internal seams
Gains: in-process calls (no network tax), one transaction for atomic writes, one pipeline and one on-call, trivial local debugging, and boundaries you can refactor with a compiler. Costs: one shared runtime and blast radius (a memory leak or a bad deploy affects everything), scaling is all-or-nothing, and a single tech stack. Wins when: the team is small-to-mid, the domain is still being learned, or you simply have no firing extraction signal. The correct default.
Microservices — many fine-grained services, one per capability/team
Gains vs the modular monolith: independent deploy cadence, per-service scaling, fault and security isolation, tech heterogeneity, and true team autonomy. Costs it adds: the full distributed-systems tax — network latency and partial failure, sagas instead of transactions, distributed tracing, and N× operational surface. Wins when: you have many teams whose coordination cost on a shared deploy exceeds the tax, or components with genuinely divergent scaling/runtime needs — i.e. real Conway pain. Wrong until the org is big enough to spend the benefit.
“Macroservices” / few coarse services — a handful of larger services
Gains vs a monolith: you isolate the two or three seams that actually hurt (e.g. peel out payments and the async job runner) and get most of the autonomy. Gains vs full microservices: a fraction of the operational surface — three pipelines, not thirty — and far fewer network hops per request. Costs: each service is still internally a mini-monolith, so intra-service coupling can creep back. Wins when: a mid-size org has a few clear, high-value seams but nowhere near 30 teams — the pragmatic middle most companies actually live in. This is usually where "we did microservices" should have stopped.
The senior framing: you don’t pick a camp, you pick the fewest boundaries that relieve real pain, and you move along the spectrum only as the pain (almost always organizational) appears.
Pitfalls
- Resume-driven / cargo-cult architecture. Adopting microservices because Netflix did, or because it’s on the ladder to staff, imports the tax without the scale that justified it. Netflix and Amazon moved to services under org sizes and traffic you almost certainly don’t have — and after living the monolith’s pain first.
- Splitting by technical layer instead of business capability. A "UI service," an "API service," a "database service" maximizes cross-service chatter for one user action. Split by capability (Orders, Payments, Catalog) so a change and its data live together.
- A shared database across services. The single fastest way to build a distributed monolith. Each service must own its data; cross-service reads go through an API or an event, never a foreign key.
- Premature extraction before boundaries are understood. Extracting while the domain is still fluid freezes a guess into an expensive contract. Wait until a seam has stopped moving and a signal fires.
- Ignoring the operational cost. Every service is N more pipelines, dashboards, alerts, on-call rotations, and CVE patch sites. A five-person team drowning in ops isn’t shipping product. Count the humans, not just the containers.
Takeaways
- Microservices are an org-scaling tool, not a speed-up. They buy independent deploys, team autonomy, and isolation; they cost you the network, eventual consistency, sagas, tracing, and N× ops. No org benefit to buy → don’t pay the tax.
- Monolith-first, and specifically modular-monolith-first. Keep hard internal seams so extraction stays cheap, and extract on a real firing signal — independent scaling, deploy cadence, runtime, team contention, or fault isolation — never on prophecy.
- Conway decides the boundaries. Draw services along team lines; cutting across them yields a distributed monolith — deploy-together, synchronous chains, shared DB — the tax with none of the benefit.
- The org is the deciding variable. A 5-person team should almost always stay a modular monolith; a 300-engineer org almost always shouldn’t. Same product, opposite right answers — and that’s exactly how you defend "why not a monolith?"
Advance organizer authored for this guide. Sources: Martin Fowler, MonolithFirst
and Microservice Premium
(martinfowler.com); Melvin Conway, How Do Committees Invent?
(1968) — Conway’s Law; Matthew Skelton & Manuel Pais, Team Topologies
(2019) — the Inverse Conway Maneuver and team-shaped boundaries; Sam Newman, Building Microservices
(2nd ed., O’Reilly) and Monolith to Microservices
; and the documented Amazon (two-pizza teams, service ownership) and Netflix migration experience, both undertaken at large org scale after outgrowing a monolith.
🤖 Don't fully get this? Learn it with Claude
Stuck on Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax** (System Design) and want to truly understand it. Explain Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Should You Use Microservices At All? — Monolith-First & the Distributed-Systems Tax** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.