A team is splitting a service and discovers the split would break a transaction. What are the options, and which is usually right?
Show the full answer Hide the answer
What the discovery means
It is evidence about the boundary, not merely an obstacle. A transaction spanning two proposed services means the two parts share an invariant, and shared invariants are the strongest possible signal that a boundary is in the wrong place.
The options
- Do not split there. Move the boundary so the invariant is contained. This is correct far more often than it is chosen, because the proposed split usually came from a domain-modelling exercise rather than from the invariants.
- Split, and accept eventual consistency with a saga. Correct when the invariant is genuinely a business process rather than a data constraint — a booking and a payment can be separate with compensation, because the business already has a concept of a failed booking. Trades atomicity for availability, and the currency of that trade is user-visible intermediate state, which must be designed into the product rather than treated as an anomaly.
- Split, and use a workflow engine for durable orchestration, which makes the saga's state, retries, timers and compensation someone else's implementation. Worth it when such workflows are numerous, long-running and expensive to get wrong.
- Split the code and share the database temporarily. The worst option and the most commonly taken — all the deployment complexity of services with none of the independence, and the shared schema remains a coupling point that makes both worse.
How to decide
Ask whether the invariant is a data constraint or a business process.
A data constraint — a balance may not go negative, stock may not be oversold — must be enforced transactionally, and the boundary must contain it. A business process — a booking with a payment and a notification — has a natural concept of partial completion and compensation, and can be a saga.
Confusing the two produces either an unnecessary distributed transaction or a correctness bug, and the distinction is a domain question that engineering cannot answer alone.
The default
When in doubt, do not split. A boundary in the wrong place is expensive to move across a network and cheap to move inside a process — so the cost of waiting is low and the cost of being wrong is high.