Patterns by the problem they solve
Patterns rarely work alone. A Saga needs reliable messaging, and a Circuit Breaker works best with timeouts and retries that are tuned to match. Start with the map, then open any pattern.
How the patterns connect
Where do the boundaries go?
How to split a system into services and migrate toward them without a big-bang rewrite.
Decompose by Subdomain
Draw service boundaries around business subdomains, not technical layers or database tables.
Strangler Fig
Replace a monolith gradually by routing one slice of functionality at a time to new services.
Decompose by Business Capability
Give each thing the business does (pricing, booking, payments) its own service and team.
Self-Contained Service
Answer requests without waiting on other services, by keeping a local copy of the data you need.
Who owns the data, and how does it stay consistent?
How services own their data and still deliver business outcomes that span several of them.
Database per Service
Each service owns its data. Everyone else reaches it through the service's API or events.
Shared Database
Several services read and write the same database. Simple at first, and the main thing that stops services being independent.
Saga
Run a multi-service business transaction as local transactions plus compensating actions.
Transactional Outbox
Save the data change and the event it must produce in one local transaction, then publish from that table.
API Composition
Answer a query that spans services by calling each one and combining the results.
CQRS
Use one model to handle commands that change state and separate read models built for the queries you need.
Event Sourcing
Store every state change as an immutable event and derive the current state by replaying them.
Change Data Capture
Turn every committed database change into an event by reading the database's own transaction log.
How do clients and services talk?
How requests and messages move between clients, gateways and services.
API Gateway
One entry point that routes, secures and shapes client requests to the services behind it.
Asynchronous Messaging
Let services talk through a broker with commands and events instead of waiting on each other.
Backend for Frontend
Give each kind of client its own small backend, shaped for its screens and owned by its team.
Idempotent Consumer
Make processing the same message twice have the same effect as processing it once.
Dead Letter Queue
Move a message that keeps failing out of the way, so it stops blocking the rest and someone can look at it.
Asynchronous Request-Reply
Accept a long-running request right away, and let the client check back for the result.
Access Token Relay
Authenticate the user once at the edge, then pass a signed token along so each service can check it locally.
What happens when a dependency fails or slows down?
How to keep serving users when parts of the system are broken, slow or overloaded.
Retry with Backoff and Jitter
Retry transient failures with growing, randomised delays, a cap and a budget.
Timeout
Never wait forever on a remote call. Decide how long a call may take, and stop waiting after that.
Circuit Breaker
Stop calling a failing dependency for a while, fail fast, and probe to see when it has recovered.
Bulkhead
Give each dependency or workload its own resources so one failure cannot use up everything.
Rate Limiting
Cap how many requests a client may make in a period, and reject the rest early and cheaply.
How do we see what the system is doing?
How to understand behaviour that is spread across many processes and machines.
Log Aggregation
Collect logs from every instance into one searchable place, with the context to connect them.
Application Metrics
Measure request rate, errors and latency in every service, and alert on what users actually feel.
Distributed Tracing
Follow one request across every service it touches using a shared trace ID.
How do we ship and run it?
How cross-cutting runtime concerns are packaged and operated across many services.
Health Check API
Expose endpoints that tell the platform whether an instance is alive and whether it is ready for traffic.
Externalized Configuration
Keep configuration and secrets out of the build, and supply them to each environment at runtime.
Sidecar
Run a helper process beside each service instance to handle shared runtime concerns.