Service boundaries and distributed state
What makes a boundary, why network calls are different, and the fallacies that keep producing outages.
Service boundaries and distributed state
A service boundary is where your process ends and someone else's begins โ different deployment, different failure domain, different upgrade schedule. Once a call crosses one, every assumption changes:
| In-process call | Cross-network call | |---|---| | failure = exception | failure = exception OR timeout OR partial result OR silence | | latency = ns | latency = ms, variable, occasionally seconds | | memory is coherent | the remote state moved on without you | | transactions work | distributed transactions are a research paper |
The eight fallacies of distributed computing remain the best debugging checklist: the network is reliable; latency is zero; bandwidth is infinite; the network is secure; topology doesn't change; there is one administrator; transport cost is zero; the network is homogeneous. Every production outage story includes at least one fallacy being violated.
The boundary design rules that follow:
- A boundary needs a contract โ versioned, explicit, with failure semantics documented ("this endpoint may return 503; treat 503 as retry-safe").
- Remote state is only a hypothesis. Your cache, your read model, the response you got 200ms ago โ all may be stale. Design reads that can tolerate staleness or declare that they cannot.
- No synchronous chains. AโBโCโD synchronous calls compound latencies and failure rates multiplicatively (0.99โด โ 0.96). Async messaging or pre-computation beats deep chains.
- The boundary owns its failures. Callers get domain errors, not stack traces from your database.
This module simulates boundaries deterministically in-process โ but the failures simulated (duplicate delivery, stale reads, retry amplification) are the real ones, miniaturized until they are testable in milliseconds.