Chapter 2: Discerning Coupling in Software Architecture

saht coupling architecture-quantum static-coupling dynamic-coupling distributed-systems

Status: Notes complete


Overview

Chapter 2 provides the foundational vocabulary for the rest of the book. Before you can reason about how to split a system, you must be able to reason about how its parts are connected — and with what kind of connection. The chapter introduces coupling not as a binary (coupled vs. decoupled) but as a multi-dimensional property with distinct types, each carrying different implications for architecture.

The central conceptual innovation is the architecture quantum: a rigorously defined unit of architecture that serves as the smallest independently deployable unit with high functional cohesion. Unlike a service or a component, a quantum captures not just code boundaries but also data ownership and the forces that bind pieces together. This unit of analysis recurs throughout the book as the primary lens for evaluating decomposition decisions.

The chapter also introduces a three-axis model of dynamic coupling — the coupling that emerges at runtime when components communicate. By separating communication style (synchronous vs. asynchronous), consistency model (atomic vs. eventual), and coordination style (orchestrated vs. choreographed), the authors create an eight-combination space that exhausts the major architectural options for inter-service communication. Understanding where a system sits in this space — and why — is the prerequisite for all the decomposition and restructuring discussions in later chapters.


Core Concepts

Coupling: A measure of how dependent one component is on another. Coupling is not binary — it varies in type, strength, and direction. High coupling makes components harder to change independently; low coupling increases modularity and independent deployability.

Architecture quantum: The smallest unit of architecture that has high functional cohesion and is independently deployable. A quantum has its own high static coupling (it includes everything it needs to function), high functional cohesion (its parts work together toward a unified purpose), and independent deployability (it can be deployed without deploying other quanta).

Static coupling: The coupling that exists at build/compile time — the structural dependencies between components (imports, libraries, shared schemas). It is visible in the dependency graph.

Dynamic coupling: The coupling that exists at runtime — how components communicate, what consistency they require, and how they coordinate. It is not visible in the static dependency graph.

Afferent coupling: The number of classes/components that depend on a given component. High afferent coupling means many things depend on you — you are important and hard to change.

Efferent coupling: The number of classes/components that a given component depends on. High efferent coupling means you depend on many things — you are fragile, because any of your dependencies can break you.

Connascence: A refinement of coupling vocabulary. Two components are connascent if changing one requires changing the other. Can be static (connascence of name, type, meaning, algorithm) or dynamic (connascence of execution, timing, value, identity).


Architecture Quanta

Definition

The architecture quantum is one of the most important original contributions of the book. It refines the notion of a “service” or “component” into something more precise and analytically useful.

An architecture quantum is:
  ┌─────────────────────────────────────────┐
  │  High Functional Cohesion               │
  │  (parts work together for one purpose)  │
  │                                         │
  │  + Independently Deployable             │
  │  (can deploy without other quanta)      │
  │                                         │
  │  + High Static Coupling                 │
  │  (includes all it needs to function)    │
  └─────────────────────────────────────────┘

Importantly, high static coupling is a feature, not a bug within a quantum. A quantum is supposed to contain everything it needs — tight internal coupling is what makes it independently deployable. The problem is coupling between quanta, not within them.

Quanta in Different Architecture Styles

Architecture StyleTypical Number of Quanta
Monolith1
Modular monolith1 (unless UI is separate)
Microservices (fine-grained)Many (1 per service ideally)
Service-based architectureSeveral (1 per coarse-grained service)
Event-driven architectureVaries — depends on consumer/producer boundaries

Why Quanta Matter

The quantum is the unit at which you can make independent deployment decisions. If two services must always be deployed together (because one’s API change requires the other to update simultaneously), they are effectively one quantum even if they run in separate processes.

The quantum concept explains why microservices are not automatically independent: if Service A calls Service B synchronously and depends on B’s response to complete its own operation, A and B are dynamically coupled even if they are statically separate. Under failure conditions, they behave as a single unit.

