الدرس 1 من 2
Independent Deployability, and What It Costs
A microservice is defined by one property, and everything difficult about the style follows from it. The prerequisites are organisational as much as technical.
Definitions of microservices usually involve size, and size is the least useful attribute. A service is not small or large; it is independently deployable. If you can release it without releasing anything else, it is a service. If you cannot, it is a module that happens to have a network interface, and you are paying for distribution without receiving it.
Independent deployability requires several things at once, and each of them is where the cost lives. The service must own its data, or a shared schema forces coordinated releases. It must tolerate its dependencies being unavailable or an old version, or the deployment order returns. Its interface must be versioned so consumers are not broken. And someone must be able to operate it in production, which is where the organisational cost appears.
| Capability | Why it becomes necessary | Typical cost |
|---|---|---|
| Independent deployment pipeline | The service must release without the others | Templated after the first, but each has its own failures |
| Distributed tracing | A request now crosses several processes and no single stack trace exists | A tracing backend, plus propagation in every service and client |
| Centralised structured logging | Correlating an incident across services is otherwise impossible | Log aggregation, retention cost, and a correlation identifier everywhere |
| Contract versioning and testing | A consumer must not break when a provider deploys | Consumer-driven contract tests and a deprecation policy |
| Resilience at every call site | Any dependency can be slow, down, or return twice | Timeouts, retries, idempotency keys, circuit breakers, fallbacks |
| Service-level ownership and on-call | A service without an owner degrades and nobody notices | A rotation per service or per team, which is a staffing decision |
| Data consistency without transactions | A business operation now spans several stores | Sagas, compensations, and eventual consistency in the product design |
The distributed monolith, in more detail
Chapter 1 introduced this as a failure mode. It deserves a second look here because it is the outcome of most unsuccessful splits, and because it is recognisable early — usually within the first two extractions, long before anyone admits it.
- 1**A required deployment order.** The single clearest symptom. If a runbook says which service goes first, they are not independently deployable and the whole cost is being paid for nothing.
- 2**A shared database.** Two services writing the same tables cannot change schema independently, which removes independent deployment mechanically rather than culturally.
- 3**Synchronous call chains.** A request that traverses four services synchronously has the availability of the product of all four and the latency of their sum, and the failure of any one fails the request.
- 4**Shared libraries carrying business rules.** A rule change now means releasing the library and every service that uses it, in order. Shared *technical* libraries are fine; shared *domain* libraries recreate the coupling.
- 5**Cross-service transactions attempted with two-phase commit.** Usually a sign the boundary is in the wrong place: the operation is one unit of work and the split cut through it.
In practice
Buying independence that was actually needed
A payments company had one modular monolith and a genuine problem: its card-authorisation path had a 99.99% availability commitment written into merchant contracts, while the rest of the system — reporting, merchant onboarding, dispute handling — had no such requirement and was deployed several times a day.
Constraints
- Authorisation must survive the failure of every other component
- Contractual 99.99% availability on authorisation only
- Other components deploy 5 to 10 times a day
- Team of 45 across six squads, with an existing platform team
Decision
Extract card authorisation into its own service with its own datastore, its own deployment pipeline and its own on-call rotation. Leave everything else in the modular monolith.
Why
The justification was a differing availability requirement, which is one of the four strong signals: frequent deployments of unrelated features were a standing risk to a contractual guarantee. Isolating the authorisation path meant a bad reporting release could no longer affect it, and the authorisation service could adopt a slower, more careful release process appropriate to its risk.
What it cost
Authorisation can no longer read merchant configuration in the same transaction, so it keeps a locally cached projection updated by events — which is up to a few seconds stale, and the team had to design what happens when a merchant is disabled during that window. They chose to fail closed on the authorisation side, accepting a small number of incorrectly declined transactions over any risk of authorising for a disabled merchant, and documented that choice where the support team could find it.
Estimating a microservices migration
As a developer
Estimates the work: splitting the code, defining the interfaces, setting up pipelines, migrating the data. That estimate is usually reasonable for the work it covers.
As an architect
Adds the permanent costs that are not in the estimate because they are not a project: an ongoing platform capability, on-call rotations, contract testing, tracing, and the product work of designing for eventual consistency in specific flows. Those typically consume between 5% and 15% of engineering capacity forever, and leaving them out is what makes migrations arrive late and disappoint. Saying it plainly at the start is far better received than discovering it in month nine.
A team has extracted three services. Each has its own repository, its own pipeline and its own team, but all three read and write the same PostgreSQL schema. Do they have microservices?RevealHide
No. They have three deployables and one system. Any schema change requires all three to be updated and released together, so the defining property — deploying one without coordinating with the others — does not hold, and they are paying network latency, serialisation, distributed debugging and three pipelines to receive nothing in return. The repositories, pipelines and teams are all real and all beside the point. The path forward is to decide which service owns which tables and give the others an interface — an API, events, or a maintained read model — and it is worth being honest that this is the expensive half of the work they thought they had finished.
Key takeaways
- A microservice is defined by independent deployability; size, repository count and team structure are consequences.
- The property requires owned data, tolerant dependencies, versioned contracts and an owner who can operate it.
- The prerequisites are organisational as much as technical, and are the part most often left out of estimates.
- A required deployment order or a shared database means you have a distributed monolith regardless of the diagram.
- The remedy for a distributed monolith is usually to merge and re-split along contexts, not to split further.