Overview
Microservice architecture splits a system into small, independently deployable services, each owning its data and aligned with a business capability. The prize is independent deployment and team autonomy; the price is turning in-process calls into a distributed system with all its failure modes. The honest framing (Fowler, Newman): you must be this tall — mature CI/CD, observability, and ops — before the trade is worth it, and a well-modularized monolith is the right starting point more often than not.
Key points
- Boundaries are the whole game: services should map to bounded contexts (DDD); get boundaries wrong and you build a distributed monolith — the worst of both worlds.
- Database per service: no shared database; data crosses boundaries via APIs and events, consistency becomes eventual (async patterns, sagas, outbox).
- Communication: sync (REST/gRPC, simple but couples availability) vs. async (events, decoupled but harder to reason about); API gateway and service discovery at the edges; contract testing to keep independence real.
- Deployment & ops: one service = one pipeline; containers + orchestration; observability (distributed tracing, correlation IDs) is non-optional because no single log tells the story.
- Organizational mirror: Conway's law works both ways — team ownership per service is the point ("you build it, you run it").
- Alternatives on the spectrum: modular monolith, and the middle grounds (moduliths, self-contained systems); migration via strangler fig, not big bang. The house position is to start as a modulith and keep extraction mechanical — see modulith & microservices.
- To explore: service mesh, serverless as the extreme of the same axis, micro-frontends as the front-end analogue.
Details
The boundary tax
A boundary in a distributed system is not free. Every boundary buys you independent deployment and independent scaling, and charges you for it in serialisation, network transfer, orchestration state, request volume and failure handling [1]. Prime Video's own team found this the hard way: a serverless, heavily-decomposed pipeline was redesigned into a monolith and cut cost by ~90%, because the fan-out of boundaries was charging orchestration and data-transfer costs the workload didn't need. The lesson isn't "monoliths win" — it's that each boundary should be bought deliberately (per an operational trigger, not aesthetics — see modulith & microservices), not inherited from a reference architecture.
Practice
- Saga, twice (source) — implement an order/payment saga as choreography, then as orchestration, with a compensating action for every failure point; the trade-off writes itself.
- FTGO application (source) — Richardson's reference implementation: trace one service's boundaries, then add a small feature end to end — API, events, saga.
- Strangler fig migration (source) — carve one bounded context out of a monolithic side project behind a routing facade, without breaking the rest.
- Build the edge (source) — the gateway tier every service system needs — load balancing, health checks, per-key limits — built from scratch.
Related
- DDD — supplies the decomposition principle.
- Hexagonal architecture — sound internal structure for each service.
- Modulith & microservices — the starting point on this spectrum and the mechanics of moving along it in both directions.
- Asynchronous and distributed system patterns
- System design fundamentals
- API design — the contract discipline service independence rests on.
- Coupling & cohesion — the framework for judging whether a service boundary is in the right place.
- Observability & SRE practice — the operational prerequisite; correlation & context propagation is the part every service boundary multiplies.
- Team topologies & Conway's law — the organizational mirror, in full.
Citations
[1] Prime Video cut costs 90% by deleting its serverless architecture, then the post vanished