\part{Architecture as a Decision Problem} \label{part:foundations} % ============================================ % SECTION: THE DECISION PROBLEM % ============================================ \section{The Decision Problem} \label{sec:decisionproblem} This module answers one question: \emph{How do I design, justify, and operate the structure of a software system so that it meets its quality attributes and remains maintainable for years -- even when individual components (AI) are non-deterministic, fallible, and expensive?} This part builds the framework in which that question becomes decidable: a demand side, a supply side, a matching rule, a decision record, and a measurement contract. Before we build, two facts from production establish why a framework is needed at all. \subsection{Two facts from production} \label{subsec:fourcases} Table~\ref{tab:fourcases} summarises four production systems, each publicly described by its own engineers. \begin{table}[htbp] \centering \caption{Four documented production systems establishing the two facts that create the decision problem: radically different structures succeed on comparable problems, and no structure dominates.} \label{tab:fourcases} \footnotesize \begin{tabular}{@{}p{2.3cm}p{4.6cm}p{7.2cm}@{}} \toprule \textbf{System} & \textbf{Structure} & \textbf{Documented outcome} \\ \midrule Stack Overflow & \texttt{.NET} monolith on roughly nine on-premise web servers & $\sim 1.3$ billion page views per month at $\sim 12$\,ms render times -- scaled \emph{up}, not \emph{out} \citep{craver2016stackoverflow, milanovic2023stackoverflow} \\ Monzo & $\sim 2{,}800$ Go microservices; one language, one monorepo, central migration automation & retail banking at scale -- viable through extreme technological homogeneity \citep{sewell2024monzo} \\ Segment & $> 140$ microservices, one per analytics destination & public 2018 rollback to a monolith: operational and test complexity crushed a small team \citep{noonan2018goodbye, infoq2020segment} \\ Prime Video & serverless orchestration: Step Functions, Lambda, S3 buffers & consolidation into a single process cut infrastructure cost by $> 90\,\%$; hard scaling limit at $\sim 5\,\%$ of expected load \citep{kolny2023primevideo, cockcroft2023prime} \\ \bottomrule \end{tabular} \end{table} Two facts follow. \textbf{First, structures differ radically for similar-looking problems}: Monzo and Stack Overflow both serve millions of users interactively at high availability -- one with thousands of deployment units, the other with essentially one. \textbf{Second, no structure dominates}: for every pattern there is a documented context in which it failed expensively (Segment, Prime Video) and one in which its unfashionable opposite succeeded at scale (Stack Overflow; Instagram \citep{woodruff2019static}; Shopify \citep{westeinde2019deconstructing}). Neither fact proves monoliths good or microservices bad. Prime Video's failure was a mismatch between a data-intensive, tightly coupled processing flow and an architecture that put expensive distributed boundaries in the middle of it \citep{kolny2023primevideo, cockcroft2023prime}; Segment's was a service cut along \emph{instances of configuration} rather than domain seams \citep{noonan2018goodbye, newman2021building}. The value of an architectural pattern is not a property of the pattern; it is a property of the \emph{match} between the pattern and the application it serves. \begin{keypoint} \textbf{Maxim 1.} Patterns are neither good nor bad; only the fit between a requirements profile and a capability profile is. \end{keypoint} That is the decision problem: given an application, choose among non-dominated structural alternatives whose value depends on the match -- knowing that the choice will be expensive to reverse. \subsection{What architecture addresses} \label{subsec:whatis} ``Software architecture'' has a documented tendency to mean everything and therefore nothing \citep{fowler2003who}. Four definition families, complementary rather than competing, pin the term down; each contributes one load-bearing element to the framework. \begin{definitionbox}[Software architecture (ISO/IEC/IEEE 42010:2022)] Architecture: ``fundamental concepts or properties of an entity in its environment and governing principles for the realization and evolution of this entity and its related life cycle processes'' \citep{iso2022architecture}. \end{definitionbox} The \textbf{normative} definition (ISO) supplies the shared vocabulary -- \emph{stakeholders}, \emph{concerns}, \emph{viewpoints}, \emph{views} -- and one obligation this framework builds on directly: recording architecture decisions \emph{and their rationale} is mandatory for a conformant architecture description (Clause~6.10) \citep{iso2022architecture, iso2011architecture, ieee2000recommended}. The \textbf{decision-centric} definition (Booch) supplies the significance criterion: ``architecture represents the significant design decisions that shape a system, where significant is measured by cost of change'' \citep[p.~214]{buschmann2007pattern}; Jansen and Bosch radicalise it -- architecture \emph{is} a composition of design decisions, and the loss of decision knowledge (\emph{knowledge vaporization}) is a principal cause of erosion \citep{jansen2005software}. The \textbf{social} definition (Fowler/Johnson) -- the expert developers' shared understanding, ``the important stuff -- whatever that is'' -- adds that perceived irreversibility is the core of the matter and that a chief task of architects is to \emph{remove} it \citep{fowler2003who}. The \textbf{structural-analytic} definition (SEI) -- ``the set of structures needed to reason about the system'' \citep{bass2021software, perry1992foundations, shaw1996software} -- carries the observation on which everything here turns: \emph{functionality is largely structure-neutral; quality attributes are not}; what the structure determines is \emph{how well} \citep{bass2021software, sommerville2020modernes}. Distilled into one sentence: \emph{architecture is the set of hard-to-reverse structural decisions that determine the quality behaviour of a system.} The cost-of-change criterion also settles the boundary towards design and implementation. Choosing between a modular monolith and microservices is architectural: reversing it is a migration measured in months. Choosing a logging library is design, revisable in days behind a stable interface; choosing a variable name is implementation, revisable in seconds. The boundary is gradual and context-dependent -- a database choice is architectural in a system without a persistence abstraction, closer to design in a hexagonal one -- and that is the point: good architecture actively pushes decisions from irreversible towards reversible \citep{fowler2003who}. (Scope note: this module operates at solution level, not at the enterprise level of TOGAF's ADM \citep{opengroup2022togaf}; enterprise mandates enter only as constraints in the requirements profile.) Two refusals follow, and the framework enforces both. It refuses \emph{fashion}: the dominance claim behind every hype cycle is falsified by Table~\ref{tab:fourcases}. And it refuses \emph{taste}: a claim that cannot be measured or falsified has no place in an architectural decision. \subsection{The framework at a glance} \label{subsec:framework} Instead of arguing towards the framework, we state it up front and spend the rest of this part constructing it. \begin{definitionbox}[The five elements of architecture--application fit] Let $A$ be a set of application classes and $P$ a set of architectural patterns. The framework of this script consists of five elements: \begin{enumerate} \item the \textbf{requirements profile} $R(a) = \bigl(w_1(a), \dots, w_{12}(a);\; S(a);\; K(a)\bigr)$ of a class $a \in A$: priority weights $w_i(a) \in \{\text{High}, \text{Medium}, \text{Low}\}$, a dominant workload shape $S(a)$, hard constraints $K(a)$ -- the \emph{demand side} (Section~\ref{sec:demand}); \item the \textbf{capability profile} $C(p) = \bigl(c_1(p), \dots, c_{12}(p);\; S(p)\bigr)$ of a pattern $p \in P$: ordinal ratings $c_i(p) \in \{++, +, \circ, -, --\}$ plus the pattern's native workload shape $S(p)$ -- the \emph{supply side} (Section~\ref{sec:supply}); \item the \textbf{architecture--application fit} $\mathrm{fit}(a,p)$: an ordinal, non-compensatory match of the two profiles, computed by rules, not arithmetic (Section~\ref{sec:fit}); \item the \textbf{Architecture Decision Record (ADR)}: the permanent, auditable record of the decision and its rationale (Section~\ref{sec:adr}); \item the \textbf{measurement contract}: the fitness functions and thresholds under which the decision is continuously tested in operation (Section~\ref{sec:adr}; in full in Part~\ref{part:fit}). \end{enumerate} Both profiles are defined over the twelve dimensions of Table~\ref{tab:dimensions} (Section~\ref{sec:dimensions}). \end{definitionbox} Figure~\ref{fig:pipeline} is the map -- of the framework and of the script. This part constructs each element once, by hand; the remaining parts instantiate them at scale: Part~\ref{part:patterns} derives $C(p)$ for seven patterns (Table~\ref{tab:capability}), Part~\ref{part:applications} derives $R(a)$ for ten application classes (Table~\ref{tab:requirements}), Part~\ref{part:fit} computes $\mathrm{fit}(a,p)$ for all seventy pairs and supplies the decision procedure and the measurement apparatus, and Part~\ref{part:ai} extends the space by AI on both of the module's axes. \begin{figure}[htbp] \centering \begin{tikzpicture}[ node distance=0.9cm and 1.0cm, sysbox/.style={rectangle, draw, rounded corners=4pt, text width=3.2cm, minimum height=1.3cm, align=center, font=\small\sffamily, line width=0.8pt}, core/.style={sysbox, fill=bankblue!20, draw=bankblue}, comp/.style={sysbox, fill=bankgreen!15, draw=bankgreen}, meas/.style={sysbox, fill=violet!15, draw=aiviolet}, arr/.style={-{Stealth[length=2.5mm]}, thick, gray!60!black}, farr/.style={-{Stealth[length=2.5mm]}, thick, dashed, bankred} ] \node[core] (klass) {Application class\\ \scriptsize (Part~\ref{part:applications})}; \node[core, right=0.9cm of klass] (profil) {Requirements profile $R(a)$\\ \scriptsize scenarios, utility tree}; \node[core, right=0.9cm of profil] (match) {Matching $\mathrm{fit}(a,p)$\\ \scriptsize against $C(p)$ (Parts~\ref{part:patterns}, \ref{part:fit})}; \node[comp, below=1.4cm of match] (adr) {Architecture decision\\ \scriptsize ADR with rationale}; \node[meas, left=0.9cm of adr] (fitness) {Measurement contract\\ \scriptsize fitness functions in CI/CD}; \node[meas, left=0.9cm of fitness] (ops) {Operation\\ \scriptsize DORA, SLOs, Lehman trends}; \draw[arr] (klass) -- (profil); \draw[arr] (profil) -- (match); \draw[arr] (match) -- (adr); \draw[arr] (adr) -- (fitness); \draw[arr] (fitness) -- (ops); \draw[farr] (ops.north) -- node[midway, right=2pt, font=\scriptsize\sffamily, text=bankred, align=left] {profile drift (A5):\\ re-measure, evolve, supersede} (klass.south); \end{tikzpicture}% \caption{The framework as a pipeline -- and the map of this script. Demand is matched against supply; the match ends in a recorded decision with a measurement contract, and operation continuously tests whether the decision's promises hold. The dashed feedback edge is not decoration -- it is assumption A5.} \label{fig:pipeline} \end{figure} \begin{ailinse}[The two AI axes of this module] AI enters this module twice. On \textbf{Axis~A}, AI is a \emph{tool in the development process}: assistants and agents generate code, tests, and documentation -- changing \emph{how} we make and guard architectural decisions. On \textbf{Axis~B}, AI is a \emph{runtime component of the system itself}: an LLM, an ML model, or an optimiser inside the architecture, bringing non-determinism, seconds-scale latency, and per-call cost -- changing \emph{what} we must decide about. Both are treated systematically in Part~\ref{part:ai}; boxes like this one flag where each axis touches the classical material. \end{ailinse} \subsection{Six load-bearing assumptions} \label{sec:axioms} The framework rests on six assumptions -- each anchored in established literature, each justifying one element of the framework. \textbf{A1 -- Architecture is the set of significant, hard-to-reverse design decisions}, significance measured by cost of change \citep[p.~214]{buschmann2007pattern} -- Johnson's ``decisions you wish you could get right early'' \citep{fowler2003who}. A1 fixes the framework's \emph{object}: what we choose is a decision with high reversal cost, and what we must manage is decision knowledge, whose loss is a documented cause of erosion \citep{jansen2005software}. A1 justifies element~4: every decision the framework produces is recorded as an ADR \citep{nygard2011documenting}, fulfilling the ISO~42010 rationale obligation \citep{iso2022architecture}. \textbf{A2 -- Everything in software architecture is a trade-off} -- and if you think you have found something that is not, you have not yet identified the trade-off. This is Richards and Ford's First Law of Software Architecture \citep{richards2025fundamentals}, empirically visible in their own star ratings: microservices lead the aggregate yet score one star on cost and simplicity; layered is the exact mirror -- five stars there, one star on deployability, elasticity, and scalability. Dominance -- one alternative at least as good everywhere and strictly better somewhere -- does not occur in the published profiles. A2 justifies element~3: because no dominant alternative exists, a \emph{matching problem} exists at all -- otherwise this script would be one page long. Corollary: any proposal that claims only benefits is incomplete \emph{by assumption}, and reviewers may demand its sensitivity and trade-off points in the ATAM sense \citep{kazman2000atam}. \textbf{A3 -- Quality attributes, not functionality, drive architecture.} Functionality is largely structure-neutral; what the structure determines is \emph{how well} -- performance, availability, modifiability, security \citep{bass2021software}; architecture determines the non-functional properties, and these can rarely be refactored in afterwards \citep{sommerville2020modernes}. A3 justifies the coordinate system: the dimensions over which both profiles range (Section~\ref{sec:dimensions}) are quality attributes and workload/constraint characteristics, anchored in ISO/IEC 25010:2023 \citep{iso2023product} -- never feature lists, which under-determine architecture. \textbf{A4 -- Requirements are architecturally usable only as measurable scenarios.} ``The system shall be scalable'' decides nothing and tests nothing; a quality attribute becomes decision-relevant only as a six-part scenario whose non-negotiable part is a \emph{response measure} with number and unit \citep{bass2021software}. Empirically, architecturally significant requirements are vague and implicit and must be systematically elicited \citep{chen2013characterizing}. A4 justifies the construction method of the demand side (Section~\ref{sec:demand}): every requirement in $R(a)$ is a scenario with a response measure, and the weights $w_i(a)$ are derived from the (High, High) leaves of a utility tree \citep{kazman2000atam, barbacci2003quality} -- not from opinion. \textbf{A5 -- An architecture decision is a hypothesis, continuously tested over the life cycle.} Lehman's laws: a system embedded in the real world must continually change or become progressively less useful \citep{lehman1980laws, lehman1996laws}; maintenance and evolution consume roughly $40$--$80\,\%$ (typically $\sim 60\,\%$) of life-cycle cost \citep{glass2002facts}. Design-time fit therefore \emph{decays}, and the instruments to re-measure it exist: architectural fitness functions in the CI/CD pipeline \citep{ford2022evolutionary} and the four DORA metrics in delivery \citep{forsgren2018accelerate, dora2023sodr} -- with the strongest single finding in the field, ``loosely coupled architectures and teams are the strongest predictor of continuous delivery'' \citep{dora2017sodr}, and the caveat that DORA's evidence is survey-based, not experimentally causal. Boehm's classical $100\times$ cost-of-change escalation \citep{boehm1981economics, boehm2001top10} is empirically flattened for changes \emph{within} an architecture \citep{menzies2017delayed} but remains steep for changes \emph{of} it -- exactly what the Segment and Prime Video rollbacks were. A5 justifies element~5: every ADR ends with a measurement contract, and evolution paths stay open (Strangler Fig \citep{fowler2004strangler}). \textbf{A6 -- AI components extend the quality attribute space but do not change the method.} Runtime AI components are non-deterministic, fallible, latency-heavy, priced per call, and subject to drift and vendor deprecation \citep{sculley2015hidden, amershi2019software, gama2014drift}; they stretch existing quality dimensions by orders of magnitude and add sub-attributes with no classical counterpart -- token cost per request, eval pass rate, prompt-injection resistance \citep{owasp2025llmtop10}. Crucially, ISO/IEC 25010:2023 already carries the vocabulary (\emph{Safety}, \emph{Flexibility/scalability}, \emph{Security/resistance}; Section~\ref{sec:dimensions}) \citep{iso2023product}. What does \emph{not} change is the method: scenarios with response measures, tactics, trade-off analysis, ADRs, fitness functions. A6 justifies how the framework treats AI: it is \emph{absorbed}, not special-cased -- one additional profile dimension (D12) and one additional test artefact class (the eval harness, Part~\ref{part:ai}), nothing else. This is the module's central intellectual bet, and Part~\ref{part:ai} is its defence. \begin{keypoint} \textbf{Maxim 2.} Because everything is a trade-off (A2) and quality drives structure (A3), architecture selection is matching; because decisions are costly to reverse (A1) and decay over time (A5), the match must be documented and continuously measured. \end{keypoint} % ============================================ % SECTION: THE COORDINATE SYSTEM -- TWELVE PROFILE DIMENSIONS % ============================================ \section{The Coordinate System: Twelve Profile Dimensions} \label{sec:dimensions} The framework box in Section~\ref{subsec:framework} made a promise: demand and supply -- $R(a)$ and $C(p)$ -- would be described in one shared, measurable vocabulary, as vectors over the \emph{same} twelve dimensions. This section builds that coordinate system, and it builds it from the ground up: first the recurring questions that anyone responsible for a real system must answer (Section~\ref{subsec:questions}); then the twelve dimensions those questions become, introduced one by one in plain language (Section~\ref{subsec:dimtour}); then the criteria under which exactly these twelve -- and no others -- were admitted (Section~\ref{subsec:admission}); and finally the reference card, Table~\ref{tab:dimensions}, which condenses everything into the compact form the rest of the script uses (Section~\ref{subsec:dimtable}). \subsection{From questions to dimensions} \label{subsec:questions} Forget frameworks for a moment and imagine you are responsible -- personally, with your name on the on-call rota -- for a system that real people use. Questions of the following kind will find you, whether or not you have a vocabulary for them: \begin{itemize} \item \emph{The university's grade-release portal: what happens at 08:00 on publication day, when the whole semester refreshes the same page at once?} \item \emph{An e-banking transfer: can the same payment ever be booked twice -- or disappear halfway?} \item \emph{One component crashes at noon: does the whole application go dark, or does one widget show a spinner while everything else keeps working?} \item \emph{The regulator calls: ``prove to us, step by step, what happened to this one transaction.'' How long does that take you?} \item \emph{A new feature request arrives: how many places in the code must change -- one module, or seventeen?} \item \emph{Two students must ship a working MVP (minimum viable product -- the smallest version of the product worth releasing) in one semester: does the structure let them, or does it demand a platform team they do not have?} \item \emph{The monthly cloud bill triples: which part of the structure is spending the money, and what was it doing at 03:00?} \item \emph{The team grows from three to thirty: do releases get faster -- or does everyone now wait for everyone else?} \item \emph{Product adds a feature whose core is an LLM call: it takes eight seconds, costs money on every single request, and is sometimes confidently wrong. Where does that live in the architecture?} \end{itemize} Three observations turn this list from anecdote into method. First, the questions \emph{recur}: every one of them has ended budgets, products, or careers, and every one of them arises across wildly different systems -- the grade portal and Instagram share the first question, merely at different magnitudes. Second, none of them asks \emph{what} the system does: functionality is largely structure-neutral (A3); every question above is about \emph{how well}, \emph{at what cost}, \emph{under which failure}. Third -- and this is the step that makes a decision theory possible -- each question can be answered with a number: requests per second, double bookings per million transfers, per cent of functionality lost, hours to reconstruct an audit trail, modules touched per feature, weeks to first release, cost per request, deployments per developer per day, seconds and cents per LLM call. Now recall what the framework needs. The match of Section~\ref{sec:fit} compares what an application \emph{demands} with what a structure \emph{delivers}. That comparison is only defined if both sides are described in the \emph{same} vocabulary, and it is only testable (A4) if that vocabulary is measurable. The twelve profile dimensions D1--D12 are exactly this: the recurring questions above -- grouped, named, and equipped with defined measures. Nothing more mysterious than that. \subsection{The twelve dimensions, one by one} \label{subsec:dimtour} The twelve dimensions fall into five thematic groups. Each dimension below follows the same rhythm: the question in plain language, what the dimension means, where it bites, and how it is measured -- with every term of art defined on first use, so that the reference card at the end of this section needs no prior knowledge. \subsubsection{Load and speed (D1--D3)} The first group asks whether the structure survives its own success: more users, more traffic, less patience. \paragraph{D1 -- Read scalability.} \emph{What happens at 08:00 on grade-release day, when the whole semester refreshes at once?} Read scalability is the ability of a structure to serve a growing volume of \emph{read} requests -- requests that look at data without changing it. It matters because most interactive systems are read-dominated by orders of magnitude: for every student filing a grade appeal there are thousands checking a result, and for every Instagram post there are thousands of feed views. Reads have a friendly property: since they change nothing, they can be served from \emph{copies} -- replicated servers and \emph{caches}, a cache being a fast store that holds ready-made answers so they need not be recomputed. That is how Stack Overflow serves roughly $1.3$ billion page views a month from a handful of servers \citep{craver2016stackoverflow}, and how Instagram carried hundreds of millions of users on a deliberately conventional monolith \citep{woodruff2019static} -- in both cases the single write path, not the read traffic, is the hard part. Measured: \emph{throughput} (requests completed per second) as replicas are added -- does doubling the servers double the throughput? -- together with the \emph{cache hit ratio}, the share of requests answered from a cache rather than computed afresh; in production, so-called RED metrics track this per service (Rate, Errors, Duration: how many requests arrive, how many fail, how long they take). Patterns will differ here because some topologies make replicating and caching reads trivial, while others entangle reads with state they cannot easily copy. \paragraph{D2 -- Write scalability and elasticity.} \emph{Black Friday: checkout traffic jumps to dozens of times the baseline for one weekend -- and is gone on Monday. Can the structure grow and shrink with the load?} Write scalability is the D1 question for requests that \emph{change} state -- and it is the harder half, because a write cannot be served from a copy: every order, payment, and booking must reach the one authoritative record, durably and in the right order. \emph{Elasticity} adds the time axis: how quickly capacity follows the load, upwards and back down again. The reference point of this script is Shopify's Black Friday/Cyber Monday weekend, with peaks around $280$ million requests per minute \citep{shopify2024bfcm}, carried by replicated ``pods'' of a monolith \citep{westeinde2019deconstructing}; the opposite end of the same dimension is \emph{scale-to-zero} -- a structure that costs nothing while nobody uses it, the core promise of serverless computing \citep{jonas2019berkeley}. Measured: the \emph{sustained ingest rate} (how much incoming write traffic per second the system durably absorbs -- ``ingest'' is simply intake), the \emph{time-to-capacity} after a load step (how many minutes pass between the spike and the capacity to serve it), and the cost of idling at zero. Patterns differ sharply: some can replicate their write path, while others funnel every write through one shared database that no number of additional servers relieves. \paragraph{D3 -- Latency and predictability.} \emph{How long does one click take -- and how long does it take on a bad day?} \emph{Latency} is the time between a request and its response; \emph{predictability} says that the interesting quantity is not the average but the distribution. Averages lie: a system can average $120$\,ms while every twentieth request takes four seconds -- and precisely the most active users, who make the most requests, hit those slow ones most often. The field therefore reports \emph{percentiles}: p50 is the median response time, p95 the time the slowest $5\,\%$ of requests see, p99 the time the slowest $1\,\%$ see; the ratio p99/p50, the \emph{tail-latency ratio}, states how much worse a bad request is than a normal one. The stakes are documented: Amazon measured roughly $1\,\%$ of sales lost per additional $100$\,ms of latency \citep{linden2006data}, and Akamai's retail study found up to $7\,\%$ of conversions lost per $100$\,ms \citep{akamai2017retail}. One more term the reference card uses: a \emph{cold start} is the extra delay incurred when a request must first wake up the component that will serve it -- characteristic of scale-to-zero structures, and the price of their D2 virtue. Measured with \emph{distributed tracing}: instrumentation that follows one request across every component it touches and reports where the milliseconds went. Patterns differ because every network hop between components adds latency, and every on-demand start adds a cold start. \subsubsection{Correctness and trust (D4--D6)} The second group asks whether the system can be trusted -- with money, with uptime, with history. \paragraph{D4 -- Consistency and transactional integrity.} \emph{An e-banking transfer: can the same payment ever be booked twice -- or vanish halfway?} This dimension asks whether concurrent access and partial failure can corrupt the data -- whether the system's numbers can silently stop being true. The classic failure is the \emph{lost update}: two processes read the same account balance, both compute a new one, and the second write overwrites the first -- money created or destroyed without any error message. The vocabulary: an \emph{invariant} is a rule that must hold at all times (``debit equals credit across every transfer'', ``no seat is sold twice''); \emph{transactional integrity} means that multi-step operations happen entirely or not at all; \emph{staleness} is how many seconds a copy of the data may lag behind the original -- tolerable for a follower count, intolerable for a ledger. Measured: the anomaly rate under concurrent load, the invariant-violation count (target: exactly zero for anything ledger-like), and the staleness bound; the instruments are \emph{Jepsen-style tests} -- harnesses that hammer a system with concurrent operations while deliberately injecting failures, then check whether the promised guarantees actually held \citep{kleppmann2017designing} -- and \emph{reconciliation jobs}, batch runs that compare two independent records of the same facts and flag every difference. Patterns differ fundamentally: a single database hands the developer transactions for free; every distribution boundary takes part of that away and obliges the developer to compensate by hand. \paragraph{D5 -- Availability and fault isolation.} \emph{One component crashes at noon: does the whole app go dark, or does one widget show a spinner?} Availability is the share of time the system does its job; fault isolation is how much of the product dies when one part dies. The plain-language core of the reference card: the \emph{blast radius} of a component is the percentage of functionality lost when that component fails -- in a single-process system it is $100\,\%$ by construction; \emph{MTTR}, the mean time to recovery, is how long the damage lasts on average. Modern operations manage availability as an explicit contract: an \emph{SLO} (service level objective) is a stated target such as ``$99.9\,\%$ of requests succeed this month''; the \emph{error budget} is the tolerated remainder -- the $0.1\,\%$ the team may deliberately ``spend'' on risky releases and experiments; \emph{error-budget burn} is the rate at which incidents consume it. Measured: SLO attainment, burn rate, blast radius per component failure, and MTTR; the honest instrument is the \emph{chaos experiment} -- deliberately killing components under realistic load and measuring what users actually lose \citep{basiri2016chaos}. Run continuously in the delivery pipeline, such an automated, repeatable check of an architectural property is called a \emph{fitness function} \citep{ford2022evolutionary} -- a term the reference card and the rest of the script use constantly. Patterns trade along this dimension rather than winning it: distribution shrinks the blast radius and simultaneously multiplies the number of things that can fail. \paragraph{D6 -- Security and auditability.} \emph{The regulator asks: prove what happened to this one transaction, end to end.} Keeping attackers out is necessary everywhere; what discriminates between \emph{structures} is auditability -- the ability to reconstruct history. An \emph{audit trail} is a complete, tamper-evident record of who changed what, when, and on whose authority; in supervised industries it is a legal duty, not a nice-to-have -- Swiss financial institutions must be able to demonstrate the integrity of their operational data to FINMA \citep{finma2023oprisk}, and payment systems live under PCI~DSS \citep{pcissc2022pcidss}. The associated cost term is the \emph{audit scope}: the portion of the system that auditors must examine -- structures that confine sensitive data flows to a small, well-bounded region shrink that scope, and with it the audit bill. Measured: the time to reconstruct a complete audit trail for one transaction (an \emph{audit drill}, run like a fire drill), and the percentage of state changes \emph{journaled} -- written to a permanent, append-only log at the moment they happen. Patterns differ by construction: some record every change as an event as their normal mode of operation; others must reassemble history from whatever scattered log files happen to exist. \subsubsection{Change and delivery (D7--D9)} The third group prices change: the next feature, the next release, the next hire. \paragraph{D7 -- Evolvability and maintainability.} \emph{A feature request arrives: how many places in the code must change?} This dimension prices the \emph{next} change -- and over a lifetime dominated by evolution (A5), it quietly dominates most others. Its central measure has a name worth memorising: \emph{change dispersion}, the number of modules touched by an average feature -- one is excellent, seventeen is an architecture problem. The underlying variable is \emph{coupling}: the degree to which modules depend on each other, so that a change in one ripples into the next; classical metrics quantify it, for instance CBO (\emph{coupling between objects} -- how many other classes a class depends on) and Martin's \emph{instability} (roughly, the share of a module's couplings that point outward, so that changes elsewhere ripple in) \citep{chidamber1994metrics, martin2003agile}; CBO belongs to the Chidamber--Kemerer (CK) metric suite the reference card names. Measured: change dispersion over the version history, coupling metrics, and \emph{declared-boundary violations} -- cases where code bypasses the module boundaries the architecture declares, with a target of zero, enforceable by CI rules that fail the build on any forbidden dependency, using tools such as ArchUnit or Spring Modulith \citep{drotbohm2023modulith}. Patterns differ because each topology draws its boundaries somewhere -- and a feature that respects one pattern's seams cuts straight across another's. \paragraph{D8 -- Simplicity and time-to-market.} \emph{Two students must ship a working MVP in one semester. Does the structure let them?} Simplicity measures how much machinery must exist, be understood, and be kept alive before the first unit of value reaches a user. The anchor is deliberately close to home: a two-person team with one semester. A structure that requires a container orchestrator (software that runs and coordinates fleets of services), a message broker (a dedicated middleman that relays messages between components), and a dozen repositories before ``hello, world'' has failed this dimension for that team -- however magnificently it would carry Shopify's Black Friday. Measured: the time from an empty repository to the first production release; the onboarding time until a new developer's first merged contribution; and the plain count of distinct runtime technologies that must be operated. This dimension is where A2 bites hardest: the structures that win D8 tend to concede D2 or D11, and vice versa -- which is why a small team's rational choice differs from a platform company's. \paragraph{D9 -- Testability and deployability.} \emph{Can a developer know within seconds that a change is safe -- and release it this afternoon without coordinating with three other teams?} Two abilities, deliberately fused: fast, trustworthy verification and independent, low-risk release. The vocabulary: a \emph{hermetic test} runs entirely self-contained -- on the developer's machine or in CI, with no shared staging environment and no live external service -- which is what makes it fast and repeatable; \emph{deployment frequency} is how often the team releases to production; the \emph{change failure rate} is the share of releases that break something. The latter two belong to the four delivery metrics of DORA -- a long-running research programme that measures software delivery performance across thousands of organisations \citep{forsgren2018accelerate} -- and DORA's 2017 analysis is why the fusion is deliberate: the ability to test without an integrated environment and to deploy independently of other teams predicted delivery performance more strongly than test and deployment automation itself \citep{dora2017sodr}. Measured: test feedback time, share of hermetic tests, deployment frequency, and change failure rate -- all read directly from pipeline telemetry. Patterns differ because both abilities are surface expressions of coupling, and coupling is precisely what topologies differ in. \subsubsection{Economics and organisation (D10--D11)} The fourth group leaves the code: structures cost money to run, and they constrain how organisations can work. \paragraph{D10 -- Operating cost efficiency.} \emph{The cloud bill tripled. Which part of the structure spends the money -- and what was it doing at 03:00?} This dimension prices the running system -- machines \emph{and} people. The vocabulary: \emph{cost per request} attributes spend to work actually done; \emph{idle cost} is what you pay for capacity that does nothing (the 03:00 question); \emph{TCO}, the total cost of ownership, is the honest sum -- building, running, and the platform work in between; an \emph{FTE}, a full-time equivalent, is the unit of that last part: one person's full working time. The hidden term matters most: the cost of a self-managed container platform is typically dominated not by compute prices but by the platform-team FTEs required to keep it alive \citep{fowler2015premium, portainer2024k8scost} -- the ``microservice premium'' materialises as staffing. Prime Video's $>90\,\%$ cost reduction from Section~\ref{subsec:fourcases} shows the same dimension from the infrastructure side \citep{kolny2023primevideo}. Measured: the TCO split across build, platform, and run; cost per request; idle cost; and platform-team FTEs -- the discipline that makes cloud spend visible and attributable per team and feature is called \emph{FinOps}. Patterns differ enormously here, and in \emph{both} directions: the same workload can cost a multiple of itself depending on the structure it runs in and the shape of its load. \paragraph{D11 -- Team scaling (Conway fit).} \emph{The team grows from three to thirty. Do releases speed up -- or does everyone wait on everyone?} Conway's law, in one plain sentence: a system's structure ends up mirroring the communication structure of the organisation that builds it \citep{conway1968committees} -- which makes every architecture decision a team-structure decision, whether the architect intends that or not \citep{skelton2019team}. This dimension therefore asks how well a structure supports many teams working in parallel, and its operational core is the coordination question: how many teams can design, build, and release without waiting for each other? Measured: \emph{deployments per developer per day} as the team count grows -- DORA found this figure rising in loosely coupled organisations and falling in tightly coupled ones \citep{forsgren2018accelerate} -- and the number of teams able to release without cross-team coordination. Patterns differ because some topologies give each team its own independently deployable unit, while others make thirty people queue for one release train. \subsubsection{The new dimension (D12)} The last dimension is genuinely new, and assumption A6 forces it into the coordinate system. \paragraph{D12 -- AI integrability.} \emph{The new feature's core is an LLM call: eight seconds, paid per request, sometimes confidently wrong. How hard does the structure fight it?} AI integrability measures how cheaply a structure can host a component that is slow, fallible, and priced per call. Such a component needs three things from its surroundings, stated here in plain words because the rest of the script uses them constantly. A \emph{queue}: a waiting line in which requests park, so that an eight-second call -- or a provider outage, or a rate limit -- does not block everything behind it. A \emph{port}: a narrow, contract-shaped interface behind which the component's non-determinism is isolated, so that ordinary, deterministic tests can substitute a fake for it. A \emph{measurement point}: a place where the cost and quality of every single call are observable -- necessary because LLM providers price per \emph{token}, a fragment of a word, so that \emph{token cost} accrues per request rather than per month, and because a component that can be wrong must be scored continuously. The scoring instrument is the \emph{eval harness}: a versioned set of test inputs with expected qualities, against which the AI component's pass rate is computed -- the AI counterpart of a regression test suite \citep{zheng2023judging}, run as a CI gate alongside per-request cost budgets \citep{ford2022evolutionary}. Patterns differ sharply in whether queue, port, and measurement point come naturally or must be bolted on -- Part~\ref{part:ai} derives the full column. \begin{examplebox}[One system, one profile: a retail e-banking application] Walk a familiar system through the five groups. \emph{Load and speed:} traffic peaks on payday mornings; reads (balance checks) outnumber writes (payments) enormously; users tolerate two seconds, not ten -- D1 and D3 matter, D2 is modest. \emph{Correctness and trust:} a double-booked transfer is existential and the audit trail is a legal duty -- D4 and D6 are as high as they go; and if the login page dies, payments must keep clearing -- D5 high. \emph{Change and delivery:} releases are monthly and formally reviewed, but the system must absorb regulatory change for decades -- D7 high, D9 moderate. \emph{Economics and organisation:} the bank operates a platform organisation anyway, and dozens of teams must work in parallel -- D10 medium, D11 high. \emph{AI:} a chat assistant is attractive, but a confidently wrong answer about a balance is a safety problem -- D12 medium, with hard guardrails. The individual judgements are debatable; the point is not. A real system has a \emph{profile} -- demanding on a few dimensions, relaxed on others -- and writing that profile down rigorously is exactly what Section~\ref{sec:demand} does. \end{examplebox} \begin{thinkbox} Pick an app you use daily. Which three dimensions dominate it? On which dimension would its operator accept a bad rating without losing sleep? Compare with your neighbour -- where you disagree, you have found a \emph{weight} discussion, and that is precisely what a utility tree resolves (Section~\ref{sec:demand}). \end{thinkbox} \subsection{Why exactly these twelve} \label{subsec:admission} Twelve intuitions are not yet a coordinate system. This subsection adds the quality control: what kind of requirement qualifies at all, where the names come from, and which conditions a candidate had to pass to become a dimension. \paragraph{Quality attributes, not functions.} A \emph{functional requirement} states what the system shall do: compute interest, post a booking, render a feed. A \emph{quality attribute requirement} (the entrenched but misleading term is ``non-functional'') states how well, under which conditions, and at what cost. The architectural asymmetry between the two is the content of A3: ``post a booking'' can be implemented inside a layered monolith, as a \emph{saga} (a chain of compensating steps) across microservices, or as an event-sourced log -- three structures previewed in Section~\ref{subsec:patternpreview} and dissected in Part~\ref{part:patterns} -- the function is identical; the consistency guarantee, the latency distribution, the audit trail, and the cost of the next change are radically different \citep{bass2021software, sommerville2020modernes}. All twelve dimensions are therefore quality attributes or workload and constraint characteristics -- never features, which under-determine architecture. We use ``quality attribute'' as the primary term, following \citet{bass2021software}. \paragraph{The names: ISO/IEC 25010:2023.} \label{subsec:iso25010} % label kept for backward compatibility; sits inside subsection 2.3 and resolves to the same number as subsec:admission The naming standard for quality attributes is ISO/IEC 25010, the product quality model of the SQuaRE series; its 2023 revision defines nine characteristics, each with named sub-characteristics: functional suitability, performance efficiency, compatibility, interaction capability, reliability, security, maintainability, flexibility, and safety \citep{iso2023product, iso2023quality, iso2011product}. Three 2023 changes matter directly here: \emph{Safety} became a new top-level characteristic (fail safe, hazard warning -- exactly what one must state for a component that can produce wrong output with full confidence); \emph{usability} was recast as \emph{Interaction capability}; and \emph{portability} became \emph{Flexibility} with an explicit new \emph{scalability} sub-characteristic, while \emph{Security} gained \emph{resistance} -- sustaining operation under attack, the normative hook for prompt-injection robustness \citep{iso2023product, owasp2025llmtop10}. The 2023 vocabulary thus covers AI-bearing systems without private extensions -- A6 starts with the quality model itself -- and its sub-characteristics appear as the anchors in the third column of Table~\ref{tab:dimensions}. \paragraph{Three admission conditions.} With the raw material fixed by A3 and the names fixed by the standard, a candidate became one of the twelve only if it passed three conditions: \begin{enumerate} \item \textbf{Standard anchoring.} Each dimension maps to ISO/IEC 25010:2023 vocabulary, so the profile language stays anchored in the standard quality model; where a dimension reaches beyond it (cost, organisation), the anchor is stated in parentheses. \item \textbf{Discrimination.} Each dimension must discriminate between at least two of the seven patterns of Part~\ref{part:patterns} -- a dimension on which all patterns score alike carries no matching information. \item \textbf{Instrumentation.} Each dimension must have a \emph{defined response measure and a measurement instrument}, so that every rating over it is a testable prediction, not an adjective. This is A4 applied to the theory itself: \textbf{no instrument, no dimension.} \end{enumerate} You have already watched the third condition at work: every block of Section~\ref{subsec:dimtour} ended with how the dimension is measured, because a dimension without an instrument would not have entered this script. Note what the condition excludes: ``elegance'', ``future-proofness'', and similar candidates without a defined response measure. Twelve is also a didactic compromise: few enough to survey, rich enough to discriminate. \begin{hinweisbox} The nine characteristics are a \emph{taxonomy}, not a \emph{metric}: ISO/IEC 25010 measures nothing by itself, and quality taxonomies are neither complete nor free of overlap -- is a denial-of-service outage an availability, security, or performance problem? \citet{bass2021software} offer the pragmatic resolution this module adopts: do not argue about the box; write the concern as a six-part scenario with a response measure (Section~\ref{sec:demand}), and the classification question dissolves. ISO~25010 supplies vocabulary and completeness checklists; the measurement work is done by scenarios and fitness functions. \end{hinweisbox} \subsection{The reference card} \label{subsec:dimtable} Table~\ref{tab:dimensions} condenses Section~\ref{subsec:dimtour} into the module's canonical reference card. It adds nothing new: every term in its columns was defined above, and every row is the compact form of one dimension block you have already read. What the table adds is \emph{status}: every rating, weight, and fit cell of Parts~\ref{part:patterns}--\ref{part:fit} is expressed over exactly these twelve rows, each admitted under the three conditions of Section~\ref{subsec:admission}. When a later chapter says ``D7'', this table is what it means. \begin{sidewaystable} \centering \caption{The twelve profile dimensions with ISO/IEC 25010:2023 anchor, response measures, and measurement instruments. This is the canonical dimension table of the module: capability profiles (Table~\ref{tab:capability}), requirements profiles (Table~\ref{tab:requirements}), and the fit matrix (Table~\ref{tab:fitmatrix}) are all expressed over these dimensions.} \label{tab:dimensions} \footnotesize \begin{tabular}{@{}p{0.7cm}p{3.1cm}p{4.0cm}p{6.3cm}p{6.3cm}@{}} \toprule \textbf{\#} & \textbf{Dimension} & \textbf{ISO 25010:2023 anchor} & \textbf{Response measure (examples)} & \textbf{Measurement instrument} \\ \midrule D1 & Read scalability & Flexibility $\to$ scalability; Performance $\to$ capacity & Throughput at $k\times$ horizontal replication; cache hit ratio; p95 read latency under load & Step-profile load tests; production RED metrics \\ D2 & Write scalability \& elasticity & Flexibility $\to$ scalability & Sustained ingest rate; time-to-capacity after a load step; scale-to-zero cost & Load tests with load steps; elasticity-lag measurement \citep{jonas2019berkeley} \\ D3 & Latency \& predictability & Performance $\to$ time behaviour & p50/p95/p99 response time; cold-start frequency; tail-latency ratio p99/p50 & Distributed tracing (OpenTelemetry); latency budgets as CI gates \citep{ford2022evolutionary} \\ D4 & Consistency \& transactional integrity & Functional correctness; Reliability & Anomaly rate under concurrency; invariant-violation count ($0$ for ledgers); staleness bound (s) & Jepsen-style consistency tests; invariant checks; reconciliation jobs \citep{kleppmann2017designing} \\ D5 & Availability \& fault isolation & Reliability $\to$ availability, fault tolerance & SLO attainment; error-budget burn; blast radius (\% of functionality lost per component failure); MTTR & SLOs and error budgets; chaos experiments as continual holistic fitness functions \citep{basiri2016chaos, ford2022evolutionary} \\ D6 & Security \& auditability & Security $\to$ accountability, non-repudiation, resistance & Time to reconstruct a complete audit trail for one transaction; \% of state changes journaled; audit scope size & Audit-trail drills; immutable logs / event sourcing; PCI/FINMA scope reviews \citep{finma2023oprisk, pcissc2022pcidss} \\ D7 & Evolvability \& maintainability & Maintainability $\to$ modularity, modifiability, analysability & Change dispersion (modules touched per average feature); coupling metrics (CBO, instability $I$); declared-boundary violations (target $0$) & ArchUnit / Spring Modulith verification as CI gates; CK metrics \citep{chidamber1994metrics, martin2003agile, drotbohm2023modulith} \\ D8 & Simplicity \& time-to-market & (Process quality; Maintainability $\to$ analysability) & Time from empty repository to first production release; onboarding time to first merged PR; number of runtime technologies & Delivery calendar; team surveys; tech-radar count \\ D9 & Testability \& deployability & Maintainability $\to$ testability & Test feedback time; \% of hermetic tests (no integrated environment needed); deployment frequency; change failure rate & Pipeline telemetry; DORA capability items on independent testing and deployment \citep{forsgren2018accelerate} \\ D10 & Operating cost efficiency & (Cost; Performance $\to$ resource utilization) & TCO split build/platform/run; cost per request; idle cost; platform-team FTEs & FinOps reporting; cost-per-request telemetry; TCO benchmarks \citep{portainer2024k8scost, kolny2023primevideo} \\ D11 & Team scaling (Conway fit) & (Organisational) & Deployments per developer per day as team count grows; number of teams able to release without cross-team coordination & DORA scaling analysis \citep{forsgren2018accelerate}; Team Topologies review \citep{skelton2019team, conway1968committees} \\ D12 & AI integrability & Safety $\to$ fail safe, operational constraint; Security $\to$ resistance & Tolerance for seconds-scale latency and asynchronous integration; feasibility of isolating non-determinism behind contracts; token-cost observability per request & Eval-harness pass rate $\geq$ threshold in CI; cost budgets per request as fitness functions \citep{ford2022evolutionary, zheng2023judging} \\ \bottomrule \end{tabular} \end{sidewaystable} Three remarks on individual dimensions. \textbf{D9 fuses testability and deployability deliberately.} DORA's 2017 analysis found precisely this pair -- can the team test without an integrated environment, and deploy independently of other teams -- to be the architecture characteristics contributing most to continuous delivery, more than test and deployment automation itself \citep{dora2017sodr, forsgren2018accelerate}. Both are surface expressions of the same underlying variable, coupling; splitting them would double-count one property. \textbf{D10 and D11 reach beyond the product quality model}, and the table says so with parenthesised anchors. They are admitted nonetheless because they pass the other two conditions: both discriminate between patterns, and both are instrumented -- by the personnel-dominated TCO evidence and the DORA scaling analysis presented in Section~\ref{subsec:dimtour} \citep{fowler2015premium, portainer2024k8scost, forsgren2018accelerate, conway1968committees, skelton2019team}. \textbf{D12 is the only genuinely new dimension, and A6 forces it.} It measures how cheaply a structure can host a component that is slow, fallible, and priced per call -- concretely, whether the pattern naturally provides the \emph{queue}, the \emph{port}, and the \emph{measurement point} introduced in Section~\ref{subsec:dimtour}. Patterns differ sharply here -- exactly the discrimination condition -- and Part~\ref{part:ai} derives the D12 ratings in detail. \begin{keypoint} The twelve dimensions of Table~\ref{tab:dimensions} are the module's canonical coordinate system: ISO-anchored, pattern-discriminating, and -- without exception -- equipped with response measures and instruments. Every capability rating is a testable prediction on this frame; every requirement weight is a utility-tree-derived priority on it; every fit cell is their rule-based comparison. When in doubt anywhere in this script, return to this table. \end{keypoint} % ============================================ % SECTION: CONSTRUCTING THE DEMAND SIDE -- R(a) % ============================================ \section{Constructing the Demand Side: The Requirements Profile $R(a)$} \label{sec:demand} The demand side of the framework is the requirements profile \[ R(a) = \bigl(w_1(a), \dots, w_{12}(a);\; S(a);\; K(a)\bigr): \] twelve priority weights, one workload shape, one set of hard constraints. None of these is written down by intuition; each is \emph{produced} by a defined method, and each subsection ends by naming the component of $R(a)$ it has just produced. \subsection{From stakeholder wishes to architecturally significant requirements} \label{subsec:asr} Not all requirements shape architecture; most functional ones do not (A3). The ones that do have a name: \begin{definitionbox}[Architecturally significant requirement (ASR)] An \emph{architecturally significant requirement} is a requirement that has a profound effect on the architecture -- one whose late accommodation would be disproportionately expensive -- and that is typically also difficult to achieve \citep{bass2021software}. \end{definitionbox} The grounded-theory study of \citet{chen2013characterizing} -- 90 practitioners from over 500 organisations -- found that ASRs are typically poorly specified, vague, and implicit, hidden inside business goals (``we plan to enter three new markets next year'' implies a scalability and a compliance ASR) or assumed context. They cannot be read off a requirements document; they must be \emph{elicited}. The established format is the SEI's Quality Attribute Workshop (QAW) \citep{barbacci2003quality}, whose essence is two design choices. First, \emph{who is in the room}: not the development team alone, but the stakeholders whose concerns the architecture must balance -- users, operators, auditors, regulators, product owners \citep{iso2022architecture}. Second, the \emph{sequence}: business and mission drivers first, then identification of architectural drivers, scenario brainstorming, consolidation, prioritisation by stakeholder vote, and refinement of the top candidates into the measurable form of Section~\ref{subsec:sixparts}. \emph{Produced:} the raw material of $R(a)$ -- a prioritised pool of candidate ASRs, elicited from stakeholders and business goals, but not yet measurable. \subsection{Quality attribute scenarios: the measurable form} \label{subsec:sixparts} A4 demands that each candidate requirement be brought into a form that can discriminate between architectures. That form is fixed: \begin{definitionbox}[Quality attribute scenario] A \emph{quality attribute scenario} is a short, testable specification of a quality requirement, consisting of six parts \citep{bass2021software}: \begin{enumerate} \item \textbf{Source of stimulus} -- who or what triggers the situation: a user, another system, an attacker, a developer. \item \textbf{Stimulus} -- the arriving event: a request, a failure, a change request, a load spike. \item \textbf{Environment} -- the operating condition: normal operation, overload, degraded mode, development time. \item \textbf{Artifact} -- the part of the system that is stimulated: the whole system, a component, a data store. \item \textbf{Response} -- the desired observable reaction. \item \textbf{Response measure} -- the quantity, with number and unit, by which success is judged: latency percentile, recovery time, person-days, detection rate. \end{enumerate} \end{definitionbox} The response measure is the non-negotiable part. ``The system shall be scalable'' names an aspiration; a scenario with a response measure names a test. Without a number and a unit, the requirement cannot be falsified, and an unfalsifiable requirement cannot discriminate between candidate architectures. Bass et al.\ distinguish \emph{general scenarios} (attribute-specific templates) from \emph{concrete scenarios} (instances filled in for one system) \citep{bass2021software}; an application class in Part~\ref{part:applications} carries characteristic concrete scenarios that act as the measuring rod for every pattern held against it. \begin{examplebox}[Worked scenario 1: availability in a payment service (banking)] \emph{Source:} a heartbeat monitor. \emph{Stimulus:} reports the failure of one application server. \emph{Environment:} normal operation, mid-day load. \emph{Artifact:} the payment service. \emph{Response:} requests are redirected to replicas; operations staff are notified; in-flight transactions either complete or roll back atomically. \emph{Response measure:} failover completed in under $30$\,s; zero transactions lost or double-posted. ``The payment service shall be highly available'' hides at least three architectural decisions that the scenario exposes: replicas (redundancy tactic), failure detection (heartbeat tactic), and transactional atomicity across the failover -- a guarantee some patterns provide structurally and others do not. The response measure -- $30$\,s, zero loss -- is directly executable as a chaos experiment \citep{basiri2016chaos}: kill an instance under load and measure. The scenario is simultaneously a requirement, a design driver, and a test specification. \end{examplebox} \begin{examplebox}[Worked scenario 2: safety in an AI advisory platform (Axis B)] \emph{Source:} a customer. \emph{Stimulus:} submits a request for which the LLM generates a factually wrong recommendation. \emph{Environment:} normal operation. \emph{Artifact:} the advisory platform. \emph{Response:} the deterministic validation layer detects and blocks the answer and escalates to a human advisor. \emph{Response measure:} detection rate $\geq 99\,\%$ on the versioned evaluation set, at less than $2$\,s added latency. Two things are notable. First, the six-part form needed \emph{no extension} for a non-deterministic component -- A6 at work: the stimulus is probabilistic (the model \emph{will} sometimes hallucinate), and the requirement is placed not on the model but on the \emph{system around it}. Second, the response measure presupposes an artefact: a versioned evaluation set against which a detection rate can be computed at all -- the eval harness, the AI counterpart of a regression test suite (Part~\ref{part:ai}). In ISO/IEC 25010:2023 terms, this is a \emph{Safety} scenario (fail safe, hazard warning) \citep{iso2023product}. \end{examplebox} \emph{Produced:} the candidate ASRs in falsifiable form -- concrete six-part scenarios, each with a response measure. \subsection{The utility tree: from scenarios to weights} \label{subsec:utilitytree} A workshop produces more scenarios than any analysis can carry. The \emph{utility tree}, introduced with the ATAM, prioritises them top-down \citep{kazman2000atam, bass2021software}: the root ``Utility'' branches into quality attributes, these into refinements, and each refinement into concrete scenarios as leaves. Every leaf is rated on two independent dimensions, each High/Medium/Low: \textbf{business importance} (what does it cost us if this scenario fails?) and \textbf{achievement difficulty} (how hard is it, architecturally, to satisfy?). The \textbf{(H,\,H) leaves} -- important \emph{and} hard -- are the architecturally critical points on which analysis and design effort concentrate. Figure~\ref{fig:utilitytree} shows a compressed example for a core-banking system. \begin{figure}[htbp] \centering \begin{tikzpicture}[ sysbox/.style={rectangle, draw, rounded corners=4pt, align=center, font=\scriptsize\sffamily, line width=0.8pt, inner sep=4pt}, root/.style={sysbox, fill=bankblue!20, draw=bankblue, font=\small\sffamily\bfseries, minimum height=1.1cm, minimum width=1.9cm}, attr/.style={sysbox, fill=bankgreen!15, draw=bankgreen, minimum width=2.6cm, minimum height=0.85cm}, leafhh/.style={sysbox, fill=bankred!15, draw=bankred, text width=6.6cm}, leaf/.style={sysbox, fill=gray!12, draw=gray!60!black, text width=6.6cm}, arr/.style={-{Stealth[length=2.2mm]}, thick, gray!60!black} ] \node[root] (util) at (0,0) {Utility}; \node[attr] (cons) at (3.6,2.7) {Consistency \&\\integrity}; \node[attr] (avail) at (3.6,0.9) {Availability}; \node[attr] (perf) at (3.6,-0.9) {Performance}; \node[attr] (mod) at (3.6,-2.7) {Modifiability}; \node[leafhh] (l1) at (9.2,2.7) {\textbf{(H,\,H)} No booking lost or double-posted under concurrent node failure; invariant violations $= 0$}; \node[leafhh] (l2) at (9.2,0.9) {\textbf{(H,\,H)} Failover of the payment service $< 30$\,s with zero transaction loss}; \node[leaf] (l3) at (9.2,-0.9) {(H,\,M) Card authorisation p95 $< 2$\,s at $3\times$ baseline load}; \node[leaf] (l4) at (9.2,-2.7) {(M,\,H) New regulatory report integrated in $\leq 10$ person-days, touching $\leq 2$ modules}; \draw[arr] (util) -- (cons); \draw[arr] (util) -- (avail); \draw[arr] (util) -- (perf); \draw[arr] (util) -- (mod); \draw[arr] (cons) -- (l1); \draw[arr] (avail) -- (l2); \draw[arr] (perf) -- (l3); \draw[arr] (mod) -- (l4); \end{tikzpicture}% \caption{A compressed utility tree for a core-banking system. Leaves are concrete scenarios (abbreviated to their response measures) rated by (business importance, achievement difficulty); the highlighted (H,\,H) leaves determine which dimensions receive High weight in the requirements profile.} \label{fig:utilitytree} \end{figure} For the framework, the utility tree performs the decisive job: it is the \emph{methodical derivation of the weights}. A dimension $D_i$ receives $w_i(a) = \text{High}$ exactly when the class's characteristic utility tree has (H,\,H) leaves under the corresponding attribute; Medium and Low follow from the remaining leaf ratings. When Part~\ref{part:applications} assigns core banking a High weight on consistency, that is a claim about documented (H,\,H) scenarios, not an opinion of the lecturer. One consequence is announced here and cashed in at the match (Section~\ref{sec:fit}): \textbf{High weights carry veto power} -- a High weight marks a binding scenario, one whose failure is existential for the class. \emph{Produced:} the twelve priority weights $w_1(a), \dots, w_{12}(a) \in \{\text{H}, \text{M}, \text{L}\}$. \subsection{What a weight means, dimension by dimension} \label{subsec:weightexamples} The utility tree says \emph{how} a weight is derived; it does not yet say what a High \emph{feels like}. So walk the twelve dimensions once more with a concrete question in mind: which kind of application pushes this dimension to High -- and which kind can honestly leave it at Low? Table~\ref{tab:weightexamples} answers with one example each, and almost every example is drawn from the ten application classes whose full profiles Part~\ref{part:applications} derives. \begin{table}[htbp] \centering \caption{What a High and a Low requirement look like, dimension by dimension. Most examples anticipate one of the ten application classes of Part~\ref{part:applications} (Table~\ref{tab:requirements}); where no class weights the dimension Low, the Low example is a deliberately generic system outside the class set. A High weight is a veto claim backed by (H,\,H) utility-tree leaves, a Low weight a deliberate release.} \label{tab:weightexamples} \footnotesize \begin{tabular}{@{}p{2.7cm}p{5.7cm}p{5.6cm}@{}} \toprule \textbf{Dimension} & \textbf{A High requirement: example} & \textbf{A Low requirement: example} \\ \midrule D1 Read scalability & A public social/content feed: thousands of reads per write, and every user sits on the read path \citep{krikorian2013timelines} & An ERP used by clerks: load is bounded by headcount and office hours \\ D2 Write scalability \& elasticity & E-commerce checkout on Black Friday: $10$--$50\times$ seasonal write peaks \citep{shopify2024bfcm}; IoT ingest that never pauses & A BI warehouse loaded once, nightly, inside a batch window \\ D3 Latency \& predictability & Interactive messaging: visible lag kills the product & An overnight Monte-Carlo run: the makespan matters, not any single millisecond \\ D4 Consistency \& integrity & A payments ledger: one double booking is an existential defect & A social feed: a stale like-count harms nobody \\ D5 Availability \& fault isolation & E-commerce: downtime converts directly into lost revenue per minute \citep{linden2006data} & An internal report generator: hours of downtime are tolerable \\ D6 Security \& auditability & Core banking under FINMA/BCBS duties: the audit trail is law \citep{finma2023oprisk, bcbs2013rdarr} & An IoT telemetry buffer: transient, impersonal data \\ D7 Evolvability \& maintainability & Any system built to live for decades: banking, ERP \citep{reuters2017cobol, sap2020maintenance} & A one-off data migration script: it runs once and is deleted \\ D8 Simplicity \& time-to-market & An internal back-office tool: its value is that it ships this quarter & A core ledger: care beats speed, and D8 yields \\ D9 Testability \& deployability & Anything changed weekly by several teams: releasing must not require heroics & A frozen batch job that changes twice a year \\ D10 Operating cost efficiency & Per-request-priced AI platforms and batch compute farms: run cost is a first-order product property & A core banking system: the run bill is dwarfed by correctness and compliance budgets \\ D11 Team scaling (Conway fit) & A platform built by thirty teams: coordination cost is the bottleneck \citep{skelton2019team} & A two-person project: Conway's law has nothing to mirror \\ D12 AI integrability & The AI-native advisory platform: hosting slow, fallible, per-call-priced components \emph{is} the product & A classical accounting module: no AI component in sight \\ \bottomrule \end{tabular} \end{table} First, be clear about what a weight \emph{asserts}. A High weight is not enthusiasm; it is a claim with teeth: this dimension carries (H,\,H) leaves -- scenarios whose failure is existential -- and it may therefore \emph{veto} a structure in the match (Section~\ref{sec:fit}), however well that structure scores elsewhere. A Low weight is equally deliberate: not ``we do not care'', but ``we will not pay structure for this'' -- the Monte-Carlo team genuinely should not spend one design decision on millisecond latency. Medium is the tradeable middle. Because a High is a veto claim, every High in a profile must survive the question: \emph{show me the (H,\,H) leaf}. Second, notice the most instructive contrast in the table: the D4 row. The payments ledger and the social feed are near-perfect \emph{mirror images} -- for the ledger a wrong number is existential and a stale one merely embarrassing, for the feed precisely the reverse: a stale feed is acceptable, an unavailable one is not. Part~\ref{part:applications} uses exactly this pair (core banking against social/content) as its didactic anchor, because a structure optimised for one is close to pessimal for the other. Third, the D7 and D8 rows expose a tension inside a single organisation: shipping fast and living long pull in opposite directions, and both are legitimately High -- in \emph{different} systems. The interesting case is the system that claims both at once: the unglamorous internal workflow tool must ship this quarter \emph{and} absorb reorganisations for the next fifteen years \citep{glass2002facts}. Whether one structure can honour both claims is precisely a matching question -- and the profile we assemble next makes it concrete. \subsection{Workload shape and hard constraints} \label{subsec:shapeconstraints} Two components of $R(a)$ remain; neither is a weight, and both are produced by inventory rather than prioritisation. \textbf{The workload shape $S(a)$} states how load arrives: \emph{interactive} request/response, \emph{continuous stream}, \emph{scheduled batch}, or an explicitly \emph{hybrid} combination -- with its quantitative signature: read/write ratio, load pattern (steady, diurnal, seasonal, spiky), latency budget, data volume, change rate. The dominant shape matters because patterns have native shapes too (Section~\ref{sec:supply}): a batch pipeline cannot carry an interactive core, however well its ratings read, and the match enforces that as a gate. The signature is measured, not guessed: read/write ratios from access logs, load patterns from telemetry, latency budgets from the binding scenarios. \textbf{The hard constraints $K(a)$} are collected as an explicit inventory: regulatory obligations (e.g.\ BCBS~239, PCI~DSS v4.0, the EU AI Act \citep{bcbs2013rdarr, pcissc2022pcidss, eu2024aiact}), team size and skills (Conway), budget, and mandated platforms. The separation from weights is load-bearing: \textbf{constraints are knock-out filters, never weights}. A pattern that violates a constraint is excluded \emph{before} any scoring, never averaged away \citep{keeney1993decisions}: a payment architecture that cannot produce the audit trail PCI~DSS requires is not ``weak on one criterion'' -- it is not a candidate. \emph{Produced:} the workload shape $S(a)$ and the constraint set $K(a)$. \subsection{$R(a)$ assembled} \label{subsec:reqassembled} The three methods together yield the demand side of the framework: \begin{definitionbox}[Requirements profile $R(a)$] Each application class $a \in A$ has a \emph{requirements profile} \[ R(a) = \bigl(w_1(a), \dots, w_{12}(a);\; S(a);\; K(a)\bigr) \] where $w_i(a) \in \{\text{High}, \text{Medium}, \text{Low}\}$ is the priority weight of dimension $D_i$ (Table~\ref{tab:dimensions}), derived from the class's characteristic utility tree (A4); $S(a)$ is the dominant \emph{workload shape} with its quantitative signature; and $K(a)$ is the set of \emph{hard constraints} -- regulatory obligations, team size and skills, budget, mandated platforms -- which act as knock-out filters, not weights \citep{keeney1993decisions}. \end{definitionbox} \begin{examplebox}[Worked construction: $R(\text{C10})$ -- the AI-native advisory platform] C10 is the class of the course project: an advisory platform whose answers are generated by LLMs over a grounded knowledge base \citep{lewis2020rag, zaharia2024compound}. Its characteristic utility tree has (H,\,H) leaves under five attributes: every statement needs provenance and every agent step must be logged -- observability is \emph{domain functionality} here ($\to$ D6); models, prompts, and frameworks change at an extreme rate ($\to$ D7); evals are the operative meaning of testability ($\to$ D9); the platform is expensive \emph{per request} (tokens, GPU), not per user -- a run-cost class no classical profile contains ($\to$ D10); and the value proposition depends on hosting slow, fallible, per-call-priced components ($\to$ D12). Hence: \begin{itemize} \item \textbf{Weights:} High on D6, D7, D9, D10, D12; Medium on D1, D3, D4, D5, D8; Low on D2 and D11. Two Mediums surprise students: D3, because users accept seconds-to-minutes for an advisory answer -- the High-grade concern is cost per request, not speed; and D4, because the profile is a hybrid -- the knowledge index may be eventually consistent while the transaction and audit path is strictly ACID. \item \textbf{Workload shape:} $S(\text{C10})$ is explicitly hybrid -- interactive request/response for the advisory dialogue, batch/asynchronous pipelines for indexing and evaluation runs. \item \textbf{Constraints:} $K(\text{C10}) = \{$EU AI Act 2024/1689: logging, documentation, human-oversight duties, potentially high-risk classification \citep{eu2024aiact}; GDPR \citep{eu2016dsgvo}$\}$. \end{itemize} $R(\text{C10})$ is now a complete, argued profile: every High traces to (H,\,H) scenarios, the shape is stated with its signature, and the constraints are knock-out conditions for the match. \end{examplebox} One profile could be a coincidence. A second, deliberately unglamorous one shows that the method produces genuinely \emph{different} demand -- and it takes eight lines. \begin{examplebox}[Worked construction: $R(\text{back-office})$ -- an internal workflow tool] Consider the university's grade-publication portal, or any internal tool that routes approvals, files, and postings between clerks -- the industry's modal, unglamorous case. Its (H,\,H) leaves sit under five attributes. \textbf{High} on D4: an approval or a posting must never be lost or duplicated -- the records \emph{are} the process. High on D6: statutory retention (e.g.\ Swiss OR~958f) and internal-control rules make the approval trail auditable by obligation. High on D7: the cost of this class lives almost entirely in evolution -- reorganisations and process changes over a $10$--$20$-year horizon, not operation \citep{glass2002facts}. High on D8: built by a small internal IT team, its value is that it ships this quarter. High on D10: an internal tool earns no revenue to bill infrastructure against, so run cost must stay near zero. \textbf{Medium} on D3 and D9 (responsive enough for office work; releases are routine but not weekly). \textbf{Low} everywhere else: load is bounded by employee headcount (D1, D2), hours of downtime are tolerable (D5), one team suffices (D11), and no AI component is in sight (D12). \textbf{Shape:} interactive request/response at office-hours load. \textbf{Constraints:} $K = \{$retention law; internal-control rules; GDPR \citep{eu2016dsgvo}$\}$. Now place the two profiles side by side. Each has five Highs, but not the same five: they overlap where regulation and longevity reach everywhere (D6, D7, D10) and diverge exactly on the discriminating pairs -- the back-office tool demands D4 and D8 where the advisory platform is relaxed, the platform demands D9 and D12 where the tool is indifferent. Different High-sets arm \emph{different vetoes}, so no single structure can be the answer to both demands -- which is A2 made operational, and precisely why a matching step (Section~\ref{sec:fit}) exists at all. Section~\ref{subsec:minimatch} runs the match for the first profile; a think-box there hands you the second. \end{examplebox} Part~\ref{part:applications} repeats exactly this construction for ten application classes -- the two just built among them, as C10 and C3 -- and Table~\ref{tab:requirements} is nothing but its result, ten profiles side by side, every High argued from documented evidence. \begin{projektbox} In week~2 you will run a compressed Quality Attribute Workshop for the \textbf{Portfolio Intelligence Platform}. In stakeholder roles (retail customer, compliance officer, operations engineer, product owner), you will brainstorm, consolidate, and prioritise quality attribute scenarios, refine the top candidates into the six-part form -- each with a numeric response measure -- and assemble them into a utility tree. Deliverable: at least eight concrete scenarios, at least three addressing the platform's AI components (answer correctness, token cost per request, provider migration), with the (H,\,H) leaves identified. This is not a warm-up exercise: the (H,\,H) leaves become the weights of your requirements profile, which you will match against the capability profiles of Part~\ref{part:patterns} in the ADR you record in week~6. \end{projektbox} \begin{keypoint} \textbf{Maxim 6.} An architecture decision without a response measure is an opinion; with a response measure and a fitness function it is a testable hypothesis. $R(a)$ operationalises this on the demand side: elicited ASRs, made falsifiable as scenarios, prioritised into weights by the utility tree, completed by a measured workload shape and an explicit constraint inventory. \end{keypoint} \begin{thinkbox} Take ``the platform shall be user-friendly'' and turn it into a six-part scenario with a response measure. What did you have to decide -- about users, tasks, context, thresholds -- that the sentence silently left open? Now do the same for ``the AI must not hallucinate''. Which was harder to make measurable, and why? \end{thinkbox} % ============================================ % SECTION: CONSTRUCTING THE SUPPLY SIDE -- C(p) % ============================================ \section{Constructing the Supply Side: The Capability Profile $C(p)$} \label{sec:supply} The supply side asks the symmetric question: what can a given structure deliver on the same twelve dimensions? The answer is the capability profile \[ C(p) = \bigl(c_1(p), \dots, c_{12}(p);\; S(p)\bigr), \] and -- exactly as on the demand side -- each rating is \emph{derived}, not asserted. But before anything can be rated, the candidates themselves must be on the table. \subsection{The seven candidates: a first look} \label{subsec:patternpreview} So far, the patterns have been little more than names in forward references. That is not good enough for what follows: the derivation examples of this section and the worked match of Section~\ref{sec:fit} only mean something if the reader can picture the structures being rated. Table~\ref{tab:patternpreview} therefore introduces the seven candidates -- the set $P$ of the framework -- each in one sentence, with its signature strength and its signature cost. The two-letter codes are used throughout the script. You have, in fact, already met four of them in production dress: Stack Overflow runs a layered-style monolith, Monzo runs microservices, Prime Video's failed design was serverless, and Segment's rollback was a microservice cut (Table~\ref{tab:fourcases}). \begin{table}[htbp] \centering \caption{The seven candidate patterns -- the set $P$ of the framework -- in one sentence each. Part~\ref{part:patterns} dissects every pattern with its topology, tactics, and footnoted capability profile; here they need only be concrete enough that the derivation examples below and the worked match of Section~\ref{sec:fit} have referents.} \label{tab:patternpreview} \footnotesize \begin{tabular}{@{}p{2.4cm}p{5.4cm}p{3.0cm}p{3.2cm}@{}} \toprule \textbf{Pattern (code)} & \textbf{Structure in one sentence} & \textbf{Signature strength} & \textbf{Signature cost} \\ \midrule Layered / 3-tier (L) & One deployable, cut into horizontal \emph{technical} layers: presentation, logic, persistence & Simple and cheap: one build, one database, one process & A typical feature cuts across all layers \\ Modular monolith (MM) & One deployable, cut into \emph{domain} modules with machine-enforced boundaries & Monolith economics with modular evolvability & Boundaries erode without continuous governance \\ Hexagonal / ports \& adapters (HX) & A domain core behind technology-neutral ports with swappable adapters -- a discipline \emph{inside} a host, not a distribution style & Hermetic testability; swappable technology & Indirection that pays off only under change \\ Microservices (MS) & Many independently deployable services, database per service & Team scaling; independent deployment & No ACID across services; the highest operating cost in the set \\ Event-driven (EDA) & Components communicate through asynchronous events via a broker & Decoupling, elasticity, fault isolation & Eventual consistency; end-to-end testing is hard \\ Pipes-and-filters / batch (PF) & Data flows through a chain or DAG of processing steps & Throughput and reproducibility for batch work & Not built for interactive latency \\ Serverless / FaaS (SL) & Functions on managed infrastructure: scale-to-zero, per-execution billing & Elasticity; zero idle cost & Cold starts; cost inverts under sustained load \\ \bottomrule \end{tabular} \end{table} Each row compresses an established literature: layered and pipes-and-filters are classical styles \citep{buschmann1996posa, shaw1996software, richards2025fundamentals}; the modular monolith is the domain-partitioned refinement of the monolith \citep{su2024modular, richards2025fundamentals}; hexagonal is Cockburn's ports-and-adapters discipline \citep{cockburn2005hexagonal, cockburn2024hexagonal}; microservices follow \citet{lewis2014microservices} and \citet{newman2021building}; event-driven architecture rests on messaging patterns \citep{hohpe2003enterprise}; serverless on the Berkeley analysis \citep{jonas2019berkeley, cncf2018serverless}. One entry needs flagging now because it behaves unlike the others: \textbf{HX is not a competitor in the same race}. It organises dependencies \emph{inside} whichever host structure it is applied to, and therefore composes with the other six -- a hexagonal modular monolith is one coherent design, not two rival ones. The next subsection makes that demarcation precise; Part~\ref{part:patterns} devotes a full chapter to each pattern. \subsection{Tactics: the causal mechanism from structure to quality} \label{subsec:patterntactic} Students routinely conflate three levels of design vocabulary; the framework keeps them apart, because its explanatory mechanism lives exactly in the gap between them. \begin{definitionbox}[Architectural pattern (style)] An \emph{architectural pattern} -- used synonymously with \emph{architectural style}, following common usage in \citet{richards2025fundamentals} and the style taxonomy of \citet{shaw1996software} -- is a named, documented macro-structure of a system or subsystem: a topology of elements, permitted relations between them, and known consequences. \end{definitionbox} \begin{definitionbox}[Architectural tactic] A \emph{tactic} is an elementary design decision that directly influences the response of one quality attribute -- the atomic unit of architectural design \citep{bachmann2003deriving, bass2021software}. Examples: \emph{heartbeat} and \emph{redundancy} (availability), \emph{use an intermediary} and \emph{defer binding} (modifiability), \emph{introduce concurrency} and \emph{maintain multiple copies} (performance). \end{definitionbox} The causal link between the two levels is the theoretical backbone of the matching apparatus: \textbf{patterns are bundles of tactics}. An event-driven architecture structurally packages ``use an intermediary'' (modifiability) and ``introduce concurrency'' (performance) while structurally impeding ``transactions'' (consistency) \citep{bass2021software}; it therefore helps some quality attributes and hurts others \emph{by construction}, not by accident. \begin{keypoint} Patterns are bundles of tactics: a pattern structurally privileges some tactics while impeding others, so every pattern helps some quality attributes and hurts others \emph{by construction}. This causal chain -- topology $\to$ tactics $\to$ quality attribute responses -- makes every $++$ and every $--$ in a capability profile explainable and testable rather than a matter of taste. \end{keypoint} Two demarcations matter for the rest of the script. First, \textbf{hexagonal architecture (ports and adapters) is a pattern of dependency organisation, not a distribution style} \citep{cockburn2005hexagonal, cockburn2024hexagonal}: orthogonal to the monolith/microservices axis, it \emph{composes} with the other six patterns -- a hexagonal modular monolith and hexagonal microservices are both coherent designs. Second, patterns are always evaluated \emph{per subsystem}, not per company logo: real systems combine a core pattern with different patterns at their edges, and Part~\ref{part:fit} treats such hybrids as the normal case. \subsection{Deriving a rating $c_i(p)$} \label{subsec:derivation} A rating $c_i(p) \in \{++, +, \circ, -, --\}$ is an \emph{ordinal} claim: how well does the pattern's topology structurally support dimension $D_i$? It is derived from three sources of evidence, applied in order. \begin{enumerate} \item \textbf{Tactics analysis.} Which tactics does the topology make cheap, and which does it impede? This is the causal core: a $--$ that cannot be traced to a structural impediment is an assertion, not a rating. \item \textbf{Published ratings.} The star ratings of \citet{richards2025fundamentals} calibrate ours, five-step to five-step ($5\star \to ++$, $4\star \to +$, $3\star \to \circ$, $2\star \to -$, $1\star \to --$), and \textbf{every deviation from the source ratings is footnoted} in Part~\ref{part:patterns}. Where no stars exist (hexagonal, serverless), the profile is derived from primary sources \citep{cockburn2024hexagonal, jonas2019berkeley, cncf2018serverless} and flagged. \item \textbf{Documented production systems.} Cases like those of Table~\ref{tab:fourcases} act as calibration points: a rating that contradicts a documented production result must either explain the context difference or yield. \end{enumerate} Two micro-derivations make the method concrete -- one positive rating, one negative. \begin{examplebox}[Micro-derivation 1: why event-driven architecture rates $++$ on D7 (evolvability)] \emph{Tactics analysis.} The broker topology is the tactic ``use an intermediary'' \citep{bass2021software} built into the macro-structure: producers publish events to a broker; consumers subscribe. A new consumer -- a recommendation engine, a moderation service, an audit feed -- therefore attaches to the event stream \emph{without touching a single producer}. The response measure of D7, change dispersion (modules touched per average feature), is structurally minimised for consumer-side growth: adding functionality is additive, not invasive. \emph{Published rating.} Richards and Ford rate the style's evolvability at five stars \citep{richards2025fundamentals} -- $++$ under the mapping, no deviation to footnote. \emph{Production evidence.} LinkedIn's Kafka ecosystem grew for a decade by attaching new consumers to the same durable log \citep{kreps2011kafka, lee2019kafka}. The rating is a trade, exactly as A2 predicts: the same intermediary that decouples producers from consumers also impedes transactions and hides the workflow -- the costs land on D4 and D9. \end{examplebox} \begin{examplebox}[Micro-derivation 2: why microservices rate $--$ on D4 (consistency)] \emph{Tactics analysis.} The weakness is structural, not incidental. Database-per-service is constitutive of the pattern, and it means \emph{no ACID transaction spans a service boundary}. A business invariant that crosses services (order $\to$ stock $\to$ ledger) must be maintained by a \emph{saga} -- a sequence of local transactions with compensating actions -- which trades atomicity for choreography or orchestration complexity \citep{richardson2018microservices, newman2021building}: intermediate states are visible, and compensation is not rollback. Against D4's response measures (anomaly rate under concurrency; invariant-violation count, target $0$ for ledgers), the topology impedes the transaction tactic by construction. Hence $--$. \emph{Production evidence.} A documented mitigation exists, but it is conditional -- Monzo makes sagas work at organisational scale under extreme technological homogeneity \citep{sewell2024monzo} -- and the matching procedure of Section~\ref{sec:fit} handles exactly this case: a veto on a High-weight dimension that only a \emph{documented} mitigation can lift. \end{examplebox} The two micro-derivations show the method at full depth on two single cells; Table~\ref{tab:capexamples} sweeps the same question -- \emph{what structural fact earns the rating?} -- across all twelve dimensions at once, naming for each the topology that supports it best and the topology that fights it hardest. \begin{table}[htbp] \centering \caption{What $++$ and $--$ look like, dimension by dimension: the structural fact behind the extreme ratings, with the patterns of Table~\ref{tab:patternpreview} that exhibit it. Where the honest rating of a named pattern falls short of the column's extreme -- $+$ instead of $++$, $-$ or $\circ$ instead of $--$ -- the entry says so on either side: ordinal distances are part of the claim.} \label{tab:capexamples} \footnotesize \begin{tabular}{@{}p{2.7cm}p{5.7cm}p{5.6cm}@{}} \toprule \textbf{Dimension} & \textbf{What $++$ looks like structurally} & \textbf{What $--$ (or the weak end) looks like} \\ \midrule D1 Read scalability & Independently replicated, cacheable read paths per service or consumer (MS, EDA) & Reads entangled with one schema and one application tier (L: $\circ$ -- caching relieves it, the single write path remains) \\ D2 Write scalability \& elasticity & Partitioned ingest with elastic consumers (EDA, SL) & One relational database receiving every write (L) \\ D3 Latency \& predictability & In-process calls: no network hop, no cold start (L, MM: $+$) & Answers arrive in makespans, not milliseconds (PF -- by design) \\ D4 Consistency \& integrity & One ACID transaction boundary around all state (L, MM) & Sagas across service databases (MS); eventual consistency through a broker (EDA) \\ D5 Availability \& fault isolation & Bulkheaded services: blast radius one service (MS, EDA) & One process: blast radius $100\,\%$ by construction (L, MM: $-$) \\ D6 Security \& auditability & One audit log, one small compliance scope (L, MM, PF: $+$) & An honest middle with two faces: per-service isolation \emph{versus} audit trails scattered across asynchronous hops (MS: $\circ$) \\ D7 Evolvability \& maintainability & Enforced module boundaries (MM: $+$); new consumers attach without touching producers (EDA) & A typical feature cuts across every technical layer (L: $-$) \\ D8 Simplicity \& time-to-market & One repository, one pipeline, shipping this week (L, PF) & Platform engineering before the first feature (MS, EDA) \\ D9 Testability \& deployability & Hermetic domain tests behind ports (HX); per-module test selection (MM: $+$) & Verification only against an integrated environment (L: $-$, in practice); event flows that resist end-to-end tests (EDA: $-$) \\ D10 Operating cost efficiency & One cheap deployable, near-zero platform staff (L, MM, PF) & The microservice premium, paid in platform-team FTEs (MS) \\ D11 Team scaling (Conway fit) & One team per service, independent release trains (MS) & One release train for everyone (L: $-$) \\ D12 AI integrability & A natural queue, port, and measurement point (EDA, HX, PF) & An honest middle: platform timeouts against minutes-long AI runs (SL: $\circ$) \\ \bottomrule \end{tabular} \end{table} Read the table as a promise about Part~\ref{part:patterns}: the capability profiles there (Table~\ref{tab:capability}) are exactly these structural facts, made systematic -- every cell derived by the three-source method above, calibrated against the published star ratings under the fixed mapping, checked against production systems, every deviation footnoted. A rating is never taste; if you cannot point at the topology and name the tactic it privileges or impedes, you do not have a rating. Note also the rows where the table refuses a $--$ (D6, D12): where a structure's weakness is genuinely two-faced or workload-dependent, the honest rating is a middle one, and pretending otherwise would be the supply-side version of the vague requirement A4 forbids on the demand side. \subsection{Native workload shape and assembly} \label{subsec:capassembled} Like an application, every pattern has a native workload shape $S(p)$: layered, modular-monolith, and microservice structures natively serve interactive request/response; event-driven architecture serves streams and asynchronous flows; pipes-and-filters serves scheduled batch; serverless serves event-triggered, short-lived work; hexagonal, as a composition pattern, inherits its host's shape. $S(p)$ is not a rating but a type: it feeds the workload-shape gate of the match. \begin{definitionbox}[Capability profile $C(p)$] Each pattern $p \in P$ has a \emph{capability profile} \[ C(p) = \bigl(c_1(p), \dots, c_{12}(p);\; S(p)\bigr), \qquad c_i(p) \in \{++,\, +,\, \circ,\, -,\, --\}, \] an \emph{ordinal} rating of how well the pattern structurally supports dimension $D_i$ (Table~\ref{tab:dimensions}), justified through the tactics the pattern bundles or impedes, anchored where possible in the published star ratings of \citet{richards2025fundamentals} under the mapping above, with every deviation from the source ratings footnoted. $S(p)$ is the pattern's native workload shape. \end{definitionbox} Part~\ref{part:patterns} repeats this construction for the seven candidates of Table~\ref{tab:patternpreview}, and Table~\ref{tab:capability} is nothing but its result, seven profiles side by side, every deviation footnoted. \begin{ailinse}[Axis B preview: an LLM component stresses D3, D10, and D12] Suppose one component of the system is an LLM call. Nothing new is needed -- the coordinate system already carries it. \emph{D3}: LLM calls cost seconds where classical calls cost milliseconds, turning time behaviour from a tuning concern into a structural one (queues, asynchronous integration, caching). \emph{D10}: per-token pricing makes operating cost a per-request attribute -- a badly designed prompt chain is a cost regression the way an $n{+}1$ query is a latency regression. \emph{D12}: the pattern either provides the queue, the port, and the measurement point such a component needs, or it does not -- and the seven patterns differ sharply on exactly that. The supply side absorbs AI as ratings on existing dimensions, per A6; Part~\ref{part:ai} derives the D12 column in detail. \end{ailinse} \begin{keypoint} A capability rating is a testable prediction, not a preference: derived from tactics, calibrated against published star ratings under a fixed mapping, checked against documented production systems, every deviation footnoted. Supply is constructed with the same rigour as demand. \end{keypoint} % ============================================ % SECTION: THE MATCH -- fit(a,p) % ============================================ \section{The Match: $\mathrm{fit}(a,p)$} \label{sec:fit} Demand and supply are now constructed; what remains is the rule that compares them. We derive it constructively: the way the profiles were built dictates which properties any admissible aggregation must have -- and those properties leave essentially one shape of procedure. \subsection{What the construction dictates} \label{subsec:aggregation} Three properties of the profiles are not stylistic choices but results of their construction, and each imposes a requirement on the aggregation. First, \textbf{constraints are knock-outs}: $K(a)$ was collected as an inventory of obligations precisely because a violated obligation cannot be traded against merit (Section~\ref{subsec:shapeconstraints}), so the aggregation must eliminate violating patterns \emph{before} any scoring \citep{keeney1993decisions} -- and the workload shape belongs to the same family, since a pattern whose native $S(p)$ contradicts the dominant $S(a)$ cannot carry the class's core. Second, \textbf{High weights carry vetoes}: a High weight was \emph{defined} as the presence of (H,\,H) leaves -- scenarios whose failure is existential -- and announced as a veto claim (Sections~\ref{subsec:utilitytree} and \ref{subsec:weightexamples}); a pattern that is structurally weak exactly there fails those scenarios, and excellence elsewhere does not un-fail them, so the aggregation must be \emph{non-compensatory} on High-weight dimensions. Third, \textbf{everything is ordinal}: ordinal inputs license ordinal outputs -- rankings and exclusions, never percentages -- and any result must be checked for stability under plausible re-weighting. These three requirements admit essentially one procedure: \begin{definitionbox}[Architecture--application fit] The \emph{architecture--application fit} $\mathrm{fit}(a,p)$ is an ordinal aggregate of the dimension-wise comparison of $R(a)$ and $C(p)$, expressed on the same five-step scale $\{++, +, \circ, -, --\}$ and determined by a deliberately \textbf{non-compensatory, three-stage procedure}: \begin{enumerate} \item \textbf{Knock-out screening.} Hard constraints $K(a)$ eliminate patterns before any scoring; a violated constraint cannot be averaged away. The \emph{workload-shape gate} belongs to this stage: if $S(p)$ does not match the dominant $S(a)$, the pattern cannot be the dominant structure of the class's core -- its cell is capped at $\circ$ (subsystem role); it may reach $+$ only where it carries a \emph{constitutive} subsystem of an explicitly shape-hybrid class, and it falls to $-$/$--$ where it would actively harm the class's binding scenarios. \item \textbf{Veto rule on High-weight dimensions.} If $c_i(p) = --$ on any dimension that $a$ weights High, $\mathrm{fit}(a,p)$ is capped at $-$; if $c_i(p) = -$, the cap is $\circ$ -- \emph{unless a documented mitigation exists} (a tactic or hybrid composition with production evidence), in which case the cell says so explicitly and the cap is lifted. \item \textbf{Holistic ordinal reading with mandatory sensitivity analysis.} The surviving candidates are ranked by their support of the High-weight dimensions; conflicts on Medium-weight dimensions are noted and can downgrade a rating by one step when they cluster. The result is a \emph{ranking with exclusions}, never ``pattern A is $12\,\%$ better''. If the ranking flips under plausible weight variation, that instability is not noise -- it marks a genuine trade-off point in the ATAM sense and must be escalated to scenario-based analysis \citep{kazman2000atam}. \end{enumerate} \end{definitionbox} ``Non-compensatory'' is the key property, and it mirrors the documented failures of Section~\ref{sec:decisionproblem}: Prime Video's serverless design was excellent on elasticity and deployability, and none of that compensated for the cost structure its workload shape imposed \citep{kolny2023primevideo}. Stage~2's mitigation clause keeps the rule honest: a veto can be lifted, but only by a \emph{documented} tactic or hybrid with production evidence -- ``pod-sharded replication of the monolith'' \citep{westeinde2019deconstructing} or ``event-driven edges around an ACID core'' -- never by optimism. \begin{examplebox}[Same class -- opposite structures: why constraints decide within the feasible set] Core banking admits \emph{opposite} viable architectures. LMAX runs a deterministic, single-threaded, event-sourced matching core processing six million orders per second on one JVM thread \citep{fowler2011lmax}; Monzo runs the same domain on roughly $2{,}800$ Go microservices \citep{sewell2024monzo}. Both satisfy the class's binding scenarios (zero booking loss, full auditability). The lesson: $R(a)$ alone does not force one pattern -- it defines a \emph{feasible set}, and the constraints and organisational context in $K(a)$ decide within it. A matching theory that pretended to compute a single winner from the profile alone would be falsified by this pair; a theory that outputs a ranked feasible set plus the constraints that discriminate is confirmed by it. \end{examplebox} \subsection{The mechanics on a real case: matching the advisory platform} \label{subsec:minimatch} A three-stage procedure reads abstract until it runs. So run it -- once, small, end to end. The demand side is $R(\text{C10})$, the advisory-platform profile assembled in Section~\ref{subsec:reqassembled}: High on D6, D7, D9, D10, D12; shape hybrid; EU AI Act and GDPR in $K$. Against it we hold three deliberately contrasting candidates from Table~\ref{tab:patternpreview}: the layered monolith (L), the modular monolith (MM), and microservices (MS). \textbf{Stage 1 -- knock-out and shape gate.} $S(\text{C10})$ is explicitly hybrid: an interactive advisory dialogue at the core, batch and asynchronous pipelines (indexing, evaluation runs) beside it. All three candidates are natively interactive, so all three pass the gate \emph{for the core} -- the pipelines will be carried by PF- and EDA-shaped subsystems in any of the three designs, since hybrids are the normal case (Section~\ref{subsec:matrixstatus}). Nor does any hard constraint in $K(\text{C10})$ eliminate a candidate outright: the EU AI Act's logging and human-oversight duties \citep{eu2024aiact} are satisfiable in all three -- though note, for stage 3, that they \emph{favour} structures in which every model call flows through one auditable path. \textbf{Stage 2 -- vetoes on the High dimensions.} Now the High set $\{$D6, D7, D9, D10, D12$\}$ interrogates each survivor, using the capability ratings previewed in Table~\ref{tab:capexamples} and derived in full in Part~\ref{part:patterns}. \emph{L:} the layered monolith rates $-$ on High-weighted D7 -- the veto rule caps it at $\circ$ unless a documented mitigation exists, and at C10's extreme change rate of models, prompts, and frameworks there is none: technical layers give the non-deterministic component no boundary, no queue, and no measurement point -- the three things it needs most. D9 is a second $-$ on a High dimension, and D12 offers only $\circ$; two unmitigated vetoes that cluster push the stage-3 reading one step below the cap, to $-$. \emph{MS:} microservices rate $--$ on High-weighted D10, which would cap the cell at $-$ -- but here the mitigation clause earns its keep. C10's D10-High targets \emph{per-request AI cost} (tokens, GPU), which dominates infrastructure cost and is governed at a gateway -- a concern orthogonal to distribution -- so the platform-cost $--$ relaxes to $\circ$ rather than $-$. What stops MS from rising further is stage 3's holistic reading: synchronous service chains multiply seconds-scale LLM latency and failure rates \citep{nygard2018release}, and the pattern's signature payoff, team scaling, sits on Low-weighted D11 -- for a student-sized team the microservice premium buys nothing \citep{fowler2015premium}. \emph{MM:} no veto fires at all -- the modular monolith rates $+$ or better on every dimension of the High set, and its one structural $-$ (D5, blast radius) is Medium-weighted and mitigated by replicated instances. \textbf{Stage 3 -- ordinal reading.} MM leads the High set outright: D6 $+$, D7 $+$, D9 $+$, D10 $++$, D12 $+$. And one composition improves it further: applying HX as the internal discipline of the monolith raises D9 and D12 to $++$ -- the LLM becomes an adapter on a port, mockable in hermetic tests, swappable on provider deprecation, guarded by contract validation \citep{cockburn2024hexagonal, evans2003ddd}. The hexagonal modular monolith is therefore the primary recommendation -- and it is exactly the architecture of the course project. Table~\ref{tab:minimatch} compresses the whole computation. \begin{table}[htbp] \centering \caption{The mini-match: $R(\text{C10})$ against three contrasting candidates. Rows are the five High-weight dimensions of C10 with the capability ratings $c_i(p)$; the verdict row is the architecture--application fit, identical to the C10 row of the full matrix (Table~\ref{tab:fitmatrix}).} \label{tab:minimatch} \footnotesize \begin{tabular}{@{}p{3.6cm}p{3.0cm}p{3.6cm}p{3.6cm}@{}} \toprule \textbf{High dimension of C10} & \textbf{L} & \textbf{MM ($+$ HX inside)} & \textbf{MS} \\ \midrule D6 Security \& auditability & $+$ & $+$ & $\circ$ \\ D7 Evolvability & $-$ \emph{(veto)} & $+$ & $++$ \\ D9 Testability \& deployability & $-$ \emph{(veto)} & $+$ ($++$ with HX) & $+$ \\ D10 Operating cost & $++$ & $++$ & $--$ \emph{(veto)} \\ D12 AI integrability & $\circ$ & $+$ ($++$ with HX) & $\circ$ \\ \midrule Stage-2 outcome & two unmitigated vetoes, clustering & no veto & D10 veto relaxed: per-request AI cost is a gateway concern, orthogonal to distribution \\ \textbf{Verdict $\mathrm{fit}(\text{C10},p)$} & $-$ & $++$ & $\circ$ \\ \bottomrule \end{tabular} \end{table} That is the entire mechanics: one profile, three candidates, three stages, a ranking with exclusions. You have now seen every element of the framework do real work once -- demand constructed (Section~\ref{sec:demand}), supply derived (Section~\ref{sec:supply}), the match computed. Part~\ref{part:fit} runs the same computation for all seventy pairs and adds what a single worked row cannot show: sensitivity analysis, hybrids, and evolution paths. \begin{thinkbox} Run the same three candidates against $R(\text{back-office})$ from Section~\ref{subsec:reqassembled} -- High on D4, D6, D7, D8, D10. Which veto fires first, and does the verdict change? Check yourself: microservices now hit two unmitigated $--$ vetoes at once (D8 and D10, both High for this class), while the layered monolith's strengths sit exactly on the class's High set (D4, D8, D10) and only D7 caps it -- liftable by scoping to a small, stable domain -- so the verdicts become L $+$, MM $++$, MS $--$: the same winner, but a radically re-ordered field. \end{thinkbox} \subsection{Why the obvious alternative fails} \label{subsec:nomcdm} Why is the familiar alternative -- score each pattern $1$--$5$ per criterion, multiply by weights, add up, $V = \sum_i w_i \cdot v_i$ -- not used? It looks rigorous; for this problem it is not. Multi-attribute value theory licenses the additive form only under three conditions \citep{keeney1993decisions}: cardinal (interval) scales, preferential independence of the criteria, and weights interpreted as trade-off rates. All three fail here: the ratings are ordinal by construction (what would ``microservices score $4.3$ on consistency'' mean?); preferential independence is violated by definition -- architecture trade-offs mean precisely that the value of ``scalability $= ++$'' depends on what happens to consistency, so A2 is a statement of preferential dependence; and nobody can state, or defend to an auditor, the rate at which audit-trail quality is exchangeable for deployment frequency. The AHP repair \citep{saaty1980analytic, saaty1977scaling} -- pairwise comparisons, eigenvector-derived priorities, a consistency check -- inherits documented defects: adding an alternative (even a copy of an existing one) can \emph{reverse the ranking} of the others \citep{belton1983shortcoming, maleki2013comprehensive}; Dyer's verdict was that the method is ``flawed as a procedure for ranking alternatives'' \citep{dyer1990remarks}; and its verbal nine-point scale collects ordinal intensity judgements but computes with them as ratio-scale numbers -- a reinterpretation measurement theory does not license \citep{banaecosta2008critical}. What this framework keeps from multi-criteria decision analysis is its \emph{explication discipline} -- criteria on the table, weights argued rather than assumed, options compared systematically; what it drops is the arithmetic pretensions. \begin{hinweisbox} \textbf{Beware pseudo-precision.} A weighted-sum matrix over ordinal ratings produces numbers -- ``pattern A: $3.87$; pattern B: $3.79$'' -- whose significant digits are artefacts of the procedure, not measurements of anything. Such numbers end discussions that should be had (the $0.08$ gap will not survive any plausible re-weighting) and lend false authority to whatever assumptions were buried in the scores. The professional habit this module trains is the opposite: report \emph{rankings with exclusions}, state the veto behind each exclusion, and run the sensitivity analysis. If the recommendation flips when weights vary plausibly, you have found a genuine trade-off point -- a \emph{finding} to escalate to stakeholders, not an error to hide with more decimals \citep{kazman2000atam, keeney1993decisions}. \end{hinweisbox} \subsection{The status of the matrix} \label{subsec:matrixstatus} Applying the three-stage procedure to all pairs yields the $7\times 10$ matching matrix of Part~\ref{part:fit} (Table~\ref{tab:fitmatrix}), and one point governs how every cell is to be read: the matrix is an \textbf{explication and communication instrument} -- a compressed, teachable heuristic that forces criteria, weights, and assumptions into the open -- \emph{not} a computation that determines decisions. The rigorous method behind every contested cell is the ATAM: scenario walk-throughs, sensitivity points, trade-off points, risks and non-risks \citep{kazman2000atam, clements2002evaluating}; where money must decide, the CBAM extends it with utility-response curves and ROI \citep{kazman2002making, asundi2001using}. Three honest limits hold throughout: the scales are ordinal (no percentages, ever); the ratings are context-dependent (the serverless cost rating literally inverts with load shape); and hybrids are the normal case, the matrix read \emph{per subsystem}. Part~\ref{part:fit} computes the full matrix and works one decision at full depth -- $\mathrm{fit}(\text{C1}, \text{MS})$ against $\mathrm{fit}(\text{C1}, \text{MM})$, stage by stage, with the sensitivity analysis the mini-match of Section~\ref{subsec:minimatch} deliberately kept small; the two worked examples are complementary, C10 as the introduction, C1 as the deep case. \begin{keypoint} The fit function is computed by rules, not arithmetic: knock-out constraints and the workload-shape gate first, then vetoes on High-weight dimensions (liftable only by documented mitigations), then a holistic ordinal reading under mandatory sensitivity analysis. A weighted sum would presuppose cardinal scales, preferential independence, and defensible trade-off rates -- all demonstrably absent -- and would let excellence somewhere compensate for catastrophe where it matters. Non-compensatory matching is not methodological caution; it is how architectural failure actually works. \end{keypoint} % ============================================ % SECTION: RECORDING AND TESTING THE DECISION % ============================================ \section{Recording and Testing the Decision} \label{sec:adr} The match produces a decision -- and A1 says the decision, not the diagram, is the primary artefact. Undocumented decisions evaporate: the code shows \emph{what} was built, never \emph{why}, and within a few staff rotations the rationale is gone -- later changes then violate constraints nobody remembers, which is what teams experience as ``legacy'' \citep{jansen2005software}. ISO/IEC/IEEE 42010:2022 draws the normative conclusion: a conformant architecture description \emph{must} record architecture decisions and their rationale (Clause~6.10) \citep{iso2022architecture}. This section presents the lightweight de-facto standard that fulfils the obligation, and the contract that turns the recorded decision into a tested hypothesis (A5). \subsection{Architecture Decision Records} \label{subsec:nygard} \begin{definitionbox}[Architecture Decision Record (ADR)] An \emph{Architecture Decision Record} is a short text document -- one to two pages, versioned in the code repository, one decision per file -- with the structure proposed by \citet{nygard2011documenting}: \textbf{Title} (numbered noun phrase), \textbf{Status} (proposed / accepted / deprecated / superseded), \textbf{Context} (the forces at play -- technical, political, social, project-specific -- described in value-neutral terms), \textbf{Decision} (active voice: ``We will \dots''), and \textbf{Consequences} (the resulting context, positive \emph{and} negative). \end{definitionbox} Three design choices make the format work: \emph{co-location} (ADRs live in the repository, next to the code they govern, not in a wiki that dies with the project office); \emph{brevity} (one decision, one page -- a format cheap enough to be used beats a comprehensive one that is not); and, most importantly, \emph{immutability}: a superseded ADR is never edited or deleted -- a new ADR supersedes it. Immutability is the direct countermeasure to knowledge vaporization: the record of \emph{why we changed our minds} is often more valuable than the current answer. The \textbf{MADR} format extends Nygard's structure with explicit \textbf{decision drivers} and \textbf{considered options}, each with pros and cons, plus an optional \textbf{confirmation} section stating how compliance will be verified \citep{kopp2018markdown, madr2024template}. For this module, MADR is the format of choice for a structural reason: ``decision drivers $+$ considered options'' is exactly one row of the matching matrix in narrative long form -- a completed matrix is the tabular compression of many MADRs. Listing~\ref{lst:adr} shows the template instantiated for a decision you will actually face in the course project. \begin{lstlisting}[language={}, caption={A MADR-style ADR for the course project: the LLM gateway decision. The Confirmation section is the measurement contract in embryonic form.}, label={lst:adr}] # ADR-011: Route all LLM calls through one gateway port Status: accepted (2026-10-14) | supersedes ADR-004 Deciders: architecture owner (name), platform team ## Context and problem statement Advisory features call a commercial LLM. Providers deprecate models on 6-12 month cycles; token costs must be attributable per request; domain logic must stay testable without paid, non-deterministic API calls in the test path. ## Decision drivers * D7 Evolvability: provider/model change must stay cheap * D9 Testability: hermetic domain tests, no live API calls * D12 AI integrability: per-request cost observability ## Considered options 1. Direct provider-SDK calls from domain services 2. One LLM gateway behind a domain-owned port <-- chosen 3. Per-feature adapters without a shared gateway ## Decision We will route every model call through a single gateway that owns prompts, schema validation, retries, model routing, and cost telemetry. Domain code depends only on the port interface. ## Consequences * Good: provider migration is an adapter task (see ADR-004 for the failed alternative); domain tests run against fakes. * Bad: one more runtime component; ~20-50 ms added latency; the gateway is a single point requiring its own SLO. ## Confirmation (measurement contract) * Static rule: no domain module imports the provider SDK (ArchUnit, CI gate, 0 violations tolerated) * Eval-harness pass rate >= 95% on every model/prompt change * Token cost per request <= budget (p95), monitored continually \end{lstlisting} \subsection{Diagrams for decisions: the C4 model in brief} \label{subsec:c4} Decisions need diagrams -- sparingly, and at the right zoom level. The \textbf{C4 model} is a notation- and tool-independent abstraction scheme with four zoom levels -- system context, container, component, code \citep{brown2024c4}; in ISO~42010 terms, a minimalist set of viewpoints \citep{iso2022architecture}. For this module, one level dominates: the seven patterns differ most visibly at \emph{container} level -- a modular monolith is one container with enforced internal boundaries, a microservice system is many, an event-driven system inserts a broker container between them -- so C4 container diagrams are the standard notation for Parts~\ref{part:patterns} and \ref{part:fit}. Where a full documentation skeleton is wanted, the arc42 template provides one, with designated homes for ADRs and quality scenarios \citep{starke2024arc42, starke2023effektive} -- but the artefacts, not the skeleton, carry the method. \subsection{The measurement contract} \label{subsec:contract} The Confirmation section of Listing~\ref{lst:adr} is the fifth framework element in embryonic form. A5 established that fit decays and must be re-measured; the \textbf{measurement contract} is where the decision commits to that discipline: every ADR ends with the \emph{fitness functions and thresholds that would tell us the decision has failed} \citep{ford2022evolutionary} -- static rules as CI gates, scenario response measures as automated tests, cost and latency budgets as telemetry alarms -- and, in operation, the four DORA metrics test whether the delivery-relevant promises of the structure are being kept \citep{forsgren2018accelerate, dora2023sodr}. When the contract is breached, the response is a documented evolution path (Strangler Fig \citep{fowler2004strangler}) recorded as a superseding ADR, never a silent rewrite. Part~\ref{part:fit} develops the full apparatus: the eight-step decision procedure with the measurement contract as its mandatory final step. \begin{keypoint} The ADR is where the framework meets ISO/IEC/IEEE 42010's conformance demand: decisions and rationale \emph{must} be recorded, and the MADR fields ``decision drivers'' and ``considered options'' carry the utility-tree weights and the matrix row into a permanent, auditable, superseding-not-overwriting record. No architecture decision is complete until it exists as an ADR ending in a measurement contract. \end{keypoint} \begin{ailinse}[Axis A: an agent drafts the ADR -- a human owns the decision] ADRs are an ideal task for AI assistance and a hard boundary for AI authority. An agent with access to the repository, the utility tree, and the matching matrix can \emph{draft} a competent MADR in minutes: enumerate the options, fill in pros and cons from the capability profiles, propose fitness functions for the confirmation section. Use that. But the decision itself is an act of accountability, not of text generation: a nameable person weighs the drivers, accepts the negative consequences, and answers for them later. And note a second-order effect: agents \emph{read} ADRs and convention files on every run \citep{openai2025agentsmd, anthropic2025claudecode}, so documentation quality is reproduced at machine speed, in whichever direction it points \citep{dora2025aireport} -- a precise ADR corpus is leverage; a stale one is automated misdirection. \end{ailinse} % ============================================ % SECTION: SUMMARY -- THE RED LINE % ============================================ \section{Summary: The Red Line} \label{sec:summary} This part built one framework, in one direction: \textbf{demand $\to$ supply $\to$ match $\to$ record $\to$ test.} \begin{enumerate} \item \textbf{The problem} (Section~\ref{sec:decisionproblem}): structures differ radically and none dominates, so architecture -- the set of hard-to-reverse structural decisions that determine a system's quality behaviour -- is a matching problem, resting on assumptions A1--A6. \item \textbf{The coordinate system} (Section~\ref{sec:dimensions}): twelve dimensions, ISO-anchored, pattern-discriminating, instrumented -- no instrument, no dimension. \item \textbf{Demand} (Section~\ref{sec:demand}): elicited ASRs $\to$ scenarios with response measures $\to$ utility-tree weights, plus measured workload shape and constraint inventory -- assembled into $R(a)$, worked twice: the AI-native advisory platform and a back-office workflow tool. \item \textbf{Supply} (Section~\ref{sec:supply}): the seven candidate patterns previewed, then tactics analysis, calibrated star ratings with footnoted deviations, production evidence -- assembled into $C(p)$ with its native shape. \item \textbf{Match, record, test} (Sections~\ref{sec:fit}, \ref{sec:adr}): the non-compensatory three-stage procedure yields $\mathrm{fit}(a,p)$ as a ranking with exclusions -- worked once for the advisory platform against three candidates; the decision is recorded as an ADR ending in a measurement contract that operation continuously tests. \end{enumerate} Table~\ref{tab:redline} maps each element to where the script instantiates it at scale. Note what the middle column now certifies: this part did not only \emph{define} the loop, it \emph{ran} it once at small scale -- two requirements profiles, a dimension-wise capability preview, one complete match ending in the course-project architecture. A reader who stops here has seen demand, supply, and matching each done concretely; Parts~\ref{part:patterns}--\ref{part:fit} do the same at scale. \begin{table}[htbp] \centering \caption{The five framework elements, where this part constructed them, and where the script instantiates them at scale.} \label{tab:redline} \footnotesize \begin{tabular}{@{}p{3.4cm}p{4.4cm}p{6.2cm}@{}} \toprule \textbf{Framework element} & \textbf{Constructed in} & \textbf{Instantiated at scale} \\ \midrule Twelve dimensions $D_1$--$D_{12}$ & Section~\ref{sec:dimensions}, Table~\ref{tab:dimensions} & the shared coordinate system of every profile and every matrix cell \\ Requirements profile $R(a)$ & Section~\ref{sec:demand} (worked: C10 and back-office; Table~\ref{tab:weightexamples}) & Part~\ref{part:applications}: ten application classes, Table~\ref{tab:requirements} \\ Capability profile $C(p)$ & Section~\ref{sec:supply} (previewed: Table~\ref{tab:patternpreview}; worked: EDA/D7, MS/D4, Table~\ref{tab:capexamples}) & Part~\ref{part:patterns}: seven patterns, Table~\ref{tab:capability} \\ Fit $\mathrm{fit}(a,p)$ & Section~\ref{sec:fit} (worked: C10 vs.\ L/MM/MS, Table~\ref{tab:minimatch}) & Part~\ref{part:fit}: the $7\times 10$ matrix (Table~\ref{tab:fitmatrix}), hybrids, evolution paths, decision procedure \\ ADR and measurement contract & Section~\ref{sec:adr}, Listing~\ref{lst:adr} & Part~\ref{part:fit}: the procedure's mandatory final steps; operation via fitness functions and DORA metrics \\ AI extension of the space & D12 (Section~\ref{sec:dimensions}); A6 & Part~\ref{part:ai}: Axis A and Axis B, class C10, the eval harness \\ \bottomrule \end{tabular} \end{table} \begin{keypoint} The chain to remember: application class $\to$ scenarios with response measures $\to$ utility tree $\to$ requirements profile $R(a)$ $\to$ non-compensatory matching against capability profiles $C(p)$ $\to$ ADR with rationale $\to$ measurement contract $\to$ operation, and -- because profiles drift -- back around. Architecture, in this module, is not a diagram you draw once; it is a hypothesis you state precisely, decide accountably, and measure for as long as the system lives. \end{keypoint}