Components, as we saw in Chapter 4, are a design-time notion. The architecture quantum concept was introduced [SAH] to measure aspects of both topology and behaviour in software architecture, related to how parts connect and communicate with one another.
An architecture quantum is an independently deployable artefact with:
Each clause carries weight, and the module unpacks all three.
| Clause | What it means |
|---|---|
| Independently deployable | An architecture quantum represents a deployable asset within the architecture: each quantum is a separate deployable unit. A monolithic architecture — one deployed as a single unit — is by definition a single architecture quantum. |
| High functional cohesion | Structurally, the proximity of related elements: classes, components, services. From a purely independent-deployability standpoint a giant monolith qualifies as a quantum, but it almost certainly is not highly functionally cohesive — it includes the functionality of the entire system. The larger the monolith, the less likely it is singularly functionally cohesive. |
| High static coupling | The elements inside the quantum are tightly wired together — which is really an aspect of contracts. |
Why the concept earns its keep: the architecture quantum boundary provides a useful common language among architects, developers and operations. Each understands the common scope under question — architects understand the coupling characteristics, developers understand the scope of behaviour, and the operations team understands the deployable characteristics. And the quantum represents one of the forces (static coupling) architects must consider when striving for proper granularity of services within a distributed architecture.
The definition uses two different kinds of coupling in the same breath, and telling them apart is examinable.
| Static coupling | Dynamic coupling | |
|---|---|---|
| Represents | How static (operational) dependencies resolve within the architecture via contracts | How quanta communicate at runtime, i.e. communication dependencies, either synchronously or asynchronously |
| Describes | How components are wired together — e.g. a service with its own database | How components call one another at runtime — e.g. a service calling another service |
| Consequence | A component is not operational without the necessary data and components | Neither component requires the other to be present to function, except for some workflow at runtime |
The one-line test: static coupling asks “what must be deployed for this thing to start at all?”; dynamic coupling asks “what must be up for this workflow to complete?” A service and its own database are statically coupled — the service is not operational without it. Two services calling each other are dynamically coupled — each can boot and live alone; only the shared workflow needs both.
The module works through the cases, and the surprising ones are the most instructive.
Here is the case that catches everybody:
If the system is tightly coupled to a user interface, the architecture forms a single architecture quantum — even if it is based on microservices. User interfaces create coupling points between the front end and the back end, and most user interfaces will not operate if portions of the backend are not available.
Architects can design user interfaces using asynchronicity so that no coupling is created between front and back — for example a microfrontend framework, where the user interface elements that interact on behalf of the services are emitted from the services themselves.
The pay-off of multiple quanta is stated explicitly: each service, acting as a bounded context, may have its own set of architecture characteristics — one service might have higher levels of scalability than another. This granular level of architecture-characteristics scoping represents one of the advantages of the microservices architecture style: high degrees of decoupling allow teams working on a service to move as quickly as possible without worrying about breaking other dependencies.
The last portion of the quantum definition concerns synchronous coupling at runtime — the behaviour of architecture quanta as they interact with one another to form workflows within a distributed architecture.
The nature of how components call one another creates difficult trade-off decisions, because it is a multidimensional decision space influenced by three interlocking forces.
| Force | Question it answers | Poles |
|---|---|---|
| Communication | What type of connection synchronicity is used? | synchronous ↔ asynchronous |
| Consistency | Does the workflow communication require atomicity, or can it use eventual consistency? | atomic ↔ eventual |
| Coordination | Does the workflow use an orchestrator, or do the services communicate via choreography? | orchestration ↔ choreography |
Synchronous communication requires the requestor to wait for the response from the receiver: the calling service makes a call and blocks — does no further processing — until the receiver returns a value, or a status indicating a state change or an error condition.
Asynchronous communication: the caller posts a message to the receiver, usually via a mechanism such as a message queue, and once the caller gets acknowledgement that the message will be processed, it returns to work. If the request requires a response value, the receiver can use a reply queue to asynchronously notify the caller of the result.
Consistency refers to the strictness of transactional integrity that communication calls must adhere to. Atomic transactions — all-or-nothing, requiring consistency during the processing of a request — lie on one side of the spectrum; different degrees of eventual consistency lie on the other.
Transactionality — having several components participate in an all-or-nothing transaction — is one of the most difficult problems to model in distributed architectures. Hence the general advice: try to avoid cross-component transactions; keep transactions inside a component, not across. Chapter 7 turns this into the aggregate rule “one transaction creates or updates one aggregate”, and Chapter 9 turns it into the saga pattern.
Coordination refers to how much coordination the workflow modelled by the communication requires. The two common generic patterns for distributed components are orchestration and choreography. Simple workflows — a single component replying to a request — do not require special consideration from this dimension; but as the complexity of the workflow grows, so does the need for coordination.
The module’s summary sentence is worth memorising: transactionality is easier in synchronous architectures with mediation, whereas higher levels of scale are possible with eventually consistent asynchronous choreographed systems.
Measuring is essential for evaluating an architecture. The module distinguishes three kinds of measure:
| Kind | Measures | Examples |
|---|---|---|
| Operational measures | Operational characteristics | performance, scalability |
| Structural measures | Structural characteristics | modularity |
| Process measures | Characteristics of the software development process | deployability, testability |
The architect has two tools for this: Quality Attribute Scenarios (Chapter 2) and fitness functions (below).
Modularity is an organising principle: paying attention to how the pieces wire together. The module offers a physics analogy that is worth quoting because it explains why governance exists at all: software systems, like complex systems in general, tend towards disorder — increasing entropy. Energy must be added to a physical system to preserve order; analogously, architects must constantly spend energy to ensure good structural soundness, which will not happen by accident.
Two definitions used from here on:
Given the importance of modularity, architects need tools to understand it with language-agnostic metrics: cohesion, coupling, connascence.
Cohesion: to what extent the parts of a module should be contained within the same module — how related the parts are to one another. Ideally, a cohesive module is one where all the parts should be packaged together, because breaking them into smaller pieces would require coupling the parts together via calls between modules to achieve useful results. Larry Constantine’s formulation: “attempting to divide a cohesive module would only result in increased coupling and decreased readability”.
Computer scientists have defined a range of cohesion measures: functional, sequential, communicational, procedural, temporal and logical cohesion.
The metric the module names is the Chidamber and Kemerer Lack of Cohesion in Methods (LCOM) metric, which measures the structural cohesion of a module — typically a component. Applied to object-oriented programming: the sum of sets of methods not shared via sharing fields.
The reading of the classic example is:
Note the direction of the scale: LCOM measures the lack of cohesion, so low is good. It is an easy thing to invert under exam pressure.
Coupling in code bases is analysed by exploiting graph theory: the method calls and returns form a call graph. In 1979 Edward Yourdon and Larry Constantine published Structured Design, defining many core concepts including two coupling metrics:
| Metric | Definition |
|---|---|
| Afferent coupling | Measuring the number of incoming connections to a code artefact (component, class, function, and so on) |
| Efferent coupling | Measuring the outgoing connections to other code artefacts |
For virtually every platform, tools exist that let architects analyse the coupling characteristics of code in order to assist in restructuring, migrating or understanding a code base.
Connascence was introduced in 1996 by Meilir Page-Jones in What Every Programmer Should Know About Object-Oriented Design, refining the afferent and efferent coupling metrics and recasting them for object-oriented languages.
Two components are connascent if a change in one would require the other to be modified in order to maintain the overall correctness of the system.
| Type | Concerns | Named forms |
|---|---|---|
| Static connascence | Static aspects of code | Connascence of Name (CoN), Connascence of Type (CoT), Connascence of Position (CoP), Connascence of Algorithm (CoA)… |
| Dynamic connascence | Calls at runtime | Connascence of Execution (CoE), Connascence of Timing (CoT), Connascence of Identity (CoI) |
Architects determine the strength of connascence by the ease with which a developer can refactor that type of coupling. Different types of connascence are demonstrably more desirable than others, and architects and developers can improve the coupling characteristics of their code base by refactoring toward better types of connascence.
The three guidelines for using connascence to improve a system’s modularity:
Cyclomatic complexity (CC) is a code-level metric designed to provide an objective measure of the complexity of code, at the function/method, class or application level. It is computed by applying graph theory to code, specifically to decision points, which cause different execution paths.
If a function has no decision statements — no if statements — then CC = 1. If the function has a single conditional, then CC = 2, because two possible execution paths exist.
CC = E − N + 2
N = nodes (lines of code)
E = edges (possible decisions)
worked example from the module: CC = 3 (3 − 2 + 2)
The module first states the limit of the classical metrics: traditional OOP-oriented metrics alone lack evaluation of issues that are important in modern software systems, such as concurrency, interaction and distribution — for example whether an API is synchronous or asynchronous. Modern systems call for a more comprehensive approach, based on the identification of a wider spectrum of quality attributes.
Which raises the question: once quality attributes have been established and prioritised, how can the architect make sure that these qualities and priorities will be respected?
The word derives from the Greek kubernan, “to steer”. Governance is an important responsibility of the architect role: ensuring software quality within an organisation falls within the scope of architecture, and negligence can lead to disastrous quality problems.
The objective is automating aspects of architecture governance, in spite of the continuous change, adaptation and evolution of software systems and requirements.
An architecture fitness function is any mechanism that provides an objective integrity assessment of some architecture characteristic or combination of architecture characteristics — assessing how close the output comes to achieving the aim.
Crucially, fitness functions are not some new framework for architects to download, but rather a new perspective on many existing tools. They overlap many existing verification mechanisms, depending on the way they are used: as metrics, monitors, unit testing libraries, chaos engineering, and so on.
| Tool | Fitness function example |
|---|---|
| JDepend | Detecting component cycles (cyclic dependencies) — cyclic dependencies are a main architectural anti-pattern that leads towards big balls of mud |
| ArchUnit | Inspired by and using the JUnit ecosystem, focusing on architectural aspects (archunit.org). Example: enforcing layering |
Making architectural decisions is a core expectation of an architect: decisions involving the structure of the application or system, but also technology decisions when these impact architecture characteristics. Michael Nygard’s term for the ones that count is architecturally significant decisions: those decisions that affect the structure, non-functional characteristics, dependencies, interfaces or construction techniques.
The key need is documenting them — to track motivations, to avoid steps back. The approach: Architecture Decision Records (ADRs), short text files, usually one to two pages long, describing a specific architecture decision. First evangelised by M. Nygard, now widely adopted.
Usually numbered sequentially, containing a short phrase describing the architecture decision. It should be descriptive enough to remove any ambiguity about the nature and context of the decision, but at the same time short and concise.
42. Use of Asynchronous Messaging Between Order and Payment Services.
Can be marked as Proposed, Accepted or Superseded.
ADR 42. Use of Asynchronous Messaging Between Order and Payment Services
Status: Superseded by 68
ADR 68. Use of REST Between Order and Payment Services
The superseded status always assumes the prior ADR status was accepted: a proposed ADR would never be superseded, but rather continue to be modified until accepted. This is a powerful way of keeping a historical record of what decisions were made, why they were made at that time, what the new decision is and why it changed.
A further status is Request for Comments (RFC), used when the architect wants to validate assumptions and assertions with a larger audience of stakeholders, specifying a deadline:
Status: Request For Comments, Deadline 09 JAN 2026
Specifying the forces at play: what situation is forcing me to make this decision? It allows the architect to describe the specific situation or issue and concisely elaborate on the possible alternatives.
The order service must pass information to the payment service to
pay for an order currently being placed. This could be done using
REST or asynchronous messaging.
Note the side benefit: by describing the context, the architect is also describing the architecture — an effective way of documenting a specific area of the architecture in a clear and concise manner.
Contains the architecture decision, along with a full justification, in an affirmative style.
Decision: we will use asynchronous messaging between services,
to improve uncoupling
This section places emphasis on the why rather than the how. Knowing why a decision was made, and its justification, helps people better understand the context of the problem and avoids possible mistakes through refactoring to another solution that might produce issues.
Documenting the overall impact of an architecture decision, both good and bad, and then the trade-off analysis associated with the decision.
This is the section that makes an ADR different from a wiki page: it forces the author to write down what the decision costs, not only what it buys.
A non-standard section from [FSA]. The Compliance section forces the architect to think about how the architecture decision will be measured and governed from a compliance perspective: the architect must decide whether the compliance check for this decision must be manual, or whether it can be automated using a fitness function.
All shared objects used by business objects in the business layer will
reside in the shared services layer to isolate and contain shared
functionality.
If it can be automated, the architect specifies here how that fitness function would be written, and whether any other changes to the code base are needed to measure this decision for compliance.
Metadata about the ADR itself: original author, approval date, approved by, superseded date, last modified date, modified by, last modification.
An independently deployable artefact with high functional cohesion, high static coupling and synchronous dynamic coupling. It was introduced to measure aspects of both topology and behaviour, related to how parts connect and communicate with one another.
Static coupling represents how static (operational) dependencies resolve within the architecture via contracts — it describes how components are wired together, e.g. a service with its own database: the component is not operational without the necessary data and components. Dynamic coupling represents how quanta communicate at runtime, synchronously or asynchronously — e.g. a service calling another service: neither component requires the other to be present to function, except for some workflow at runtime.
One. Any architecture that deploys using a single database always has a single quantum, because the architecture quantum measure of static coupling includes the database, and a system relying on a single database cannot have more than a single quantum. The module names two such cases explicitly: the device-based architecture style, and an event-driven architecture with a centralised event broker.
Because of the user interface. If the system is tightly coupled to a UI, the architecture forms a single architecture quantum even if it is based on microservices: user interfaces create coupling points between front end and back end, and most UIs will not operate if portions of the backend are unavailable. The remedy is to design the UI using asynchronicity — for example a microfrontend framework, where the UI elements that act on behalf of the services are emitted from the services themselves.
Each service, acting as a bounded context, may have its own set of architecture characteristics — one service might need higher scalability than another. This granular scoping of architecture characteristics is one of the advantages of microservices, and the high degree of decoupling allows the team on a service to move as fast as possible without worrying about breaking other dependencies.
Communication (synchronous ↔ asynchronous), consistency (atomicity ↔ eventual consistency) and coordination (orchestration ↔ choreography). They form a multidimensional decision space, and architects cannot choose in isolation: each option has a gravitational effect on the others. Transactionality is easier in synchronous architectures with mediation, whereas higher levels of scale are possible with eventually consistent asynchronous choreographed systems.
That transactionality — several components participating in an all-or-nothing transaction — is one of the most difficult problems to model in distributed architectures, hence the general advice to avoid cross-component transactions: keep transactions inside a component, not across. This is the same rule that reappears as the aggregate transaction boundary in Chapter 7 and as the saga pattern in Chapter 9.
The Chidamber and Kemerer Lack of Cohesion in Methods metric measures the structural cohesion of a module, typically a component; applied to OOP it is the sum of sets of methods not shared via sharing fields. Since it measures the lack of cohesion, a low score is good. A class with a high LCOM has field/method pairs that could each move into their own class without affecting behaviour.
Two components are connascent if a change in one would require the other to be modified in order to maintain the overall correctness of the system. Static connascence concerns static aspects of code (Name, Type, Position, Algorithm); dynamic connascence concerns calls at runtime (Execution, Timing, Identity). Guidelines: (1) minimise overall connascence by breaking the system into encapsulated elements; (2) minimise any remaining connascence that crosses encapsulation boundaries; (3) maximise the connascence within encapsulation boundaries.
By the ease with which a developer can refactor that type of coupling: some types of connascence are demonstrably more desirable than others. Architects and developers improve their code base by refactoring toward better types of connascence — i.e. converting a hard-to-refactor coupling into an easier one, rather than trying to remove all coupling.
CC = E − N + 2, where N represents nodes (lines of code) and E represents edges (possible decisions). A function with no decision statements has CC = 1; with one conditional, CC = 2. Industry thresholds: CC ≤ 10 acceptable, barring considerations such as complex domains; [FSA] suggests CC < 5 for cohesive, well-factored code; and Crap4J’s dictum is that above 50 no amount of code coverage rescues that code from crappiness.
Any mechanism that provides an objective integrity assessment of some architecture characteristic or combination of architecture characteristics — assessing how close the output comes to achieving the aim. It is not a new framework for architects to download: it is a new perspective on many existing tools, overlapping existing verification mechanisms depending on how they are used — metrics, monitors, unit testing libraries, chaos engineering. Named examples: JDepend for detecting cyclic component dependencies, ArchUnit for layering rules.
Standard: Title, Status, Context, Decision, Consequences. Extensions from [FSA]: Compliance and Notes. Superseded always assumes the prior ADR was accepted — a proposed ADR would never be superseded, only modified until accepted. Superseding keeps a historical record of what was decided, when, why, and why it changed. A further status is Request for Comments, with a deadline.
Because it forces the architect to think about how the decision will be measured and governed: the architect must decide whether the compliance check must be manual, or whether it can be automated using a fitness function — and if automated, specify how that fitness function would be written and what changes to the code base are needed to measure the decision. It is the bridge from a written decision to enforced governance.