Single-Quantum vs. Multi-Quantum Architectures

Single Quantum (Monolith):
  ┌──────────────────────────┐
  │  UI + App + DB           │  ← All one deployable unit
  └──────────────────────────┘
  Benefit: Simple transactions, simple deployment
  Cost: No independent scaling, team coupling

Multi-Quantum (Microservices):
  ┌────────┐  ┌────────┐  ┌────────┐
  │  Q1    │  │  Q2    │  │  Q3    │
  │ Order  │  │Payment │  │Shipping│
  └────────┘  └────────┘  └────────┘
  Benefit: Independent deployability and scaling
  Cost: Distributed systems complexity

Static Coupling

Afferent and Efferent Coupling

Afferent coupling (Ca) — incoming dependencies — tells you how important a component is. If many things depend on you, you are central; changing you requires changing many other things.

Efferent coupling (Ce) — outgoing dependencies — tells you how fragile a component is. If you depend on many things, any of those things failing or changing can break you.

Instability metric: I = Ce / (Ca + Ce)
  I = 0 → Maximally stable (many dependents, no dependencies)
  I = 1 → Maximally unstable (many dependencies, no dependents)

Desired direction of coupling:
  Stable ←── Unstable
  (unstable components should depend on stable ones,
   not the other way around)

Types of Static Coupling in Distributed Systems

Coupling TypeDescriptionExample
Shared libraryServices share a compiled libraryCommon data transfer objects (DTOs)
Shared databaseServices read/write the same database/schemaLegacy monolith pattern
Shared schemaServices consume the same message schemaEvent-driven systems
API contractService A depends on Service B’s interfaceREST/gRPC calls

Shared database is the most dangerous form of static coupling in distributed architectures: it makes it impossible to evolve a service’s data model independently, and it couples deployment — a schema change in one service’s tables can break another service that shares the database.

Coupling and Independent Deployability

The relationship between static coupling and independent deployability is direct:

More static coupling between quanta
  → More coordination required for deployment
    → Less independent deployability
      → Larger effective deployment unit
        → Higher risk per deployment
          → Less frequent deployment
            → Slower feedback loops

This cascade is why the authors treat reducing inappropriate static coupling between quanta as one of the highest-priority concerns in distributed architecture design.


Dynamic Coupling

Static coupling is visible in code and dependency graphs. Dynamic coupling is the coupling that emerges at runtime — it cannot be read from the source code alone. It is determined by three orthogonal dimensions:

The Three Dimensions of Dynamic Coupling

         COMMUNICATION             CONSISTENCY              COORDINATION
         ─────────────             ───────────              ────────────
         Synchronous               Atomic                   Orchestrated
             vs.                      vs.                       vs.
         Asynchronous              Eventual                 Choreographed

Each dimension is an independent binary choice, producing 2 × 2 × 2 = 8 possible combinations of dynamic coupling style.


Dimension 1: Communication — Synchronous vs. Asynchronous

Synchronous communication: The caller waits for a response before proceeding. The caller is blocked during the call.

Caller ──── request ────► Service
Caller ◄─── response ─── Service
(caller blocked during round trip)

Asynchronous communication: The caller sends a message and continues. The response (if any) arrives later via callback, event, or polling.

Caller ──── message ────► Queue/Broker
Caller continues executing...
                          Queue/Broker ──► Service
Service ──── response ──► Queue/Broker (optional)
Caller ◄──── response ─── Queue/Broker (optional)
SynchronousAsynchronous
Coupling strengthHigh — caller depends on callee availabilityLow — decoupled by queue
LatencyAdditive — caller waits for each hopNon-additive for caller
Error handlingImmediate — caller gets errorComplex — need dead-letter queues, idempotency
ThroughputLimited by slowest serviceCaller unblocked; services process at own rate
Data freshnessImmediate responsePotentially stale
DebuggingEasier — clear request/response trailHarder — distributed trace spans multiple systems

Dimension 2: Consistency — Atomic vs. Eventual

