advanced 2 min answer

A team is splitting a service and discovers the split would break a transaction. What are the options, and which is usually right?

temporalboundariestransactionssagainvariants
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.