The Eight Fallacies of Distributed Computing: An Architecture Review
Use the eight fallacies to question a distributed design through an illustrative checkout journey, explicit network assumptions and an architecture review worksheet.
Use the fallacies to find hidden assumptions
A diagram showing checkout, inventory and payments looks straightforward. Each connection hides a contract: how long the caller waits, whether a response proves a write happened, who authenticates whom and who owns a failure across teams.
The eight fallacies are a way to expose those assumptions before choosing implementation patterns. This is a conceptual architecture review, not a list of mandatory infrastructure components. A small system can address many of the risks by making fewer remote calls and keeping a transaction in one place.
The list hosted on James Gosling's site credits Peter Deutsch. In the historical account linked from that page, Arnon Rotem-Gal-Oz describes Deutsch's seven-item list and Gosling's later addition of network homogeneity. The labels below paraphrase the list; the checkout example and review questions are this article's application of it.
Follow one checkout across the boundaries
Consider an illustrative retailer. A browser asks the checkout API to reserve inventory, charge a payment method and create an order. Inventory and payment belong to different teams; payment also involves an external provider.
Inventory reserves the last unit. The provider accepts a charge, but the response is lost. Checkout times out. The customer retries while the inventory service is being redeployed. An old client also sends a price in a different currency format than the new API expects.
Nothing in that sequence requires every server to fail. Some actions succeeded, some results are unknown and some assumptions changed. Calling the entire request “failed” loses information the recovery process needs.
Delivery and timing: what does the caller actually know?
| Assumed | Impact | Review question | | --- | --- | --- | | Reliable delivery | A lost response hides a completed charge. | How does the caller discover an unknown outcome without creating a second charge? | | No travel time | Serial inventory and payment calls consume the response deadline. | Which calls must be serial, and what happens when the deadline expires? | | Unlimited capacity | A large request or replay competes with ordinary checkout traffic. | What payload, concurrency and backlog can each boundary accept? |
A timeout is a limit on waiting, not a transaction rollback. Assign a stable operation identifier before sending the request. Document which system can answer “did this operation happen?” and how long that answer remains available. This can require a reconciliation workflow rather than an immediate retry. AWS's guidance on idempotent APIs explains the relationship between caller intent and repeatable requests.
For a simple timing exercise, assume an observed trace spends 40 ms in the first remote round trip, 70 ms in the second and 30 ms in local processing. The serial path is 140 ms. Those are illustrative components of one trace, not measured service percentiles. Adding each service's p99 would not produce an end-to-end p99: the distributions and their correlations matter.
Batching can reduce round trips while increasing payload size, memory use and the cost of retrying a batch. Asynchronous processing can shorten the acknowledgement path, but now the product needs a pending state and a reliable way to show eventual completion. Neither is an automatic improvement.
Trust and change: which boundary moved?
| Assumed | Impact | Review question | | --- | --- | --- | | Implicit trust | Inventory accepts an unapproved caller. | What verifies the caller and permits the action? | | Fixed endpoints | A deployment or failover changes where requests should go. | How do clients refresh discovery and drain old connections? | | One operator | Checkout and payment teams change conflicting settings. | Who owns the API, incident response and notice of changes? |
Transport protection and application authorization have different jobs. TLS protects a connection when correctly configured; it does not decide whether a user may buy for another account. Mutual TLS can identify a workload, but application permissions and credential lifecycle still need owners. Select controls from the trust boundary and threat model rather than assuming that a private network is sufficient. NIST's Zero Trust Architecture explicitly separates trust from network location.
Discovery does not eliminate topology risk. DNS caching, long-lived connections, proxy routing and client retry behavior all influence how quickly a caller follows a new endpoint. Test a controlled endpoint replacement while requests are in flight.
For a cross-team API, record a decision-maker and an escalation backup. A shared repository alone does not ensure that the people changing a firewall, schema and client library know the same release constraints.
Cost and compatibility: what did the diagram leave out?
| Assumed | Impact | Review question | | --- | --- | --- | | Free transfer | Repeated remote reads add traffic, compute and support costs. | What data crosses each boundary and how will its cost be measured? | | Uniform behavior | Client versions disagree about currency, field presence or errors. | Which protocol and meaning changes must be supported? |
Bandwidth and transport cost overlap, but they are not interchangeable. A call can use little bandwidth and still incur connection, serialization, observability and operational overhead. Evaluate the whole request path before replacing readable JSON with a different format; changing serialization may miss the actual bottleneck.
Compatibility includes meaning. Both sides can parse a numeric field while disagreeing about whether it represents cents or dollars. A contract should state units, required fields, supported versions, error semantics and ownership of change. Test old and new clients against the same examples. “Use a standard protocol” is a starting point, not evidence of compatible behavior.
Turn the review into a small decision record
Pick one consequential operation, such as payment capture. Write down its business invariant first: one accepted purchase must not produce two intended captures. Then record these fields in the architecture decision:
- The authoritative system and operation identifier.
- The response deadline, unknown-outcome state and recovery owner.
- The dependency and payload limits, including overload behavior.
- Caller identity, authorization and credential rotation ownership.
- Endpoint-change and version-compatibility tests.
- Transfer and operational costs to observe before expansion.
For the illustrative checkout, the outcome could be a durable pending order, a stable payment operation key and reconciliation against the provider's operation status. That design still needs retention, deduplication and customer-support rules. A pending status cannot remain a permanent hiding place for unresolved money movement.
Exercise the uncertain outcome
Run one controlled test in which the provider accepts the operation but the caller loses the response. The caller should retain the same operation identity, query the authoritative status and avoid creating a second intended effect. Record who resolves a result that remains unknown after automated reconciliation.
Repeat the exercise during a dependency slowdown and while one consumer is on an older contract version. Verify that deadlines bound resource use, retries do not amplify overload, and the compatibility rule produces an explicit rejection or supported response. This small test exposes more than a diagram that assumes the network, timing and participants are reliable.
Retain the trace, operation record and reconciliation result as acceptance evidence. If the team cannot determine whether the effect occurred, keep the operation contained and assign a human resolution path before expanding traffic.
Use the failure-pattern guide to prepare recovery exercises and the resilience-pattern guide to compare controls. If the review reveals unclear transaction or service boundaries, an Ampity system architecture engagement can define the design, assumptions and acceptance criteria for that work.