Atomic consistency: All operations in a transaction either all succeed or all fail together. At any point, all consumers see the same state.

Eventual consistency: Updates propagate asynchronously; at any given moment different parts of the system may have different views of the data. The system will converge to consistency eventually, but there is a window of inconsistency.

Atomic consistency:
  Write → All reads immediately see new value
  [Requires distributed coordination — expensive]

Eventual consistency:
  Write → Reads may see old or new value
          for an indeterminate period
          → Eventually all reads see new value
  [No coordination required — cheaper, more available]
AtomicEventual
CorrectnessStrong — all nodes agree at all timesWeak — temporary divergence allowed
AvailabilityLower — requires coordination (locks, 2PC)Higher — no coordination required
PerformanceLower — coordination overheadHigher — no blocking
ComplexityLower for developers (familiar ACID model)Higher — must handle conflict resolution, idempotency
Failure handlingSimpler — rollbackComplex — compensating transactions

Dimension 3: Coordination — Orchestrated vs. Choreographed

Orchestrated coordination: A central orchestrator (often called a saga orchestrator or workflow engine) directs all participants, tells each one what to do and when, and handles failures centrally.

Orchestrated:
         ┌──────────────┐
         │ Orchestrator │
         └──────────────┘
         /      |       \
        ↓       ↓        ↓
  ┌───────┐ ┌───────┐ ┌───────┐
  │ Svc A │ │ Svc B │ │ Svc C │
  └───────┘ └───────┘ └───────┘
  (Orchestrator knows the workflow)

Choreographed coordination: Each service knows what to do based on events it receives. No central coordinator exists; behavior emerges from the reactions of individual services.

Choreographed:
  ┌───────┐ ──event──► ┌───────┐ ──event──► ┌───────┐
  │ Svc A │            │ Svc B │            │ Svc C │
  └───────┘            └───────┘            └───────┘
  (Each service reacts to events; no central control)
OrchestratedChoreographed
CouplingServices coupled to orchestratorServices coupled to event schema
Workflow visibilityHigh — orchestrator knows the whole workflowLow — workflow is implicit in event chains
Error handlingCentralized — orchestrator manages compensationDistributed — each service must handle its own failures
FlexibilityLower — workflow changes require orchestrator updatesHigher — services can be added/removed without changing others
ComplexitySimpler for complex workflowsCan become chaotic (“choreography hell”)
TestabilityEasier — test the orchestratorHarder — must simulate full event chains

The 8 Combinations

All eight combinations of (Sync/Async) × (Atomic/Eventual) × (Orchestrated/Choreographed) are possible, though some are more common and more coherent than others:

#  Comm        Consistency  Coordination   Typical Use Case
─  ────────    ───────────  ─────────────  ─────────────────────────────────────
1  Sync        Atomic       Orchestrated   Traditional SOA, distributed monolith
2  Sync        Atomic       Choreographed  Rare — sync choreography is unusual
3  Sync        Eventual     Orchestrated   Orchestrator reads stale data
4  Sync        Eventual     Choreographed  Rare — inconsistent coordination
5  Async       Atomic       Orchestrated   Saga pattern with orchestrator (most common in microservices)
6  Async       Atomic       Choreographed  Saga pattern with choreography (events + compensation)
7  Async       Eventual     Orchestrated   Event-driven with central saga manager, eventual reads
8  Async       Eventual     Choreographed  Pure event-driven architecture (e.g., event sourcing + CQRS)

The most common production patterns:

  • Combination 1 (Sync/Atomic/Orchestrated): Easy to reason about but creates strong temporal coupling; the “distributed monolith” anti-pattern often emerges here.
  • Combination 5 (Async/Atomic/Orchestrated): The saga orchestrator pattern — the most common approach to distributed transactions in microservices.
  • Combination 8 (Async/Eventual/Choreographed): Pure event-driven — maximum decoupling, maximum operational complexity.

Coupling and the CAP Theorem

