Deployability and testing
Shipping services independently — contract tests, environments, progressive delivery, and what “done” means when the system is distributed.
Microservices only win if you can change one service without freezing the fleet. That is a delivery and testing problem as much as a design problem.
Independent deploy as a requirement
A service is not independently deployable if:
- it must ship with three others to keep contracts compatible
- migrations require downtime coordinated across teams
- “integration environment” is the only place truth is verified
Treat deploy independence as an acceptance criterion for the architecture, not a hoped-for side effect.
Test in layers
- Unit / component — domain rules and local adapters
- Contract tests — producer and consumer agree on API/event shapes
- Integration tests — real dependencies where risk is high (DB, broker), fakes elsewhere
- End-to-end — few critical journeys, not a mirror of the whole graph
E2E suites that boot every service for every PR become the new monolith. Prefer narrow e2e plus strong contracts.
Progressive delivery
Ship safely with:
- automated pipelines per service
- backward-compatible migrations (expand/contract)
- canaries or weighted rollout
- fast rollback (including data-compatible rollback plans)
Blue/green and canaries do not help if a breaking schema ships underneath them.
Environments that tell the truth
Shared staging that nobody trusts is expensive theater. Prefer:
- ephemeral environments for PRs where feasible
- contract verification in CI
- production-like observability in lower envs for the paths that matter
What “done” means
A change is done when:
- it is in production (or safely behind a flag)
- dashboards and alerts cover the new failure modes
- consumers were considered — and migrated or left compatible
- runbooks mention the new behavior
In a distributed system, merging to main is the middle of the story, not the end.