Source · Software Architecture: The Hard Parts (O'Reilly) and Communication Patterns (O'Reilly)
Why this matters
Software Architecture: The Hard Parts, Communication chapters; Communication Patterns (O'Reilly)The moment a system is split across process boundaries, how its parts talk to each other becomes an architectural decision with lasting consequences. Choose synchronous calls everywhere and you couple services in time — one slow dependency stalls the whole chain. Choose asynchronous messaging without care and you trade that for complexity in ordering, error handling, and eventual consistency.
Communication patterns govern coupling, resilience, and the shape of business workflows. Getting them right is often the difference between a distributed system that degrades gracefully and one that fails as a unit.
The concept
Software Architecture: The Hard Parts, Ch. 12-13; Communication PatternsSynchronous communication means the caller sends a request and blocks, waiting for a response — it needs the callee available now and couples the two in time. Asynchronous communication means the caller sends a message and continues without waiting; the receiver processes it later, decoupling availability but introducing eventual consistency.
For coordinating a workflow that spans services, two styles compete. Orchestration uses a central coordinator (an orchestrator) that explicitly directs each step and holds the workflow logic — easy to reason about, but the orchestrator becomes a hub of coupling. Choreography has no central brain: each service reacts to events emitted by others, so logic is distributed and services stay loosely coupled, at the cost of harder end-to-end visibility.
When a business transaction spans multiple services and cannot use a single ACID transaction, a saga coordinates it as a sequence of local transactions, each with a compensating action that semantically undoes it if a later step fails. Sagas can themselves be orchestrated or choreographed.
Underpinning all of this are contracts — the agreed shape of messages and APIs between services. Contracts range from strict (tightly specified, e.g. a rigid schema) to loose (minimal, tolerant of change), a choice that trades safety against evolvability.
Worked scenario
Software Architecture: The Hard Parts, Ch. 12 (Sagas)An e-commerce checkout must reserve inventory, charge payment, and create a shipment across three services. A single database transaction is impossible, so the team models it as a saga.
In an orchestrated saga, a Checkout Orchestrator calls Reserve Inventory, then Charge Payment, then Create Shipment. If Create Shipment fails, the orchestrator invokes compensating actions — Refund Payment and Release Inventory — to unwind the work. All workflow logic lives in one visible place.
In a choreographed alternative, Inventory emits an 'InventoryReserved' event, Payment reacts and emits 'PaymentCharged', Shipping reacts to that; a failure triggers compensating events flowing backward. No central coordinator exists, so services couple only to events — but tracing 'what happened to order 42' now requires correlating events across services.
The payment call itself might be synchronous (block for authorization) while shipment creation is asynchronous (fire a message, confirm later), and each inter-service message adheres to a versioned contract so a change on one side does not silently break the other.
How it connects
Software Architecture: The Hard Parts, Ch. 13; Building Evolutionary Architectures 2eCommunication patterns are where DDD's context boundaries become runtime integrations — a context map's relationship becomes a synchronous call or an event stream with a contract. They are the connective tissue of The Hard Parts' distributed transactions and data decomposition.
The coupling introduced by an orchestrator or a strict contract is exactly what Architecture Metrics measures (afferent/efferent coupling), and what evolutionary fitness functions can guard — for example, a contract test that fails the build when a producer breaks a consumer's expectations.
- Equating asynchronous with 'better' or 'faster'. Async decouples availability and improves resilience but adds eventual consistency, ordering, and error-handling complexity; sync is simpler when the call is genuinely needed now.
- Confusing orchestration with a saga. Orchestration vs choreography is a coordination style; a saga is a pattern for managing a multi-service transaction. A saga can be implemented either way.
- Assuming a saga rolls back like a database transaction. It cannot undo committed local transactions; it issues compensating actions that semantically counteract them, which may not restore the exact prior state.
- Synchronous couples caller and callee in time (blocking); asynchronous decouples availability at the cost of eventual consistency.
- Orchestration centralizes workflow logic in a coordinator; choreography distributes it via events — trading visibility for looser coupling.
- A saga manages a distributed transaction as local transactions plus compensating actions, and can be orchestrated or choreographed; contracts govern the agreed message shape.