The dynamic coupling choices map directly onto the CAP theorem’s constraints:

  • Atomic consistency requires distributed coordination — it sacrifices availability or partition tolerance depending on how it is implemented.
  • Eventual consistency allows availability and partition tolerance at the cost of consistency (by CAP’s definition).
  • Synchronous communication creates a hidden form of availability coupling: if Service B is unavailable, Service A cannot complete its operation.
  • Asynchronous communication breaks this availability coupling at the cost of increased latency and complexity.

Architects must understand that choosing atomic consistency in a distributed system is not just a correctness decision — it is an availability and performance decision with system-wide implications.


Connascence in Distributed Systems

Connascence (a vocabulary from the 1990s, revived in SAHT) provides a more nuanced vocabulary for coupling than simple “high/low”:

Static Connascence (in source code)

  • Connascence of Name (CoN): Multiple components agree on a name (method name, field name). Weakest form.
  • Connascence of Type (CoT): Components agree on a type.
  • Connascence of Meaning (CoM): Components agree on the meaning of a value (e.g., 1 = active, 0 = inactive).
  • Connascence of Algorithm (CoA): Components must implement the same algorithm (e.g., same hashing function).

Dynamic Connascence (at runtime)

  • Connascence of Execution (CoE): Order of execution matters between components.
  • Connascence of Timing (CoT): Timing of execution matters.
  • Connascence of Values (CoV): Multiple values must change together (e.g., related fields in different services).
  • Connascence of Identity (CoI): Multiple components must reference the same entity instance.

In distributed systems, connascence of values and connascence of identity are the most dangerous forms — they require cross-service coordination that is expensive and failure-prone.


Trade-off Summary

Static Coupling Trade-offs

Coupling TypeLow Coupling (good)High Coupling (bad)
Between quantaIndependent deployability, evolutionaryCoordination overhead, deployment coupling
Within quantumHigh cohesion, fewer network calls— (desired, within limits)
Shared DBSchema evolution coupling, deployment coupling
Shared libraryCode reuseVersion coupling, ripple effects

Dynamic Coupling Trade-offs

StyleBenefitsCosts
SynchronousSimple, immediate consistencyTemporal coupling, cascading failures
AsynchronousDecoupled, resilientComplex error handling, eventual consistency
AtomicStrong correctness guaranteesPerformance cost, coordination overhead
EventualHigh availability, high performanceDeveloper complexity, conflict resolution
OrchestratedVisible workflow, central error handlingOrchestrator is a single point of failure/change
ChoreographedFlexible, decoupledInvisible workflow, distributed error handling

Decision Framework

Choose synchronous communication when:

  • The caller genuinely needs the result before proceeding
  • Latency budget allows for blocking
  • The callee is highly available and fast

Choose asynchronous communication when:

  • The caller does not need an immediate result
  • Resilience to callee unavailability is important
  • Throughput matters more than individual request latency

Choose atomic consistency when:

  • Operations must be all-or-nothing (financial transactions, inventory)
  • Data correctness is non-negotiable
  • The performance/availability cost is acceptable

Choose eventual consistency when:

  • Temporary inconsistency is tolerable
  • High availability is more important than strong consistency
  • The system operates at a scale where coordination is prohibitively expensive

Choose orchestration when:

  • The workflow is complex and must be visible
  • Centralized error handling and compensation is required
  • Workflow changes are infrequent

Choose choreography when:

  • Services must be maximally decoupled
  • The system needs to support adding/removing services without changing others
  • Workflows are relatively simple

Identify quantum boundaries by asking:

  1. Can this component be deployed without deploying these other components?
  2. Does this component share a database with these other components?
  3. Does this component fail or succeed as a unit with these other components?
    If any answer is “no,” the components may be in the same quantum.

Sysops Squad Saga

Chapter 2 applies the quantum analysis to the Sysops Squad system to demonstrate what coupling looks like in practice.

Current State: One Quantum

