The Two Questions That Decide It: Who Deploys, and How Often Does the Whole Thing Change?
A 22-person startup asks you whether to "go microservices" because a conference talk said teams should own services end to end. Before any diagram, ask two questions and write the answers down: who needs to deploy independently of whom, and how often do changes actually cross module boundaries? Microservices pay when independent deployment and team autonomy outweigh distribution cost — and for most early-stage teams, the honest answer to both questions is "nobody, rarely."
The mechanism is not mystical. In a monolith, one release trains all changes into a single artifact: if checkout changed today and catalog changed yesterday, both ship in tomorrow's pipeline, and two teams coordinate through one release calendar. Microservices buy the removal of that coordination: team A deploys catalog at 14:03 while team B deploys billing at 14:07, no negotiation, no freeze, no rollback of code they never wrote. That property is worth a great deal when twelve teams would otherwise sit in a release-approval meeting — and worth nothing to a team of five whose changes rarely collide.
A decision frame you can take into a design review:
| Signal | Points to monolith | Points to services |
|---|---|---|
| Team size / shape | 1–2 teams, shared on-call | 4+ teams wanting end-to-end ownership |
| Release pattern | Weekly, coordinated, low contention | Multiple deploys/day per team, queue forming |
| Change coupling | Features frequently touch 2+ modules | Modules change independently in practice |
| Scaling needs | One profile, scale the box | One module needs 10× different resources |
| Failure tolerance | Whole-app outage is tolerable | One capability must fail without the rest |
| Ops maturity | Nobody wants a 3am pager beyond the app | Dedicated platform/rotation exists already |
The two rows teams ignore are ops maturity and change coupling. Services convert one deployable into N, and the difference is not linear: every service needs a pipeline, a runtime (Kubernetes service or serverless config), a secret store entry, dashboards, alerts, an on-call runbook, an SLO, a staging environment, and an owner when the original author left. Each service adds network failure modes, deployment pipelines, and monitoring obligations, and none of that work touches a customer feature. A team without the appetite for that bill gets a worse version of both worlds: the cost of distribution plus, often, the coordination of a monolith anyway.
The quiet counter-example is change coupling. If pricing, cart, and checkout co-change in most feature work — the same observation from Boundaries and Module Coupling — then separate services do not remove coordination, they move it into network calls, versioned contracts, and joint deploys wearing a distributed costume. Co-change means one cohesive unit; cutting it into services taxes every feature with cross-service choreography while the teams still must agree, now with worse tooling.
Interview framing: "when would you choose microservices?" is a filter question that punishes enthusiasm. Lead with the two conditions (independent deployment need, team autonomy worth paying for), show the cost table, and add the reversal condition — "if change coupling between our services turns out high, we would merge them back" — because a decision with no exit is a fashion, not an analysis.
The Bill for Every Service: Pipelines, Partitions, and the Monitoring Tax
"We split into six services and shipped nothing for three months" is a common post-mortem opening. The time did not vanish; it went to the tax that distribution levies per service, whether the service does anything yet or not. Budget it explicitly, because the decision to split is really a decision to fund these line items.
Deployment pipeline per service. Not the YAML — the discipline. Each service needs its own build, test, image, version, rollout, and rollback path, plus the environment it deploys to. On a shared platform, service number seven is cheap because the template exists; service number one is a platform project. Teams that skip this end up with a shared pipeline that deploys all services together — congratulations, you have a monolith with extra network hops.
Network failure modes enter the request path. In-process calls fail by exception, synchronously, in one stack trace. Networked calls fail by timeout, connection reset, DNS blip, TLS expiry, or a peer that is up-but-slow — and every one of them must be answered with a policy:
| Failure | Monolith equivalent | What the service version needs |
|---|---|---|
| Peer slow | A slow method call | Timeouts with budgets (summed across hops!) |
| Peer down | Exception, caught locally | Retry with backoff + idempotency keys, or circuit breaker |
| Peer deploys new contract | Nothing — one artifact | Versioned schemas, compatibility tests, rollout order |
| Partial result | Impossible in one ACID tx | Saga or compensation across services |
| Duplicate delivery | Not in scope | Dedup keys, at-least-once handling everywhere |
The timeout row is where designs die in production. Five chained calls with 2-second defaults give a user a 10-second worst case, and one hanging dependency takes the whole path with it — the cascading failure that motivates the resilience patterns you will meet later in this roadmap. The contract row is a permanent tax: schema evolution now requires compatibility testing (your producer and consumer are deployed at different times, forever), which is exactly the problem no monolith has.
Monitoring obligations multiply. One app means one latency chart, one error rate, one deploy timeline. Twelve services mean twelve of each, plus the question "why is checkout slow?" that now spans hops — which forces distributed tracing before you can debug your own system, plus correlation IDs propagated through every caller, plus log aggregation with a queryable service field. Alerting needs an owner per service, and on-call needs someone who understands a failure domain they may not have written.
There is a category teams forget: the testing and environment problem. End-to-end behavior now requires running (or virtualizing) every dependency. Contract tests and consumer-driven pacts mitigate it; they are real work, owned by someone. Add data consistency without shared transactions, secrets rotation across N services, capacity planning per service, and license/security scanning per artifact, and the list has stopped being about software design.
None of this argues against microservices — it argues for charging them to the decision. Write the list in the review, attach owners and estimates, and compare against the coordination cost you are trying to escape. When the coordination cost is real (teams waiting on a shared release train), the bill buys something. When it is hypothetical, you just purchased a platform team's salary to avoid a fifteen-minute sync.
Ready or Just Tempted: A Checklist Before the First Split
Readiness for microservices is not a technology stack; it is a set of conditions you can verify this month. A team that passes the checklist gets distribution to work for it. A team that fails it gets an expensive monolith — and the failures have recognizable names.
The readiness checklist. Each item is testable:
- A real deployment queue exists. Pull the last quarter of release data: are teams waiting on each other's release windows weekly? If deploys are painless and rare, the main benefit of services is unused.
- At least three to four stable teams (the classic two-pizza size) with capacity to own services end to end — code, deploy, pager — including when the author changes jobs.
- A platform seed exists: a service template that produces CI, health checks, dashboards, and a deploy target in under a day. If it takes two weeks to stand up service one, it will take two weeks again for service N.
- Boundaries have survived scrutiny: the candidate seams pass the co-change and invariant tests, not a hunch. This is why boundary analysis precedes the split — see Service Boundary Decomposition.
- Operational muscle: someone wants the pager, error budgets are agreed, and there is appetite for tracing and contract testing.
Failing items map to failure modes with familiar symptoms:
| Check failed | Six months later, you have |
|---|---|
| No deployment contention | A shared pipeline deploying all services in lockstep — the distributed monolith |
| Team too small to own N services | Services owned by nobody, on-call dread, fixes landing wherever the author is free |
| No platform template | Six bespoke snowflake setups, each slightly broken differently |
| Boundaries are a hunch | Two services co-changing weekly, joined by RPC calls and a joint release calendar |
| No tracing/contract discipline | "Checkout is slow, which dependency?" answered by logging into four boxes |
The small-team case deserves stating plainly because industry fashion hides it: small teams with infrequent releases usually ship faster as a well-structured monolith. Five engineers can hold the whole system in their heads; one deploy pipeline means one place to fix when CI breaks; a single database makes every feature a query instead of a choreography. Their velocity advantage over a microservice team of the same size is not marginal — the service team spends its first months on scaffolding the monolith team spends on product, and the gap often never closes because the scaffolding never stops.
Migration shape, when the checklist passes: keep the monolith as the spine, carve out one module where the trigger is loudest (the one with a scaling or cadence problem), run it in parallel behind the existing API, and measure whether the promised autonomy actually appeared — deploy frequency per team, lead time, incident blast radius. The measured result is the answer to give the next "should we split?" meeting: not an ideology, but your own trigger, your own bill, and a reversal condition written down before the first service exists. That is the whole discipline: microservices are a response to measured pain, not a milestone.
Quiz
1. A five-person team releases the whole product weekly, and feature work usually touches several modules. What does the decision analysis say?
2. Which cost is incurred by every service, regardless of how simple the service's code is?
3. Five chained service calls each carry a 2-second default timeout. What is the architectural problem and the first fix?
4. Which item is NOT part of a credible microservices readiness check?
Flashcards
Question
What two conditions must hold for microservices to pay for distribution?
Click to reveal answer
Answer
1) Independent deployment is genuinely needed — release data shows teams contending on a shared calendar; 2) Team autonomy is worth funding — enough stable teams to own services end to end (code, deploy, pager) with a platform template. If neither holds, the distribution bill buys nothing measurable.
Question
Name four per-service failure modes that do not exist in a monolith.
Click to reveal answer
Answer
Timeout/slow-peer policies in the request path (with summed deadline budgets), retry needing idempotency keys and duplicate delivery dedup, versioned-contract compatibility because producer and consumer deploy at different times, and partial failure requiring sagas instead of one ACID transaction. Plus the debug gap: 'why is it slow?' now spans hops and forces tracing.
Question
Why does co-change between candidate services argue against splitting them?
Click to reveal answer
Answer
Frequent co-change means the modules form one cohesive unit; separate services do not remove the required team coordination, they move it into versioned contracts, cross-service choreography, and joint deploys over a network — the distributed monolith's signature. Verify with git history before cutting.
Question
What is the 'platform tax' for the first service versus the Nth?
Click to reveal answer
Answer
Service one is a platform project: pipeline, runtime, secrets, dashboards, alerts, runbook, staging — often weeks. Service N reuses the template and lands in under a day. Teams that skip the template get six bespoke snowflakes and later rebuild the platform anyway, which is where 'we split and shipped nothing for three months' comes from.
Question
How do you measure whether a microservices split actually delivered?
Click to reveal answer
Answer
Compare before/after on the trigger you cited: deploy frequency per team, lead time from merge to production, incident blast radius (did one service's failure stay contained?), and whether release-coordination meetings disappeared. If contended deploys and joint releases persist, you built a distributed monolith and should merge back.
Revision Notes
Key Takeaways
- 1. Microservices are a response to measured pain: independent deployment must be needed and team autonomy must be worth funding, or distribution buys nothing
- 2. Every service carries a fixed bill — pipeline, network failure policies, contract compatibility, tracing, on-call — whether it does business logic or not
- 3. High co-change between candidate services means one cohesive unit; splitting it produces joint deploys over a network, i.e., a distributed monolith
- 4. A small team with infrequent releases ships faster as a well-structured monolith; the service team's scaffolding months are a real, often permanent, opportunity cost
- 5. Pass the readiness checklist before the first split — deployment contention, stable owning teams, a platform template, scrutinized boundaries — and measure the outcome against the trigger
Interview Tips
- • 'When would you use microservices?' — two conditions (independent deployment need, team autonomy worth paying for), then the bill, then the reversal condition; naming the exit is what separates analysis from fashion
- • 'How would you decide for our system?' — ask for release data and co-change evidence: who waits on whom, which modules change together; the answer comes from data, not from a stack preference
- • 'What is a distributed monolith?' — services that still deploy together and fail together: shared libraries in lockstep, synchronous chains, shared DB; you paid distribution and kept coordination
- • 'We are five engineers — should we split?' — no: show the scaffolding bill and the contention test; recommend a modular monolith with enforced boundaries and revisit when a trigger (scaling, cadence) is proven
Cheat Sheet
When Microservices Make Sense
Decision inputs (write answers down):
- Who must deploy independently of whom? (release data, not opinions)
- How often do changes cross module boundaries? (git co-change)
- Does one capability need different scale or failure isolation?
| Points to monolith | Points to services |
|---|---|
| 1–2 teams, rare/weekly releases | 4+ teams, multiple deploys/day demand |
| Features co-change across modules | Modules change independently in history |
| One scaling profile | One module needs 10× different resources |
| No platform/ops appetite | Platform template + on-call rotation exists |
Per-service bill: pipeline+runtime+secrets+dashboards+alerts+runbook+SLO+staging · network policies (timeout budgets, retries w/ idempotency, contract compatibility, sagas) · tracing/log correlation · contract testing + env topology.
Classic failure: split without a platform → snowflakes; split while co-changing → distributed monolith (joint deploys over a network); split with 5 engineers → scaffolding eats product time.
Migration shape: monolith stays spine → carve the one module with the loudest trigger → run parallel behind existing API → measure deploy frequency, lead time, blast radius.
Decision sentence template: 'we split X because