Microservices Architecture
Microservices architecture structures a system as independently deployable services aligned to business capabilities (bounded contexts), each owning its data and communicating via explicit contracts. This page focuses on the software architecture choice and requirements drivers — when to adopt, how to decompose, and when not to. For runtime patterns (discovery, resilience, scaling), see System Design → Microservices.
warning
| Driver | Why services help | Cost you accept |
|---|---|---|
| Multiple teams need autonomous release | Reduce release coupling | Cross-service versioning |
| Different scale/SLO per domain | Independent scaling & isolation | Ops complexity |
| Polyglot or specialized runtimes | Choose fit per service | Fragmented skills |
| Hard blast-radius isolation | Fault isolation by process | Partial failure modes |
| Regulatory data boundaries | Separate trust domains | Gateway & audit overhead |
- Team smaller than roughly two pizza teams with unclear domain boundaries.
- Domain still learning — boundaries will move weekly.
- You lack CI/CD, observability, and on-call maturity.
- Primary pain is messy code — distribution will not heal coupling.
- You need frequent cross-entity ACID transactions without a plan.
danger
Use domain-driven design heuristics: linguistic boundaries, data ownership, change frequency, and team ownership. Prefer splitting along seams you already modularized in a monolith.
Capability first
Billing, Identity, Catalog — not "ControllerService" or "UtilsService".
Data ownership
Each service owns its store; others use APIs/events — no shared tables.
Contract design
Versioned APIs; consumer-driven contracts where multiple consumers exist.
Transaction reality
Replace distributed ACID with sagas/outbox and explicit consistency models.
| Style | Use when | Watch out |
|---|---|---|
| Sync request/response | Need immediate answer; simple queries | Cascading latency/failures |
| Async events/messages | Decouple; fan-out; temporal independence | Eventual consistency |
| Async commands | Ask another service to do work | Ownership of retries/idempotency |
Prefer choreography or orchestration deliberately. Document consistency expectations in NFRs and user-visible UX (e.g., "payment pending").
- No shared writable database across services.
- Publish domain events for state changes others must know.
- Use outbox/inbox patterns for reliable publishing.
- Accept eventual consistency where requirements allow; reserve strong consistency for narrow local aggregates.
| 1 | In one DB transaction: |
| 2 | 1) Update order status = Paid |
| 3 | 2) Insert outbox row OrderPaid |
| 4 | Async publisher relays outbox → broker |
| 5 | Consumers update their own projections idempotently |
Microservices work best when team boundaries match service boundaries (Conway's Law as a tool). Stream-aligned teams own services end-to-end; platform teams provide paved roads; enabling teams coach. Misalignment — many teams editing one service, or one team owning twenty — recreates coupling.
| Topology smell | Architectural response |
|---|---|
| Many teams in one service | Split along team seams OR merge teams |
| One team, 30 microservices | Consolidate into fewer deployables |
| Ticket ping-pong for features | Wrong boundaries; redesign ownership |
- Modularize the monolith first; extract along proven seams.
- Establish platform baselines: CI templates, auth, observability, deployment.
- Start with one extraction that has a clear driver (scale or team).
- Invest in contract tests and progressive delivery before wide rollout.
- Track distributed tracing from day one of the first split.
| 1 | [ ] Drivers written (team/scale/SLO/compliance) |
| 2 | [ ] Bounded contexts identified with data ownership |
| 3 | [ ] Consistency model agreed with product for UX |
| 4 | [ ] Platform maturity sufficient (CI/CD, obs, on-call) |
| 5 | [ ] Modular monolith alternative considered |
| 6 | [ ] First extraction plan is incremental (strangler) |
| 7 | [ ] ADR approved with consequences |
- Nano-services: every class a network call.
- Shared libraries that force lockstep deploys across all services.
- Chatty sync call chains (A→B→C→D) without timeouts/bulkheads.
- Entity services ("CustomerService" CRUD only) with no business cohesion.
- Copying org chart poorly — accidental boundaries.
Microservices demand mature DevOps: independent pipelines, contract testing in CI, coordinated schema/event evolution, and clear ownership. Scrum-of-scrums or team-of-teams coordination focuses on contracts and shared goals — not centralized code approval for every change.
| SDLC concern | Microservice practice |
|---|---|
| Testing | Unit + contract + selective E2E |
| Release | Independent deploy + compatible contracts |
| Requirements | NFRs per service + cross-journey SLOs |
| Design | ADRs per service + platform standards |
| 1 | Identity — accounts, sessions, roles |
| 2 | Catalog — products, pricing read models |
| 3 | Checkout — cart, order placement |
| 4 | Payments — charges, refunds (PCI boundary) |
| 5 | Fulfillment — shipping, inventory reservations |
| 6 | Notify — email/push (consumes events) |
| 7 | |
| 8 | Sync: Checkout → Payments charge |
| 9 | Async: OrderPlaced → Fulfillment, Notify, analytics |
Each service adds: pipeline, dashboards, alerts, on-call surface, versioning, local-dev complexity, and failure modes. Budget platform investment before proliferating services. A useful heuristic: do not have more services than you can staff with clear owners and SLOs.
| Hidden cost | Mitigation |
|---|---|
| Local environment pain | Dev containers; narrow stubs; contracted fakes |
| Event versioning debt | Schema registry; compatibility tests |
| Orphan services | Ownership catalog; delete ruthlessly |
Community
Get help on Slack, Discord or VIP
Stuck on a guide? Join the community and ask.