The existing Sysops Squad monolith is a single quantum: all functionality (ticket creation, routing, dispatch, billing, reporting, knowledge base) is deployed together, shares a single database, and fails or succeeds as a unit.

┌─────────────────────────────────────────────────────────────┐
│  Sysops Squad Monolith (Single Quantum)                     │
│                                                             │
│  [Ticket]  [Routing]  [Dispatch]  [Billing]  [Reporting]   │
│                                                             │
│  ────────────────── Shared Database ──────────────────────  │
└─────────────────────────────────────────────────────────────┘

Static coupling: All modules share the database schema. A schema change for billing tables can break ticket routing queries.
Dynamic coupling: All operations are in-process function calls — synchronous, atomic (ACID transactions), and orchestrated by the application’s call stack.

Target State Analysis: Multiple Quanta

If the team moves to a distributed architecture, they must identify quantum boundaries. The chapter suggests the Sysops Squad system likely has several natural quanta:

┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│  Ticket Q    │   │  Expert Q    │   │  Billing Q   │
│              │   │              │   │              │
│  Ticket DB   │   │  Expert DB   │   │  Billing DB  │
└──────────────┘   └──────────────┘   └──────────────┘
        ↑                  ↑                  ↑
  Ticket ops      Routing/Dispatch      Billing/Contracts

The Key Architectural Questions

The Sysops Squad saga in Chapter 2 establishes questions that later chapters will answer:

  1. What are the quantum boundaries? Which functionality belongs in each quantum?
  2. What is the static coupling between quanta? Do they share data? Share libraries?
  3. What is the dynamic coupling style? When Ticket creates a ticket and needs Expert to be notified, is that synchronous or asynchronous? Atomic or eventual?
  4. What consistency is required? If a ticket is created but routing fails, must the ticket creation also fail (atomic)? Or can the ticket exist and routing retry (eventual)?

These questions are concrete instances of the Chapter 2 framework applied to a real (fictional) system.


Key Takeaways

  1. Coupling is multi-dimensional — it exists in static form (build-time dependencies) and dynamic form (runtime communication patterns), and each type has distinct implications for architecture.
  2. The architecture quantum — defined by high functional cohesion, independent deployability, and high static coupling within — is the fundamental unit of analysis for distributed architecture decisions.
  3. Static coupling between quanta (shared databases, shared libraries, API contracts) reduces independent deployability and creates deployment coordination overhead.
  4. Afferent coupling (incoming) indicates importance and stability; efferent coupling (outgoing) indicates fragility. Well-designed systems have unstable components depending on stable ones, not the reverse.
  5. Dynamic coupling has three independent dimensions: communication style (sync/async), consistency model (atomic/eventual), and coordination style (orchestrated/choreographed), yielding 8 possible combinations.
  6. Synchronous communication creates temporal coupling — the caller is unavailable during the call and fails if the callee fails. Asynchronous communication breaks this coupling at the cost of complexity.
  7. Atomic consistency requires distributed coordination (expensive, reduces availability); eventual consistency improves availability and performance at the cost of developer complexity and temporary data divergence.
  8. Orchestration centralizes workflow visibility and error handling but creates a single point of change; choreography maximizes decoupling but makes workflows implicit and harder to debug.
  9. A system can be statically decoupled (separate services, separate databases) but dynamically highly coupled (synchronous calls, atomic transactions) — the static and dynamic dimensions must both be evaluated.
  10. The Sysops Squad monolith is a single quantum; migrating to distributed architecture requires identifying natural quantum boundaries, which in turn requires understanding the coupling between business domains.

  • ch01-no-best-practices — Establishes the trade-off framing that this chapter operationalizes through coupling vocabulary
  • ch03-decomposition — Applies quantum and coupling analysis to the decomposition decision
  • DDIA Chapter 9 — Consistency and Consensus (the CAP theorem and distributed transactions in depth)
  • DDIA Chapter 11 — Stream Processing (asynchronous, event-driven patterns)

Last Updated: 2026-05-30