795 lines
102 KiB
TeX
795 lines
102 KiB
TeX
\part{The Fit: Matching, Decision Procedure, and Measurement}
|
|
\label{part:fit}
|
|
|
|
Ten times Part~\ref{part:applications} ended with a verdict and a promise: a one-sentence primary and secondary recommendation, and the assurance that Part~\ref{part:fit} computes this verdict through the three-stage procedure. This part keeps that promise. You own both operands -- the requirements profiles $R(a)$ of Part~\ref{part:applications} and the capability profiles $C(p)$ of Part~\ref{part:patterns} -- and you have watched the \emph{architecture--application fit} $\mathrm{fit}(a,p)$, the ordinal aggregate of their dimension-wise comparison defined in Part~\ref{part:foundations}, run once at small scale in the C10 mini-match (Table~\ref{tab:minimatch}). What you have not yet seen is the machine at full load. The part proceeds the way Parts~\ref{part:patterns} and~\ref{part:applications} worked -- cases first, generalisation after: three matches computed end to end, each exposing one stage of the procedure (Section~\ref{sec:threecases}); the general procedure they instantiate (Section~\ref{sec:fit-computation}); all seventy pairs at once -- the matching matrix with its per-class rationales (Sections~\ref{sec:fitmatrix}--\ref{sec:matrix-reading}); what the matrix cannot say -- hybrids and evolution paths (Section~\ref{sec:hybrids}); the eight-step decision procedure (Section~\ref{sec:procedure}); and how a decision stays honest for years -- the measurement contract with its organisational and reflexive complements (Sections~\ref{sec:contract}--\ref{sec:limits}).
|
|
|
|
% ============================================
|
|
% SECTION: THREE MATCHES, THREE STAGES
|
|
% ============================================
|
|
\section{Three Matches, Three Stages}
|
|
\label{sec:threecases}
|
|
|
|
\emph{What does the three-stage procedure actually do when it runs?} Usually far less than students expect -- most of the work happens before anything is scored. The three cases of this section make that visible: each runs one class from Part~\ref{part:applications} against real candidates, lands on exactly the verdict that class's section promised, and is chosen because a different stage does the decisive work in it -- the knock-out screening and shape gate for C6, the veto rule with its documented mitigations for C1, the holistic ordinal reading with its built-in sensitivity alarm for C2. (C10, the course-project class, was Part~\ref{part:foundations}'s introductory match; the three classes here complement it.)
|
|
|
|
\subsection{Case 1 -- C6 against all seven candidates: Stage 1 does almost all the work}
|
|
\label{subsec:case-c6}
|
|
|
|
\emph{The nightly risk run must finish by 06:00, reproduce to the bit, and cost as little as possible: which of the seven patterns can even apply for the job?} Recall the C6 profile (Table~\ref{tab:req-c6}): High on D2 in its makespan reading, on D9 in its reproducibility reading, and on D10; dominant workload shape \emph{scheduled batch}; deterministic seeds as a hard constraint. Before comparing a single rating, hold that shape against the native-shape row $S(p)$ of the capability table (Table~\ref{tab:capability}).
|
|
|
|
\begin{examplebox}[Computing the C6 row: one gate, six casualties]
|
|
\textbf{Stage 1 -- knock-out and shape gate.} $S(\text{C6})$ is scheduled batch, and exactly one candidate is natively batch-shaped: PF. The gate caps every other cell at $\circ$ -- a subsystem role at best -- before any rating above the shape row is compared (Table~\ref{tab:case-c6} names the roles), and its harm clause takes two candidates further down: L has no answer to makespan, checkpointing, or CPU-hour cost and carries $--$ against High-weighted D2, so $\mathrm{fit}(\text{C6}, \text{L}) = {--}$; MS would multiply communication cost across service boundaries against High-weighted D10 -- the Prime Video lesson at HPC scale \citep{kolny2023primevideo} -- so $\mathrm{fit}(\text{C6}, \text{MS}) = {--}$.
|
|
|
|
\textbf{Stages 2 and 3 -- one survivor.} Only PF reaches the veto stage, and no veto fires: against the High set $\{$D2, D9, D10$\}$ it rates $+$, $+$, $++$ (Table~\ref{tab:cap-pf}) -- throughput from data-parallel frameworks, reproducibility by construction, utilisation-driven cost \citep{zaharia2012resilient, yoo2003slurm, glasserman2003monte}; its $--$ on D3 sits on a Low weight and is inert. The holistic reading ranks a field of one. \textbf{Result: $\mathrm{fit}(\text{C6}, \text{PF}) = {++}$, every other pattern at $\circ$ or below} -- the C6 row of Table~\ref{tab:fitmatrix}, computed almost entirely at Stage~1.
|
|
\end{examplebox}
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Case 1 -- the C6 row decided at Stage~1: the workload-shape gate against $S(\text{C6}) = $ scheduled batch. Only PF proceeds to Stages~2--3; the verdict column is identical to the C6 row of Table~\ref{tab:fitmatrix}.}
|
|
\label{tab:case-c6}
|
|
\begin{tabular}{@{}llp{7.2cm}c@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Native shape $S(p)$} & \textbf{Stage-1 outcome} & \textbf{Verdict} \\
|
|
\midrule
|
|
L & interactive & gate caps at $\circ$; harm clause -- no answer to makespan or checkpointing, $--$ against High D2 & $--$ \\
|
|
MM & interactive & gate caps at $\circ$: orchestration codebase around monolithic kernels & $\circ$ \\
|
|
HX & (host's) & gate caps at $\circ$: ports touch no binding dimension & $\circ$ \\
|
|
MS & interactive & gate caps; harm clause -- communication cost multiplied against High D10 & $--$ \\
|
|
EDA & stream / async & gate caps at $\circ$: job-status glue beside scheduler and DAG & $\circ$ \\
|
|
PF & scheduled batch & \textbf{gate passed} -- proceeds to Stages 2--3; no veto on $\{$D2, D9, D10$\}$ & $++$ \\
|
|
SL & event-trig., short-lived & gate caps at $\circ$: burst fan-out for communication-light sections only & $\circ$ \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
The didactic point generalises: \emph{run the cheapest test first} -- six of seven candidates died before a single rating was weighed. The knock-outs of $K(a)$ belong to the same stage and work the same way: recall from Part~\ref{part:applications} that $K(\text{C1})$ eliminates any structure that cannot guarantee an ACID booking core, an immutable audit journal, and ten-plus-year retention -- before scoring, however well it scales \citep{bcbs2013rdarr}. The verdict is the one Section~\ref{sec:c6} promised: pipes-and-filters on HPC/batch infrastructure as primary, serverless fan-out for bursty, communication-light parallel sections as secondary -- with the honest subsystem roles (the $\circ$ cells) stated, not hidden.
|
|
|
|
\subsection{Case 2 -- C1: the veto rule and its documented mitigations}
|
|
\label{subsec:case-c1}
|
|
|
|
\emph{Two candidates pass the gate, both natively interactive -- and one of them cannot commit a transaction across its own internal boundaries: how does the procedure decide core banking?} Where Case~1 was settled by shape, C1 is settled by the veto rule, because its gate lets several serious candidates through. Recall the profile (Table~\ref{tab:req-c1}): High on D4, D5, D6, D7, and D9; hard constraints including an ACID booking core and BCBS~239 / FINMA auditability \citep{bcbs2013rdarr, finma2023oprisk}; dominant workload shape interactive with batch edges. The contested pair is the modular monolith against microservices -- Tables~\ref{tab:cap-mm} and~\ref{tab:cap-ms} side by side.
|
|
|
|
\begin{examplebox}[Computing the cells C1/MS and C1/MM step by step]
|
|
\textbf{Stage 1 -- knock-out and shape gate.} Both microservices (MS) and the modular monolith (MM) are natively interactive patterns, so the shape gate passes for both. No hard constraint in $K(\text{C1})$ eliminates either outright: the ACID-core constraint does not name a pattern, and both patterns can in principle be operated under FINMA-grade audit obligations. Both survive to Stage~2.
|
|
|
|
\textbf{Stage 2 -- veto rule for MS.} From Table~\ref{tab:capability}, $c_{4}(\text{MS}) = {--}$: no ACID transactions across service boundaries; sagas trade atomicity for choreography complexity \citep{richardson2018microservices}. D4 is High-weight in C1, so the veto fires and caps the cell at $-$. Note the kind of fact the veto has seized on: a \emph{structural} one. No mitigation \emph{restores} ACID across service boundaries -- sagas buy coordination with compensating actions, not atomicity -- so a mitigation can only show that living without the property is survivable in this class. Is there one? Yes, but conditional: Monzo operates roughly 2{,}800 microservices in production banking -- under the condition of organisational scale plus extreme technological homogeneity (one language, one monorepo, central migration automation) \citep{sewell2024monzo}. The mitigation is real but bound to a condition most organisations do not meet, and the microservice premium is paid in platform staffing with no gain for typical team sizes \citep{fowler2015premium}. The cap is therefore lifted only to $\circ$, with the condition stated in the cell rationale. MS also rates $--$ on D8 and D10, but both are Low-weight in C1 -- no further veto fires. \textbf{Result: $\mathrm{fit}(\text{C1}, \text{MS}) = \circ$.}
|
|
|
|
\textbf{Stage 2 -- veto rule for MM.} $c_{4}(\text{MM}) = {++}$ (cross-module ACID transactions) -- no veto. But $c_{5}(\text{MM}) = {-}$ on High-weight D5, which caps the cell at $\circ$ -- unless a documented mitigation exists. It does: hot-standby replication of whole monolith instances is the classical banking high-availability tactic, in production at Fineract-class core-banking systems \citep{fineract2024core}. The cap is lifted.
|
|
|
|
\textbf{Stage 3 -- holistic reading.} MM now stands at $++$ on D4, $+$ on D6, $+$ on D7, and $+$ on D9 -- support on every High-weight dimension of the class, with the one structural weakness mitigated. \textbf{Result: $\mathrm{fit}(\text{C1}, \text{MM}) = {++}$.} The ranking MM $\succ$ MS for the C1 core is stable under plausible weight variation: it would flip only if D11 (team scaling) rose to High \emph{and} the Monzo homogeneity condition held -- which is exactly what the cell rationale in Section~\ref{subsec:fit-c1} records as the escalation condition.
|
|
\end{examplebox}
|
|
|
|
The division of labour generalises: the veto rule does the heavy lifting, and the ``documented mitigation'' clause is where engineering knowledge -- not arithmetic -- enters the computation. The asymmetry between the two mitigations is the lesson: an \emph{operational} weakness (MM's one-process blast radius) is repaired outright by a standard tactic -- hot standby, pod replication \citep{westeinde2019deconstructing} -- while a \emph{structural} one (atomicity surrendered at the boundary) can only be made survivable, under a condition most organisations do not meet. The rest of the row follows the same mechanics (Section~\ref{sec:rationales}); in particular HX -- a delta discipline, not a competitor -- joins MM at $++$ by isolating the long-lived booking core from volatile channels and providers \citep{cockburn2024hexagonal}. The verdict is the one Section~\ref{sec:c1} promised: a hexagonal modular monolith for the booking core (MM and HX at $++$), EDA at the edges and PF for the batch runs as secondary, and microservices only when organisation size forces D11 to High -- the Monzo condition -- exactly the C1 row of Table~\ref{tab:fitmatrix}.
|
|
|
|
\subsection{Case 3 -- C2: the holistic reading and its built-in alarm}
|
|
\label{subsec:case-c2}
|
|
|
|
\emph{Two finalists carry $++$ where it matters and neither dominates: what does the procedure return when scoring cannot separate the survivors?} The social/content platform is that case. Recall the profile (Table~\ref{tab:req-c2}): the widest High set in the catalogue -- D1, D3, D5, D7, D9, D11 -- and a constraint set that knocks out almost nothing; the discrimination work is done by the weights, not the constraints.
|
|
|
|
\textbf{Stage 1} requires one honest observation about shape: the class core has two constitutive paths -- the interactive read path that serves the feed, and the asynchronous fan-out path that delivers posts (the five-second delivery scenario is binding for the class). Neither MS (natively interactive) nor EDA (natively stream/async) is shape-foreign to the path it would carry, so the gate passes both. \textbf{Stage 2} fires one veto against each, and documented practice lifts both: MS's $-$ on High-weighted D3 (mitigation: edge caching, precomputed timelines \citep{krikorian2013timelines}); EDA's $-$ on High-weighted D9 (mitigation: schema/contract tests, progressive delivery). Both reach Stage~3 intact.
|
|
|
|
\textbf{Stage 3} must now rank two survivors, and the comparison refuses to close. Across the High set, MS reads $++$, (mitigated), $++$, $++$, $+$, $++$ and EDA reads $++$, $+$, $++$, $++$, (mitigated), $+$. Neither dominates: MS leads where teams multiply (D9, D11 -- independent deployments), EDA where consumers multiply (D3 on the asynchronous path; D7 in its attach-new-consumers reading). The mandatory sensitivity analysis flips the ordering under entirely plausible variation: weight D11 the way a several-hundred-team organisation must, and MS wins; frame the feed as what it technically is -- an eventually consistent, precomputed product of an event flow -- and EDA wins. By Stage~3's own rule, that instability is not noise: it marks a genuine tradeoff point in the ATAM sense, to be escalated to scenario-based analysis rather than smoothed over \citep{kazman2000atam}.
|
|
|
|
And here the documented record refuses the either/or. Twitter's timeline architecture is both patterns at once -- fan-out-on-write \emph{is} publish/subscribe, an event flow whose product, the precomputed timeline, is served by independently scaled services \citep{krikorian2013timelines}. The honest reading of the instability is therefore not ``the procedure failed to pick a winner'' but ``the class genuinely needs both patterns, \emph{placed}'' -- the bridge to Section~\ref{sec:hybrids}, where hybrids turn out to be the normal case, not the exception. The verdict is the one Section~\ref{sec:c2} promised: an EDA + microservices hybrid at organisational scale (MS and EDA at $++$), a modular monolith as secondary until that scale is \emph{measured}, not assumed (Mastodon runs the full fan-out mechanics in a Rails monolith \citep{mastodon2024docs}) -- exactly the C2 row of Table~\ref{tab:fitmatrix}.
|
|
|
|
\begin{keypoint}
|
|
Three cases, three stages, one division of labour: the knock-out screening and shape gate kill most candidates before any scoring (C6 -- the cheapest test runs first), the veto rule disciplines the High set and prices every mitigation as documented engineering rather than optimism (C1), and the holistic ordinal reading ranks the survivors while flagging its own instability as a finding, not an error (C2). Every one of the seventy cells in Section~\ref{sec:fitmatrix} was produced by exactly this division of labour.
|
|
\end{keypoint}
|
|
|
|
% ============================================
|
|
% SECTION: THE PROCEDURE IN GENERAL
|
|
% ============================================
|
|
\section{The Procedure in General}
|
|
\label{sec:fit-computation}
|
|
|
|
\emph{What rule were the three matches following?} Three matches have run end to end; this section states what they instantiated -- briefly, because every element has already done visible work.
|
|
|
|
\subsection{The formal statement}
|
|
|
|
\begin{sloppypar}
|
|
Recall the operands. Each application class $a \in A$ carries a requirements profile $R(a) = (w_1(a), \dots, w_{12}(a);\, S(a);\, K(a))$: utility-tree-derived priority weights $w_i(a) \in \{\text{High},\allowbreak\ \text{Medium},\allowbreak\ \text{Low}\}$ \citep{kazman2000atam}, the dominant workload shape $S(a)$, and the hard constraints $K(a)$ -- derived ten times over in Part~\ref{part:applications}. Each pattern $p \in P$ carries a capability profile $C(p) = (c_1(p), \dots, c_{12}(p);\, S(p))$ with ordinal ratings $c_i(p) \in \{++, +, \circ, -, --\}$, justified through tactics \citep{bachmann2003deriving, bass2021software} and calibrated against the star ratings of \citet{richards2025fundamentals} where those exist -- derived seven times over in Part~\ref{part:patterns}.
|
|
\end{sloppypar}
|
|
|
|
\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 computed under a deliberately \emph{non-compensatory, three-stage procedure}:
|
|
\begin{enumerate}
|
|
\item \textbf{Knock-out screening and workload-shape gate.} Hard constraints $K(a)$ eliminate patterns \emph{before} any scoring; a violated constraint cannot be averaged away \citep{keeney1993decisions}. 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), may reach $+$ only where it carries a \emph{constitutive} subsystem of an explicitly shape-hybrid class, and falls to $-$/$--$ where it would actively harm the class's binding scenarios. The gate is read per constitutive path: a pattern is \emph{not} shape-foreign to a class one of whose binding scenarios constitutes a path of the pattern's native shape -- the reading Case~3 (Section~\ref{subsec:case-c2}) applied to C2's fan-out delivery scenario (S2 of Table~\ref{tab:req-c2}).
|
|
\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; clustered conflicts on Medium-weight dimensions can downgrade a rating by one step. The result is a \emph{ranking with exclusions}, never ``pattern A is 12\,\% better''. If the ranking flips under plausible weight variation, that instability marks a genuine tradeoff point in the ATAM sense and must be escalated to scenario-based analysis \citep{kazman2000atam}.
|
|
\end{enumerate}
|
|
\end{definitionbox}
|
|
|
|
The three stages are ordered by decreasing hardness, and each now has a worked face. Stage~1 encodes facts no merit elsewhere can compensate -- a violated BCBS~239 obligation, an interactive pattern asked to carry a scheduled-batch core \citep{bcbs2013rdarr, keeney1993decisions}: Case~1 (Section~\ref{subsec:case-c6}) was this stage running the show, emptying six of the C6 row's seven cells on shape alone. Stage~2 encodes Assumption~A4: the High weights come from the $(H,H)$ leaves of a utility tree, so a structural failure on such a dimension fails precisely the scenarios that define the class -- unless engineering practice has produced a documented way around it \citep{westeinde2019deconstructing, richardson2018microservices}; Case~2 (Section~\ref{subsec:case-c1}) showed both halves of the rule, a mitigation that repairs (MM's hot standby) and one that merely makes survivable under condition (MS's Monzo condition). Stage~3 is deliberately the softest: it produces an ordering, and it carries a built-in alarm for its own instability -- the alarm that fired in Case~3 (Section~\ref{subsec:case-c2}) and returned a hybrid rather than a false winner.
|
|
|
|
\subsection{Why the fit is not a weighted sum}
|
|
|
|
Part~\ref{part:foundations} (Section~\ref{subsec:nomcdm}) established the formal case against the obvious formula $V(p) = \sum_i w_i \cdot v_i(p)$: additive value functions presuppose cardinal scales, preferential independence, and weights as trade-off rates \citep{keeney1993decisions} -- all three violated by ordinal profiles whose trade-offs are the very definition of preferential dependence (Assumption~A2) -- and the best-known repair, AHP, inherits rank reversal and unlicensed scale reinterpretation \citep{saaty1980analytic, belton1983shortcoming, dyer1990remarks, banaecosta2008critical}. What the three cases add is a demonstration of what the formula would have destroyed: it would have averaged the C6 shape gate away under good scores elsewhere, let MS's missing cross-service ACID be compensated by team scaling in C1, and manufactured a decimal-point winner in C2 exactly where the honest output is a flagged tradeoff point. The theory keeps the \emph{explication discipline} of multi-criteria decision analysis -- criteria, weights, and assumptions forced into the open -- and drops its arithmetic pretensions: the matrix of Section~\ref{sec:fitmatrix} is an \emph{explication and communication instrument}, not a computation that determines decisions; the rigorous method behind every contested cell is ATAM \citep{kazman2000atam, clements2002evaluating}, and, where money decides, its economic extension CBAM with utility-response curves and return on investment \citep{kazman2002making}.
|
|
|
|
\begin{keypoint}
|
|
The fit computation is non-compensatory by design: constraints knock out before anything is scored, structural failures on High-weight dimensions veto unless a documented mitigation exists, and only then does a holistic ordinal ranking follow -- with mandatory sensitivity analysis. A weighted sum over ordinal profiles would be formally illegitimate and would average away exactly the failures that matter most.
|
|
\end{keypoint}
|
|
|
|
% ============================================
|
|
% SECTION: THE MATCHING MATRIX
|
|
% ============================================
|
|
\section{The Matching Matrix}
|
|
\label{sec:fitmatrix}
|
|
|
|
\subsection{Cell semantics}
|
|
|
|
\emph{What does one cell of a seventy-cell grid actually claim?} A matrix cell answers one precisely delimited question, and misreading that question is the most common student error with this instrument.
|
|
|
|
\begin{definitionbox}[Cell semantics of the matching matrix]
|
|
A cell $\mathrm{fit}(a, p)$ states the fit of pattern $p$ \emph{as the dominant structure of the core} of application class $a$ -- the pattern that owns the class's binding quality attribute scenarios. It does \emph{not} state whether $p$ is useful anywhere in a system of class $a$: hybrid roles at the edges (an event journal beside an ACID core, a batch pipeline beside an interactive product) are stated in the cell rationale, not in the cell value.
|
|
\end{definitionbox}
|
|
|
|
Two consequences follow. First, a $-$ cell is not a prohibition: EDA rates $-$ as the dominant structure of a banking core, yet the same rationale names the immutable event journal as the natural regulatory audit trail at that core's edges \citep{kleppmann2017designing}. Second, the hexagonal column needs a special reading: HX is a delta pattern of dependency organisation, not a distribution style \citep{cockburn2005hexagonal, cockburn2024hexagonal}; it composes with a host (typically MM), and its cells read ``as the internal discipline of the class's core''.
|
|
|
|
\subsection{The \texorpdfstring{$7 \times 10$}{7 x 10} grid}
|
|
|
|
Table~\ref{tab:fitmatrix} shows the complete matrix -- the three cases of Section~\ref{sec:threecases}, done seventy times. Rows C6, C1, and C2 are the rows you have already computed; the remaining seven were produced by exactly the same three stages per Section~\ref{sec:fit-computation} -- knock-out and shape gate, then the H-dimension veto with documented mitigations, then the holistic ordinal reading -- and every cell is traceable to $R(a) \times C(p)$ through the rationales in Section~\ref{sec:rationales}.
|
|
|
|
\begin{sidewaystable}
|
|
\centering
|
|
\small
|
|
\caption{The matching matrix: architecture--application fit of seven patterns (columns) as the dominant structure of the core of ten application classes (rows). Ratings on the ordinal scale $++$ (excellent fit) to $--$ (structural misfit); bold marks the cells underlying the primary recommendation of each class. Cells are computed by the three-stage procedure of Section~\ref{sec:fit-computation}; the per-class rationales appear in Section~\ref{sec:rationales}.}
|
|
\label{tab:fitmatrix}
|
|
\begin{tabular}{@{}p{5.2cm}ccccccc@{}}
|
|
\toprule
|
|
\textbf{Application class} & \textbf{L} & \textbf{MM} & \textbf{HX}$^{\dagger}$ & \textbf{MS} & \textbf{EDA} & \textbf{PF} & \textbf{SL} \\
|
|
\midrule
|
|
C1 Core banking / transactions & $\circ$ & {\boldmath$++$} & {\boldmath$++$} & $\circ$ & $-$ & $\circ$ & $-$ \\
|
|
C2 Social media / content platform & $\circ$ & $+$ & $\circ$ & {\boldmath$++$} & {\boldmath$++$} & $\circ$ & $\circ$ \\
|
|
C3 Back-office / workflow & $+$ & {\boldmath$++$} & $+$ & $--$ & $-$ & $\circ$ & $\circ$ \\
|
|
C4 ERP / enterprise core system & $\circ$ & {\boldmath$++$} & $+$ & $--$ & $-$ & $\circ$ & $--$ \\
|
|
C5 E-commerce platform & $-$ & {\boldmath$++$} & $+$ & $+$ & $+$ & $\circ$ & $+$ \\
|
|
C6 Simulation / batch compute & $--$ & $\circ$ & $\circ$ & $--$ & $\circ$ & {\boldmath$++$} & $\circ$ \\
|
|
C7 Decision support / BI analytics & $+$ & $+$ & $\circ$ & $-$ & $\circ$ & {\boldmath$++$} & $+$ \\
|
|
C8 Real-time / IoT streaming & $--$ & $-$ & $\circ$ & $+$ & {\boldmath$++$} & $+$ & $-$ \\
|
|
C9 Collaboration / messaging & $\circ$ & $+$ & $\circ$ & $+$ & {\boldmath$++$} & $-$ & $--$ \\
|
|
C10 AI-native analysis / advisory & $-$ & {\boldmath$++$} & {\boldmath$++$} & $\circ$ & $+$ & $+$ & $\circ$ \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
|
|
\vspace{0.5em}
|
|
\begin{minipage}{0.92\textwidth}
|
|
\footnotesize $^{\dagger}$\,HX (hexagonal / ports and adapters) is a delta pattern: it composes with a host pattern (typically MM), and its cells read ``as the internal discipline of the class's core''. Note that the HX column is never negative: as a delta pattern its cost ($c_8 = -$) surfaces only as capped cells where the change rate is low (C6, C7) -- its one-sidedness is a property of its orthogonality to the distribution axis, not a free lunch \citep{cockburn2024hexagonal}. Pattern abbreviations: L = layered/3-tier, MM = modular monolith, MS = microservices, EDA = event-driven architecture, PF = pipes-and-filters/batch pipeline, SL = serverless/FaaS.
|
|
\end{minipage}
|
|
\end{sidewaystable}
|
|
|
|
\begin{keypoint}
|
|
Read a matrix cell as the answer to one question only: \emph{how well does this pattern serve as the dominant structure of this class's core?} The edges of the same system routinely use patterns whose cell reads $\circ$ or $-$ -- the hybrid roles are stated in the rationales, and Section~\ref{sec:hybrids} shows that hybrids are the normal case, not the exception.
|
|
\end{keypoint}
|
|
|
|
% ============================================
|
|
% SECTION: CELL RATIONALES PER APPLICATION CLASS
|
|
% ============================================
|
|
\section{Cell Rationales: The Ten Rows in Detail}
|
|
\label{sec:rationales}
|
|
|
|
This section records, for each application class, the stage-by-stage computation behind every cell of its row -- which gate or knock-out fired, which veto, which documented mitigation lifted which cap -- plus the primary and secondary recommendation and the central trade-off the class forces. Two recurring markers keep the tables compact: \emph{veto} names the High-weight dimension on which the veto rule of Section~\ref{sec:fit-computation} fired, and \emph{mitigation} names the documented tactic or hybrid composition that lifted (or partially lifted) the cap. The operands of each row are the class's requirements table in Part~\ref{part:applications} (Tables~\ref{tab:req-c1}--\ref{tab:req-c10}) and the pattern columns of Table~\ref{tab:capability}; the evidence -- the production systems, the measured numbers -- lives in the ``what real systems chose'' discussions of Part~\ref{part:applications} and is back-referenced here, not re-narrated. Nothing in this section is new evidence: it is the same evidence, now \emph{matched}.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C1 -- Core banking / transaction system}
|
|
\label{subsec:fit-c1}
|
|
|
|
Case~2 (Section~\ref{subsec:case-c1}) computed this row's contested pair, MM against MS, stage by stage; Table~\ref{tab:fit-c1} completes the remaining cells (operands: Table~\ref{tab:req-c1} against the pattern columns of Table~\ref{tab:capability}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C1 (core banking): fit of each pattern as the dominant structure of the booking core.}
|
|
\label{tab:fit-c1}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $\circ$ & A single ACID database satisfies the consistency veto, but technical layering fails the decades-long evolvability requirement (veto D7) and the change-isolation needs of a banking core. \\
|
|
MM & $++$ & Cross-module ACID transactions plus enforced domain boundaries match the ledger's consistency veto and the peripheral change rate (veto D5; mitigation: hot-standby replication, the classical banking HA tactic) -- Fineract's production architecture \citep{fineract2024core}. \\
|
|
HX & $++$ & Ports isolate a long-lived booking core from volatile channels, providers, and AI scoring adapters, making the core hermetically testable -- the standard bank-backend discipline \citep{cockburn2024hexagonal}. \\
|
|
MS & $\circ$ & Sagas replace ACID in the money path (veto D4; mitigation only under the documented Monzo condition: organisational scale plus extreme homogeneity \citep{sewell2024monzo}), and the premium is paid in platform staff with no gain for typical team sizes \citep{fowler2015premium}. \\
|
|
EDA & $-$ & Eventual consistency is vetoed in the booking core (veto D4: High weight against $--$, uncapped as dominant structure); as an \emph{edge} pattern the immutable event journal is the natural regulatory audit trail and integration surface \citep{kleppmann2017designing}. \\
|
|
PF & $\circ$ & Shape gate: end-of-day clearing, statements, and risk runs are genuine batch pipelines, but the pattern cannot carry the interactive account core. \\
|
|
SL & $-$ & Stateful sequential ordering, strict guarantees, and auditable long-lived state conflict with ephemeral stateless functions (veto D4; weak on all remaining High-weight dimensions). \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a hexagonal modular monolith for the booking core. \emph{Secondary:} EDA at the edges (journal, fraud streams, reporting feeds) and PF for the batch runs; microservices only when organisation size forces D11 to High -- the Monzo condition \citep{sewell2024monzo}. \emph{Central trade-off:} \textbf{consistency versus scalability}. Documented practice resolves the conflict not by choosing one pattern but by \emph{placing} patterns -- a strictly consistent, even single-threaded core (the LMAX extreme of Part~\ref{part:applications} \citep{fowler2011lmax}) with eventually consistent, event-fed peripheries, the consistency boundary documented as an ADR and guarded by reconciliation fitness functions. The hybrid answer for this class is therefore the canonical one of the whole matrix: \emph{ACID core, EDA edges}.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C2 -- Social media / content platform}
|
|
\label{subsec:fit-c2}
|
|
|
|
Case~3 (Section~\ref{subsec:case-c2}) ran this row's Stage-3 finale between MS and EDA; Table~\ref{tab:fit-c2} records the full row (operands: Table~\ref{tab:req-c2}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C2 (social media / content platform).}
|
|
\label{tab:fit-c2}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $\circ$ & Instagram proves a layered monolith scales reads via stateless replication \citep{woodruff2019static}, but single-quantum releases and technical partitioning throttle the High-weighted feature velocity (veto D7, D11) as the organisation grows. \\
|
|
MM & $+$ & Buys Instagram-style scaling plus domain-cut change isolation (veto D5; mitigation: replicated instances); the honest ceiling is release coordination once team count passes roughly five. \\
|
|
HX & $\circ$ & Adds testability, but the class's binding constraints (read fan-out, team scaling) live elsewhere, and feed paths carry little long-lived domain logic. \\
|
|
MS & $++$ & Independent scaling of feed, media, and graph services plus independent team deployments match D1, D7, and D11 simultaneously (veto D3; mitigation: edge caching and precomputed timelines \citep{krikorian2013timelines}); the $--$ on cost and simplicity is an accepted price at this scale. \\
|
|
EDA & $++$ & Fan-out-on-write \emph{is} an event flow -- the Twitter timeline architecture \citep{krikorian2013timelines}; new consumers (recommendations, moderation) attach without touching producers (veto D9; mitigation: schema/contract tests plus progressive delivery). \\
|
|
PF & $\circ$ & Shape gate: feed precomputation, ranking-model training, and media processing are pipelines beside the serving path, never the interactive product core. \\
|
|
SL & $\circ$ & Viral spikes suit elastic functions (veto D3: cold starts), yet sustained baseline load makes per-execution pricing structurally expensive \citep{jonas2019berkeley}. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} an EDA + microservices hybrid at organisational scale. \emph{Secondary:} a modular monolith until that scale is \emph{measured}, not assumed -- Mastodon demonstrates full fan-out mechanics in a Rails monolith \citep{mastodon2024docs}. \emph{Central trade-off:} \textbf{read scalability and team scaling versus simplicity and cost}. The deciding measurement is deployments per developer per day as teams multiply \citep{forsgren2018accelerate}; consistency is deliberately sacrificed (eventual feeds) -- the exact mirror image of C1, which is why the pair C1/C2 is the didactic anchor of the whole matrix.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C3 -- Back-office / workflow application}
|
|
\label{subsec:fit-c3}
|
|
|
|
Table~\ref{tab:fit-c3} gives the cell-by-cell rationale for the C3 row (the back-office workflow application; operands: Table~\ref{tab:req-c3}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C3 (back-office / workflow application).}
|
|
\label{tab:fit-c3}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $+$ & CRUD over one ACID store at office-hours load is this pattern's native habitat, and the High weight on D8 rewards its five-star simplicity; but the $-$ on High-weighted evolvability is the documented legacy-rot risk of decade-old back-office systems (veto D7; mitigation only for small, stable scope -- the mitigation is scoping, hence $+$ rather than $++$). \\
|
|
MM & $++$ & The same run cost with domain boundaries that pay off over the 10--20-year evolution horizon that dominates this class's cost \citep{glass2002facts} -- the Pareto choice when process change is frequent. \\
|
|
HX & $+$ & Worth the indirection exactly where long-lived process logic meets volatile integrations -- LDAP, ERP, DMS, workflow engine as adapter \citep{camunda2024zeebe} (veto D8; mitigation: apply ports selectively at the integration seams). \\
|
|
MS & $--$ & The premium buys scaling and team autonomy this class does not need, at simplicity and run costs vetoed twice (veto D8, D10) \citep{fowler2015premium}. \\
|
|
EDA & $-$ & Asynchronous choreography destroys the traceable, sequential process semantics (four-eyes principle, audit trail) the class is built around (veto D8: $--$ on High); a workflow engine, not a broker, is the fit. \\
|
|
PF & $\circ$ & Shape gate: nightly reporting jobs and imports are pipelines at the edge of an interactive forms-over-data core. \\
|
|
SL & $\circ$ & Sporadic office-hours load fits scale-to-zero economics, but the operational skill investment rarely amortises for internal IT. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a modular monolith with externalised process logic (a Camunda-class workflow engine behind a port). \emph{Secondary:} layered 3-tier for small, stable scope. \emph{Central trade-off:} \textbf{day-one simplicity versus multi-decade evolvability}. The measurable tiebreaker is change dispersion per process change: if a reorganisation touches every layer, the layering was wrong.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C4 -- ERP / enterprise core system}
|
|
\label{subsec:fit-c4}
|
|
|
|
Table~\ref{tab:fit-c4} gives the cell-by-cell rationale for the C4 row (the ERP core; operands: Table~\ref{tab:req-c4}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C4 (ERP / enterprise core system).}
|
|
\label{tab:fit-c4}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $\circ$ & One schema, one transaction scope fits the integration mandate, but technical layers offer no discipline against permanent customising pressure at ERP scale (veto D7, with no scoping mitigation available -- ERP scope is never small). \\
|
|
MM & $++$ & Modules over a shared ACID data model with a disciplined extension mechanism is \emph{literally} the Odoo/ERPNext architecture, matched in Part~\ref{part:applications} (Section~\ref{sec:c4}) \citep{odoo2024docs, frappe2024erpnext}; no veto fires -- the $-$ on D5 is Medium-weight: planned maintenance windows are an accepted ERP norm. \\
|
|
HX & $+$ & Ports pay off at the integration peripheries (EDI, banking, tax services) and keep customising out of the core -- the survival condition for 20--30-year life cycles \citep{sap2020maintenance}. \\
|
|
MS & $--$ & Cross-module ACID postings (order $\to$ stock $\to$ ledger) are the product's value and become distributed sagas (veto D4) -- structurally the strongest anti-fit in the grid \citep{richardson2018microservices}. \\
|
|
EDA & $-$ & Eventual consistency between ledger and inventory contradicts the class's defining integrity guarantee (veto D4); events serve only outbound integration. \\
|
|
PF & $\circ$ & Shape gate: period-end closing, MRP, and payroll runs are canonical scheduled pipelines inside the batch window -- a subordinate, well-fitting component. \\
|
|
SL & $--$ & Long transactions, batch windows, stateful sessions, and a monolithic data model contradict short-lived stateless functions on every axis (veto D4, plus the sustained-load cost inversion). \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a modular monolith. \emph{Secondary:} hexagonal discipline within it for the extension ecosystem; layered only for very small scope. \emph{Central trade-off:} \textbf{one integrated data model versus independent module scaling and deployment} -- resolved by module boundaries \emph{inside} one transactional quantum, not by process boundaries. Decades of ERP practice, and the near-absence of viable microservice ERPs, are the empirical evidence that integration wins here.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C5 -- E-commerce platform}
|
|
\label{subsec:fit-c5}
|
|
|
|
Table~\ref{tab:fit-c5} gives the cell-by-cell rationale for the C5 row (the e-commerce platform; operands: Table~\ref{tab:req-c5}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C5 (e-commerce platform).}
|
|
\label{tab:fit-c5}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $-$ & A small shop is served honestly, but the single write path is precisely what the class's defining 10--50$\times$ seasonal peaks break (veto D2: $--$ on High, no mitigation within the pattern), and full-regression releases fail D9. \\
|
|
MM & $++$ & Shopify's Packwerk-enforced modular Rails core carries peaks of roughly 280 million requests per minute while preserving checkout ACID (veto D2; mitigation: pod-sharded replication; veto D5; mitigation: replicated pods) -- the class's canonical case study \citep{westeinde2019deconstructing, shopify2024bfcm}. \\
|
|
HX & $+$ & Ports around payment, logistics, tax, and search providers localise the class's very high integration churn -- and shrink the PCI audit scope \citep{pcissc2022pcidss}. \\
|
|
MS & $+$ & Amazon's founding case shows the fit at organisational scale (veto D3; mitigation: caching and edge delivery); below that scale the platform premium ($--$ on Medium-weight D10) eats margin -- the rating rises to $++$ only when D11 measurably binds. \\
|
|
EDA & $+$ & Order flows, inventory updates, and saga-based checkout choreography are naturally event-shaped at the edges of an ACID checkout \citep{richardson2018microservices} (veto D9; mitigation: contract tests, progressive delivery). \\
|
|
PF & $\circ$ & Shape gate: catalogue feeds, search indexing, and recommendation training are supporting pipelines, not the storefront. \\
|
|
SL & $+$ & Flash-sale spikes are the textbook elastic-load case (veto D3; mitigation: provisioned concurrency and edge runtimes); sustained catalogue traffic and checkout latency SLOs keep it from primary status \citep{jonas2019berkeley}. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a modular monolith with a hybrid consistency profile inside (catalogue eventual, checkout ACID) and event-driven edges. \emph{Secondary:} microservices at organisational scale -- team size, not traffic, decides MM versus MS (the Shopify-versus-Amazon contrast). \emph{Central trade-off:} \textbf{seasonal elasticity versus checkout consistency}. The measurable contract: p95 checkout latency and zero uncompensated oversells during peak-load tests at ten times baseline.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C6 -- Scientific simulation / batch compute}
|
|
\label{subsec:fit-c6}
|
|
|
|
Case~1 (Section~\ref{subsec:case-c6}) computed this row almost entirely at Stage~1; Table~\ref{tab:fit-c6} records the per-cell residue (operands: Table~\ref{tab:req-c6}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C6 (scientific simulation / batch compute).}
|
|
\label{tab:fit-c6}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $--$ & Shape gate plus veto D2: an interactive serving pattern has no answer to makespan, checkpointing, or CPU-hour cost -- a category error. \\
|
|
MM & $\circ$ & Numeric kernels are monolithic \emph{code} (OpenFOAM-style), but the architecture class around them is the pipeline; the module system contributes nothing to throughput (cap via D2) \citep{openfoam2024guide}. \\
|
|
HX & $\circ$ & Ports around solvers and data sources buy testability of orchestration code; the compute core and the binding cost dimension are untouched. \\
|
|
MS & $--$ & Distributing a tightly coupled numeric dataflow across service boundaries multiplies communication cost (veto D10) -- the general form of the Prime Video lesson at HPC scale \citep{kolny2023primevideo}. \\
|
|
EDA & $\circ$ & A replayable log is useful glue for job status, but continuous event semantics add machinery where a scheduler and a DAG already express the whole control flow (cap via D9). \\
|
|
PF & $++$ & Immutable inputs $\to$ deterministic stages $\to$ versioned outputs under Slurm/Airflow/Spark is the class's dominant form, with reproducibility by construction \citep{yoo2003slurm, zaharia2012resilient, glasserman2003monte}. \\
|
|
SL & $\circ$ & Embarrassingly parallel bursts (Monte-Carlo fan-out) fit FaaS elasticity, but data-heavy inter-stage communication through storage recreates the Prime Video cost trap -- the split D10 rating resolves against it for data-intensive stages \citep{kolny2023primevideo}. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} pipes-and-filters on HPC/batch infrastructure. \emph{Secondary:} serverless fan-out for bursty, communication-light parallel sections. \emph{Central trade-off:} \textbf{elastic scale-out versus data affinity} -- measured as cost per simulation and communication share of runtime. When inter-node communication dominates (Amdahl's regime), consolidate; do not distribute.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C7 -- Decision support / BI analytics}
|
|
\label{subsec:fit-c7}
|
|
|
|
Table~\ref{tab:fit-c7} gives the cell-by-cell rationale for the C7 row (BI analytics; operands: Table~\ref{tab:req-c7}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C7 (decision support / BI analytics).}
|
|
\label{tab:fit-c7}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $+$ & The serving tier is honestly a thin layered application that delegates heavy reads to the warehouse -- Metabase ships as one JAR for exactly this reason \citep{metabase2024docs}. \\
|
|
MM & $+$ & The same fit with cleaner seams between semantic model, query, and visualisation concerns as the tool estate grows. \\
|
|
HX & $\circ$ & Adapter isolation of warehouse dialects helps tool vendors more than in-house BI teams; the dominant contracts are data schemas, not code ports. \\
|
|
MS & $-$ & Splitting a read-only analytical product into services adds network and platform cost against no High-weight dimension (veto D10: $--$ on High). \\
|
|
EDA & $\circ$ & Streaming ingestion earns its broker-operations complexity only when the freshness contract measurably tightens below the batch window \citep{kreps2011kafka}. \\
|
|
PF & $++$ & The modern data stack \emph{is} an ELT pipeline -- sources $\to$ orchestrated DAGs $\to$ warehouse $\to$ serving -- with lineage and refresh contracts as first-class audit artefacts (D1 is delegated to the output store by design) \citep{beauchemin2015airflow, kimball2013warehouse}. \\
|
|
SL & $+$ & Scheduled, spiky transformation jobs are a natural fit for pay-per-run functions (the $++$ side of the split D10 rating), though warehouse-native scheduling often does the same more cheaply. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} pipes-and-filters (ELT) feeding a layered serving tier -- the canonical hybrid of the row. \emph{Secondary:} EDA ingestion where freshness SLAs demand it. \emph{Central trade-off:} \textbf{data freshness versus cost and simplicity}. ``Consistency as of the last refresh'' is a deliberately chosen third consistency semantics beside ACID and eventual; the ADR to write is the freshness contract, the fitness functions are refresh-window adherence and p95 dashboard latency -- and tightening freshness towards real time drags the class into C8 economics.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C8 -- Real-time / IoT streaming}
|
|
\label{subsec:fit-c8}
|
|
|
|
Table~\ref{tab:fit-c8} gives the cell-by-cell rationale for the C8 row (real-time streaming; operands: Table~\ref{tab:req-c8}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C8 (real-time / IoT streaming).}
|
|
\label{tab:fit-c8}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $--$ & Shape gate plus veto D2: a synchronous request/response monolith cannot sustain continuous ingest at the world's production rate with backpressure. \\
|
|
MM & $-$ & Modularity helps the codebase, but the single quantum caps sustained ingest and fault isolation (veto D2, D5) and cannot provide the durable, partitioned, replayable transport the class is defined by. \\
|
|
HX & $\circ$ & Ports isolate processing logic from broker APIs (easing Kafka-to-Pulsar-style migrations); the binding constraints are throughput semantics, not dependency direction. \\
|
|
MS & $+$ & Stream processors deploy naturally as long-running services aligned with the dataflow (which keeps the D3 concern out of a request/response path) -- provided boundaries follow the flow, exactly where Segment's per-destination cut failed \citep{noonan2018goodbye}. \\
|
|
EDA & $++$ & A durable, partitioned, replayable log with decoupled producers and consumers is the class's defining structure -- Kafka's origin story \citep{kreps2011kafka, lee2019kafka}. \\
|
|
PF & $+$ & Stream processing is pipes-and-filters over a log -- the batch form's latency rating ($--$ on High-weighted D3, veto) is lifted by its documented streaming incarnation with exactly-once checkpointing \citep{carbone2017state, akidau2015dataflow}. \\
|
|
SL & $-$ & Per-event function invocation at sustained millions of events per second is dominated economically (the $--$ side of the split D10 rating) and latency-wise (cold starts, veto D3) by long-running stream processors. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} EDA (log-centric broker topology) with streaming pipes-and-filters as the processing layer -- Kafka + Flink + OLAP serving, the documented Uber stack \citep{fu2021realtime}. \emph{Secondary:} microservice processors where team ownership demands it. \emph{Central trade-off:} \textbf{delivery semantics versus operational complexity and cost}. Exactly-once and event-time correctness are bought with checkpointing machinery and a permanent operations competence; the pragmatic norm is at-least-once plus idempotence, decided per stream, per scenario. The measurement contract: consumer lag, watermark delay, and duplicate rate under chaos experiments.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C9 -- Collaboration / messaging}
|
|
\label{subsec:fit-c9}
|
|
|
|
Table~\ref{tab:fit-c9} gives the cell-by-cell rationale for the C9 row (collaboration/messaging; operands: Table~\ref{tab:req-c9}).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C9 (collaboration / messaging).}
|
|
\label{tab:fit-c9}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $\circ$ & Fine for small installations, but millions of long-lived stateful connections are a resource profile the pattern never modelled (cap via D5). \\
|
|
MM & $+$ & No veto beyond D5 (mitigation: replicated instances); the single-binary-by-design fit is the Mattermost case of Part~\ref{part:applications} (Section~\ref{sec:c9}) \citep{mattermost2024docs}. \\
|
|
HX & $\circ$ & Helps swap storage and push providers (Discord's MongoDB $\to$ Cassandra $\to$ ScyllaDB path); the class's crux -- connection fan-out -- is orthogonal to dependency direction \citep{ingram2023discord}. \\
|
|
MS & $+$ & Discord's per-attribute specialisation (BEAM gateways, Rust data services) shows targeted services exactly where tail latency demands them (veto D3; mitigation: specialised low-latency services) \citep{ingram2023discord}. \\
|
|
EDA & $++$ & Gate passed on the push path -- the class's binding fan-out delivery scenario (Table~\ref{tab:req-c9}); no veto on the High set, and the pattern--domain coincidence is the one Part~\ref{part:applications} records for the push layer (Section~\ref{sec:c9}) \citep{hohpe2003enterprise}. \\
|
|
PF & $-$ & Shape gate plus veto D3 ($--$ on High): interactive bidirectional message flows are the opposite of unidirectional batch transformation (history exports aside). \\
|
|
SL & $--$ & Structural knock-out: long-lived WebSocket connection state is the canonical anti-case for short-lived stateless functions \citep{jonas2019berkeley}. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a hybrid -- a monolithic persistence and business core with a specialised event-driven push layer, Slack's documented shape (PHP/Hack core plus the Flannel edge cache) \citep{slack2017flannel}. \emph{Secondary:} a modular monolith alone for the self-hosted market segment. \emph{Central trade-off:} \textbf{real-time fan-out at global scale versus deployability and simplicity}. The tiebreaker is the measured concurrent-connection count: below roughly $10^5$ connections the specialised push layer is premature. The same functionality spans Mattermost's single binary and Discord's polyglot cluster -- scale and business model, not the domain, decide.
|
|
|
|
% --------------------------------------------
|
|
\subsection{C10 -- AI-native analysis / advisory platform}
|
|
\label{subsec:fit-c10}
|
|
|
|
This is the course-project class, and its match has already run once: the mini-match of Part~\ref{part:foundations} (Table~\ref{tab:minimatch}) computed L, MM, and MS against its five High weights. Table~\ref{tab:fit-c10} extends the row to all seven candidates (operands: Table~\ref{tab:req-c10} -- rare-but-heavy requests, provenance and per-step audit duties with potential legal force \citep{eu2024aiact}, extreme model and prompt churn, per-request cost as a first-order concern).
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\footnotesize
|
|
\caption{Cell rationales for C10 (AI-native analysis / advisory platform -- the course-project class).}
|
|
\label{tab:fit-c10}
|
|
\begin{tabular}{@{}lcp{12.2cm}@{}}
|
|
\toprule
|
|
\textbf{Pattern} & \textbf{Fit} & \textbf{Rationale} \\
|
|
\midrule
|
|
L & $-$ & Technical layers give the non-deterministic component no boundary, no queue, and no measurement point -- the three things it needs most (veto D7; $-$ on High-weighted D9). \\
|
|
MM & $++$ & A domain-cut monolith hosts the deterministic services (data access, computation, audit) cheaply and gives the AI subsystem a hard module boundary that CI can verify \citep{drotbohm2023modulith} (the $-$ on D5 is Medium-weight and mitigated by replication). \\
|
|
HX & $++$ & The LLM is an adapter on a port: swappable on provider deprecation, mockable in tests, guarded by contract validation -- the anti-corruption layer for a component that would otherwise corrupt the domain \citep{evans2003ddd, cockburn2024hexagonal, sculley2015hidden}. \\
|
|
MS & $\circ$ & Per-service blast-radius control is welcome, but synchronous service chains multiply seconds-scale LLM latency and failure rates \citep{nygard2018release}; the D10-High veto targets per-request AI cost -- a gateway concern orthogonal to distribution -- so the platform-cost $--$ relaxes to $\circ$ rather than $-$. \\
|
|
EDA & $+$ & Queues absorb LLM latency, rate limits, and outages, and create natural batching points for cost control -- asynchronous integration is the default for non-interactive AI work (veto D9; mitigation: the eval harness replaces end-to-end event testing as the correctness instrument). \\
|
|
PF & $+$ & Ingestion $\to$ chunking $\to$ embedding $\to$ index, and the eval harness itself, are pipelines with versioned data contracts \citep{lewis2020rag, barnett2024seven}; $+$ rather than $++$ because the interactive advisory surface is not a pipeline ($--$ on Medium-weight D3). \\
|
|
SL & $\circ$ & Event-glue around batch APIs fits (spiky advisory load hits the $++$ side of the split D10 rating); platform timeouts against minutes-long LLM/solver runs and opaque per-call cost stacking do not \citep{jonas2019berkeley}. \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\emph{Primary recommendation:} a hexagonal modular monolith -- deterministic core, AI adapters at ports, an LLM gateway as the single measurement point -- plus pipes-and-filters for ingestion and evals and an orchestrated agent workflow for the AI layer. This is a \emph{designed hybrid}, and saying so explicitly is part of the theory. \emph{Secondary:} EDA for the AI job and audit spine. \emph{Central trade-off:} \textbf{agent autonomy and capability versus cost, latency, and testability} -- governed by a token-cost budget and a p95 latency budget per use case as CI-gated fitness functions (Section~\ref{sec:contract}), and by the determinism boundary: \emph{LLM agents propose; deterministic services decide and book} (Part~\ref{part:ai}).
|
|
|
|
\begin{keypoint}
|
|
Every cell of the ten rows is traceable to the same mechanics: $R(a)$ against $C(p)$, a veto where a High weight meets a deep deficit, and a documented mitigation wherever a cap was lifted. The recurring resolution across the rows is \emph{consistent core, asynchronous edges} -- hybrids arise by \emph{placing} patterns in different subsystems, never by averaging their scores.
|
|
\end{keypoint}
|
|
|
|
% ============================================
|
|
% SECTION: READING THE MATRIX AS A WHOLE
|
|
% ============================================
|
|
\section{Reading the Matrix as a Whole}
|
|
\label{sec:matrix-reading}
|
|
|
|
\emph{What does the grid say as a whole that no single cell can?} The matrix rewards a second reading -- not cell by cell but by columns, rows, and boundaries.
|
|
|
|
\subsection{Column patterns: the unfashionable default and the earned premium}
|
|
|
|
Column-wise, the \textbf{modular monolith is primary or secondary in seven of ten classes} -- not because it is fashionable (it is conspicuously unfashionable) but because most requirements profiles weight consistency, evolvability, cost, and time-to-market higher than independent scaling, and MM is the only pattern rated $+$ or better on all four of those dimensions (Table~\ref{tab:capability}). This is the matrix-level restatement of Fowler's MonolithFirst argument: do not start with microservices even if you expect to need them, because stable service boundaries cannot be cut before the domain is understood, and refactoring \emph{between} services is far costlier than \emph{within} a monolith \citep{fowler2015monolith}.
|
|
|
|
\textbf{Microservices earn their premium in exactly two situations}, both visible in the grid: where High-weight read scalability, fault isolation, and team scaling coincide (C2, and conditionally C5 and C8), and nowhere else. The premium is real and quantified: the pattern rates $--$ on cost and simplicity \citep{richards2025fundamentals}, and the run-cost side materialises as platform staffing -- self-managed Kubernetes total cost of ownership runs roughly three times managed offerings, dominated by personnel \citep{fowler2015premium, portainer2024k8scost}. The two $--$ cells in the MS column (C3, C4) mark the classes that pay the premium and collect nothing.
|
|
|
|
\textbf{PF and EDA are workload-shaped columns.} Their $++$ cells sit precisely where the class's dominant workload shape matches the pattern's native shape -- scheduled batch for PF (C6, C7), continuous stream or fan-out for EDA (C8, C9, and the C2 fan-out) -- and the shape gate caps them at $\circ$ everywhere the class core is interactive. These two columns are the clearest demonstration that the gate of Stage~1 does real work: no amount of merit on other dimensions lets a batch pipeline carry an interactive core.
|
|
|
|
\textbf{The HX column is never negative} -- and that is not a free lunch but a property of orthogonality: as a delta pattern, hexagonal architecture composes with the host rather than competing with it, and its cost ($c_8 = -$) surfaces only as capped cells where the change rate is low (C6, C7) \citep{cockburn2024hexagonal}.
|
|
|
|
\subsection{Row patterns and the empirical support points}
|
|
|
|
Row-wise, \textbf{no class is served above $\circ$ by every pattern, and no pattern serves every class above $\circ$} -- Assumption~A2 made visible in a single glance at the grid. If a dominant pattern existed, its column would be uniformly positive, and this part of the module would be one page long.
|
|
|
|
Cell-wise, the five case-study systems of the module -- Prime Video, Segment, Shopify, Uber, and Stack Overflow -- each sit exactly on a cell boundary: they are the empirical support points at which fit and misfit have been \emph{measured in money}. Prime Video sits on the split serverless cost cell (over 90\,\% infrastructure cost reduction after consolidating a data-intensive flow into one process) \citep{kolny2023primevideo, cockcroft2023prime}; Segment sits on the MS evolvability cell read against a wrongly cut boundary (services per configuration instance, not per domain seam) \citep{noonan2018goodbye}; Shopify sits on the MM write-scalability mitigation (pod-sharded replication) \citep{westeinde2019deconstructing, shopify2024bfcm}; Uber's DOMA sits on the MS team-scaling cell at the point where service count itself became the problem \citep{gluck2020doma}; and Stack Overflow sits on the layered read-scalability deviation (cache-friendly read dominance served by roughly nine web servers) \citep{craver2016stackoverflow}.
|
|
|
|
\begin{keypoint}
|
|
The modular monolith dominates the matrix as default not despite but because of its unfashionableness: most requirements profiles weight consistency, evolvability, cost, and time-to-market above independent scaling. Microservices earn their documented premium only where read scalability, fault isolation, and team scaling are simultaneously High -- and the premium is paid in platform staffing either way \citep{fowler2015premium, forsgren2018accelerate}.
|
|
\end{keypoint}
|
|
|
|
\begin{thinkbox}
|
|
Take the C5 row (e-commerce) and increase the organisation from 3 teams to 30 while holding traffic constant. Which cells change, through which dimension, and at which stage of the three-stage procedure? Now hold the organisation at 3 teams and multiply traffic by 50. Why does the second variation move the row so much less than the first -- and what does that say about the popular claim that ``we need microservices to scale''?
|
|
\end{thinkbox}
|
|
|
|
% ============================================
|
|
% SECTION: HYBRIDS AND EVOLUTION PATHS
|
|
% ============================================
|
|
\section{Hybrids and Evolution Paths}
|
|
\label{sec:hybrids}
|
|
|
|
\emph{What happens when a fit that was right stops being right?} Four documented episodes set this section's agenda. In 2018, Segment -- whose per-destination microservice cut had grown into more than 140 services a small team could no longer test or operate -- consolidated them back into one deployable \citep{noonan2018goodbye}. In 2023, Amazon Prime Video moved its audio/video monitoring workflow from a serverless orchestration into a single process and cut infrastructure cost by over 90\,\% \citep{kolny2023primevideo, cockcroft2023prime}. Shopify chose the opposite of extraction: stay a monolith, enforce module boundaries with Packwerk, shard whole-monolith pods \citep{westeinde2019deconstructing, shopify2024bfcm}. And the classical outward move -- growing the new structure around a legacy core -- has carried its own name since 2004: the Strangler Fig \citep{fowler2004strangler}. None of these corrects a wrong initial decision; each is a fit that \emph{was} right decaying as profile, organisation, or measured load drifted -- Assumption~A5 in production. This section teaches the two instruments for exactly that situation, as rules rather than footnotes: hybrids, which place different patterns where one no longer serves all subsystems, and evolution paths, the documented, repeatable repairs between patterns.
|
|
|
|
\subsection{Hybrids are the normal case}
|
|
|
|
Eight of the ten primary recommendations in Section~\ref{sec:rationales} are compositions: a consistent core with event-driven edges (C1, C5), a pipeline feeding a serving layer (C7), a log with stream processors (C8), a monolith with a specialised push layer (C9), a hexagonal core with pipelines and orchestration (C10). Only C4 (the pure modular monolith) and C6 (the pure pipeline) come close to a single-pattern answer -- and even they carry subordinate pipelines and glue.
|
|
|
|
The unit of fit evaluation is therefore the \emph{subsystem with its own architecture quantum} -- its own unit of deployment, scaling, and failure. Applying the matrix to a whole enterprise in one stroke is a category error the theory explicitly forbids: the question is never ``is this company a microservices company?'' but ``what is the dominant structure of \emph{this} subsystem's core, and which patterns serve its edges?''. The composition itself must be recorded; a C4-model container diagram is the natural notation, since the seven patterns differ most visibly at container level \citep{brown2024c4}.
|
|
|
|
\subsection{Fit is a function of time}
|
|
|
|
Lehman's laws guarantee the drift the opening episodes displayed: a system embedded in the real world must continually change or become progressively less useful, and its complexity increases unless work is invested to reduce it \citep{lehman1980laws, lehman1996laws}. A fit established at design time therefore decays (Assumption~A5), and every recommendation must carry a migration strategy. Three documented strategies span the space:
|
|
|
|
\begin{itemize}
|
|
\item \textbf{MonolithFirst.} The argument already met in Section~\ref{sec:matrix-reading}: stable service boundaries cannot be cut before the domain is understood, so do not start with microservices even if you expect to need them \citep{fowler2015monolith}. The matrix encodes this as the MM column's default dominance; the evolution path encodes it as the sanctioned starting state.
|
|
\item \textbf{Strangler Fig.} Grow the new structure around the old, intercepting and capturing function by function, keeping the migration incremental and stoppable at any point \citep{fowler2004strangler}. The pattern works in both directions. Outward: extracting services from a monolith along verified module boundaries. Inward: the Segment and Prime Video consolidations that opened this section \citep{noonan2018goodbye, kolny2023primevideo}. Uber's DOMA shows a third direction: beyond roughly 2{,}200 services, a \emph{second} structuring level (about 70 domains with gateways) had to be re-introduced -- convergence back towards macro-modules \citep{gluck2020doma}.
|
|
\item \textbf{Sacrificial architecture.} Consciously accept that the current structure will be replaced in a few years while keeping internal quality high \citep{fowler2014sacrificial} -- especially legitimate for AI-native components whose model and tool landscape turns over in months.
|
|
\end{itemize}
|
|
|
|
Figure~\ref{fig:evolution} summarises the documented evolution paths between the patterns as a state diagram: states are patterns, transitions are named migration strategies with their documented cases.
|
|
|
|
\begin{figure}[htbp]
|
|
\centering
|
|
\resizebox{\textwidth}{!}{%
|
|
\begin{tikzpicture}[
|
|
sysbox/.style={rectangle, draw, rounded corners=4pt, minimum width=3.4cm, minimum height=1.2cm, align=center, font=\small\sffamily, line width=0.8pt},
|
|
core/.style={sysbox, fill=bankblue!20, draw=bankblue, font=\small\sffamily\bfseries},
|
|
comp/.style={sysbox, fill=bankgreen!15, draw=bankgreen},
|
|
extern/.style={sysbox, fill=gray!15, draw=gray!60!black},
|
|
arr/.style={-{Stealth[length=2.5mm]}, thick, gray!60!black},
|
|
lbl/.style={font=\footnotesize\sffamily, align=center}
|
|
]
|
|
\node[extern] (L) at (0,0) {L\\Layered monolith};
|
|
\node[core] (MM) at (8,0) {MM\\Modular monolith};
|
|
\node[comp] (MS) at (16,0) {MS\\Microservices};
|
|
\node[extern] (SL) at (0,-4.0) {SL\\Serverless orchestration};
|
|
\node[comp] (DOM) at (16,-4.0) {Domain-bundled\\services (DOMA)};
|
|
|
|
\draw[arr] (L) -- node[lbl, above=1pt] {enforce domain boundaries\\(Packwerk, ArchUnit, Modulith)} (MM);
|
|
\draw[arr] (MM) -- node[lbl, above=1pt] {Strangler-Fig extraction\\when D11 measurably binds} (MS);
|
|
\draw[arr] (MS.south west) to[bend left=22] node[lbl, below=3pt] {consolidation (Segment 2018)} (MM.south east);
|
|
\draw[arr] (MS) -- node[lbl, right=3pt] {re-bundle into $\sim$70 domains\\(Uber DOMA 2020)} (DOM);
|
|
\draw[arr] (SL.east) -| node[lbl, above=2pt, pos=0.22] {process consolidation\\(Prime Video 2023, $-90\,\%$ cost)} (MM.south);
|
|
\draw[arr, dashed] (L.north) to[out=55, in=125, looseness=1.1] node[lbl, above=2pt] {sacrificial rebuild (planned replacement)} (MM.north);
|
|
\end{tikzpicture}}%
|
|
\caption{Documented evolution paths between architectural patterns. States are patterns; labelled transitions are migration strategies with their documented cases \citep{fowler2004strangler, fowler2015monolith, fowler2014sacrificial, noonan2018goodbye, kolny2023primevideo, gluck2020doma}. The modular monolith is both the sanctioned starting state (MonolithFirst) and the documented consolidation target.}
|
|
\label{fig:evolution}
|
|
\end{figure}
|
|
|
|
\begin{keypoint}
|
|
\textbf{Maxim 5.} Choose the pattern for the requirements profile you can verify today; buy options on the profile you expect tomorrow -- via module boundaries, ports, and a strangler-ready seam, not via speculative distribution. Every arrow in Figure~\ref{fig:evolution} is cheaper to traverse when the boundaries it needs were bought in advance as modules and ports rather than as processes.
|
|
\end{keypoint}
|
|
|
|
\begin{ailinse}[Sacrificial architecture for AI-native components]
|
|
Axis~B sharpens the evolution argument. LLM providers deprecate models on windows of months, not years \citep{openai2026deprecations}, and the agent-framework landscape turns over even faster. For the AI layer of a C10 system, sacrificial architecture is therefore not an admission of failure but the rational default \citep{fowler2014sacrificial}: design the AI subsystem to be replaced -- behind a port, with an eval harness as the acceptance gate for its successor -- while the deterministic core is designed to last. The port boundary converts a provider deprecation from an architecture revision (the steep part of the cost-of-change curve, Section~\ref{sec:contract}) into an adapter task.
|
|
\end{ailinse}
|
|
|
|
% ============================================
|
|
% SECTION: THE DECISION PROCEDURE
|
|
% ============================================
|
|
\section{The Decision Procedure}
|
|
\label{sec:procedure}
|
|
|
|
\emph{How does a pre-filtered shortlist become a defensible decision?} The matrix pre-filters; it does not decide. The teachable, auditable procedure compresses the SEI method family \citep{bass2021software, barbacci2003quality, kazman2000atam} into eight steps, each with a defined artefact and a defined measurement, and continues into the life cycle per Assumption~A5.
|
|
|
|
\begin{enumerate}
|
|
\item[\textbf{(i)}] \textbf{Identify the ASRs.} Mine business goals, stakeholder interviews, and the regulatory frame -- not the requirements document alone, which empirically under-specifies architecturally significant requirements \citep{chen2013characterizing}. Classify the system as an instance (or blend) of the ten application classes -- a \emph{hypothesis about its ASR bundle} to inherit and then correct.
|
|
\item[\textbf{(ii)}] \textbf{Formulate quality attribute scenarios with response measures.} Six parts each; no scenario without a number \citep{bass2021software}. An unfalsifiable requirement cannot discriminate between patterns (Assumption~A4).
|
|
\item[\textbf{(iii)}] \textbf{Prioritise in a utility tree.} Rate each leaf on (business importance, achievement difficulty) $\in \{H,M,L\}^2$; the $(H,H)$ leaves \emph{are} the weights of $R(a)$ -- this is where the matrix weights come from, so they are derivable, not arbitrary \citep{kazman2000atam}.
|
|
\item[\textbf{(iv)}] \textbf{Pre-filter candidate patterns via the matrix.} Apply the knock-out constraints and shape gate first, then the veto rule (Section~\ref{sec:fit-computation}). Output: two to three candidate patterns or compositions, including the hybrid options named in the relevant class row.
|
|
\item[\textbf{(v)}] \textbf{Trade-off analysis (ATAM-light).} Walk the $(H,H)$ scenarios against each candidate's tactic bundle; identify \emph{sensitivity points} (one decision, large effect on one attribute) and \emph{tradeoff points} (one decision, opposing effects on several attributes); classify each as risk or non-risk \citep{kazman2000atam, clements2002evaluating}. Where money decides, extend with CBAM utility-response curves -- what is 99.99\,\% availability \emph{worth}, versus 99.9\,\%? \citep{kazman2002making}. Sensitivity analysis is mandatory: vary the weights plausibly; if the recommendation flips, you have found a genuine tradeoff point that deserves stakeholder negotiation, not a formula.
|
|
\item[\textbf{(vi)}] \textbf{Decide and record as an ADR.} Context, decision, consequences -- including the negative ones; superseded, never edited \citep{nygard2011documenting}. The MADR fields ``decision drivers / considered options'' carry the utility-tree weights and the matrix row into the record \citep{kopp2018markdown}; this fulfils ISO/IEC/IEEE 42010 Clause~6.10 by construction and counters architectural knowledge vaporisation \citep{iso2022architecture, jansen2005software}.
|
|
\item[\textbf{(vii)}] \textbf{Define the measurement contract.} Every ADR ends with the fitness functions that would falsify it -- with thresholds (Section~\ref{sec:contract}).
|
|
\item[\textbf{(viii)}] \textbf{Measure in operation and keep evolution paths open.} The DORA metrics and the quality-attribute-specific measures run continually; Lehman indicators (growth, complexity trend, debt stock) run quarterly \citep{lehman1980laws, cunningham1992wycash, kruchten2012techdebt}. When measurements falsify the decision, the sanctioned responses are the documented evolution paths of Section~\ref{sec:hybrids}. A revised decision is a new ADR that supersedes -- never silently overwrites -- the old one.
|
|
\end{enumerate}
|
|
|
|
Note how much of this you have already done. Steps~(i)--(iii) are the pipeline Part~\ref{part:applications} ran ten times over -- challenges to binding scenarios to utility-tree weights -- so classifying and weighting a profile is inherited work, corrected against elicited scenarios rather than invented. Steps~(iv)--(vi) are the three cases of Section~\ref{sec:threecases} performed under governance: the same gate, veto, and ordinal reading, with the sensitivity analysis escalated to stakeholders and the outcome recorded. Steps~(vii) and~(viii) are the genuinely new obligations, and the remainder of this part belongs to them.
|
|
|
|
\begin{keypoint}
|
|
\textbf{Maxim 6} (restated from Part~\ref{part:foundations}). An architecture decision without a response measure is an opinion; with a response measure and a fitness function it is a testable hypothesis. The eight steps exist to manufacture exactly that transformation -- from stakeholder concern to falsifiable, monitored commitment.
|
|
\end{keypoint}
|
|
|
|
\subsection{A full worked example: the course-project decision run}
|
|
\label{subsec:decision-example}
|
|
|
|
\begin{examplebox}[Decision run for the Portfolio Intelligence Platform (class C10) -- steps (i)--(iv)]
|
|
\textbf{(i) ASRs.} The platform analyses client portfolios and generates advisory answers with LLM support. Stakeholder interviews and the regulatory frame yield the ASR bundle: grounded answers with provenance, complete per-step audit logging (EU AI Act duties may attach \citep{eu2024aiact}), per-request cost control, provider-migration robustness, and an extreme change rate for prompts and models. Classification: an instance of C10, inheriting C6/C7 traits (index and eval pipelines) and C3 traits (deterministic services).
|
|
|
|
\textbf{(ii) Scenarios.} The binding scenario: \emph{a customer (source) submits a request for which the LLM generates a factually wrong recommendation (stimulus) in normal operation (environment) of the advisory platform (artifact); the deterministic validation layer blocks the answer and escalates to a human (response); detection rate $\geq 99\,\%$ at $< 2$\,s added latency (response measure)} \citep{bass2021software}. Companion scenarios fix the cost budget (token cost per request $\leq$ CHF~0.40 at p95), the latency budget (advisory answer $< 20$\,s end-to-end), and the migration scenario (provider deprecation absorbed within one sprint, zero domain-code changes).
|
|
|
|
\textbf{(iii) Utility tree.} The $(H,H)$ leaves land on D6 (auditability), D7 (evolvability under model churn), D9 (testability, operationalised as eval pass rate), D10 (cost per request), and D12 (AI integrability) -- reproducing the High weights of the C10 column in Table~\ref{tab:requirements}, as the theory predicts.
|
|
|
|
\textbf{(iv) Matrix shortlist.} The C10 row (Table~\ref{tab:fit-c10}) yields MM $++$ and HX $++$ as core candidates, with EDA $+$ (job/audit spine) and PF $+$ (ingestion and eval pipelines) as named edge patterns; L is excluded by veto, MS and SL are capped at $\circ$. Shortlist: (a) hexagonal modular monolith with pipelines and an async job spine; (b) the same core with a fuller EDA backbone.
|
|
\end{examplebox}
|
|
|
|
\begin{examplebox}[Decision run for the Portfolio Intelligence Platform (class C10) -- steps (v)--(viii)]
|
|
\textbf{(v) ATAM-light.} Walking the $(H,H)$ scenarios against both candidates identifies one dominant \emph{sensitivity point} -- the placement of the LLM gateway, on which auditability, cost telemetry, and migration cost all hinge -- and one genuine \emph{tradeoff point}: LLM context length (answer quality up; cost and latency down) \citep{kazman2000atam}. The weight variation test flips nothing between (a) and (b) for the core; it does flip the job-spine choice when audit-log completeness is weighted maximally, which is recorded as a risk to be retired by a spike. CBAM reasoning settles the spine: the fuller EDA backbone buys availability the class only weights Medium, at an operations cost the class weights High \citep{kazman2002making} -- candidate (a) wins.
|
|
|
|
\textbf{(vi) ADR.} The decision is recorded as ADR-007 (Listing~\ref{lst:adr007}), whose decision drivers are the utility-tree weights and whose considered options are the matrix shortlist -- one matrix row, narrated.
|
|
|
|
\textbf{(vii) Measurement contract.} ADR-007 ends with the fitness functions of Table~\ref{tab:contract}: module-boundary verification, the determinism-boundary rule, latency and token budgets, eval pass rate, reconciliation, and chaos drills -- each with threshold and cadence.
|
|
|
|
\textbf{(viii) Operation.} The DORA four keys run per deployable unit; the eval harness gates every prompt and model change; Lehman indicators run quarterly. The declared evolution paths: extract the ingestion pipeline to its own quantum if batch load grows; replace the LLM adapter on deprecation (sacrificial by design); escalate to an EDA spine if audit volume demands it -- each a new, superseding ADR.
|
|
\end{examplebox}
|
|
|
|
Listing~\ref{lst:adr007} shows the resulting record in MADR-style form \citep{kopp2018markdown, nygard2011documenting}. Note the two properties that make it more than paperwork: the considered options carry the matrix reasoning (auditable), and the final section carries the measurement contract (falsifiable). The gateway rule that the decision relies on is subsequently fixed in its own record, ADR-011 (Listing~\ref{lst:adr}, Part~\ref{part:foundations}).
|
|
|
|
\begin{lstlisting}[language={}, caption={ADR-007 of the course project: the architecture decision as a Markdown Architecture Decision Record, ending in its measurement contract.}, label={lst:adr007}]
|
|
# ADR-007: Hexagonal modular monolith with LLM gateway
|
|
Status: accepted (2026-10-12) | supersedes: ADR-003
|
|
|
|
## Context and problem statement
|
|
The Portfolio Intelligence Platform (class C10) must deliver
|
|
grounded advisory answers with full audit logging (EU AI Act),
|
|
per-request cost control, and robustness against LLM provider
|
|
deprecation. Change rate of prompts/models is extreme; the
|
|
deterministic services (data access, portfolio computation,
|
|
audit) have classical back-office profiles.
|
|
|
|
## Decision drivers (utility-tree (H,H) leaves)
|
|
* D6 auditability: every agent step reconstructable
|
|
* D7 evolvability under model churn
|
|
* D9 testability = eval pass rate >= 95% in CI
|
|
* D10 token cost per request <= CHF 0.40 (p95)
|
|
* D12 AI integrability: queue, port, measurement point
|
|
|
|
## Considered options (matrix shortlist, Table fit-c10)
|
|
1. Hexagonal modular monolith + PF pipelines + async jobs (++)
|
|
2. Same core + full EDA backbone for jobs/audit (+)
|
|
3. Microservices per capability (o)
|
|
4. Layered monolith (-, veto D7)
|
|
|
|
## Decision
|
|
Option 1. Deterministic core as Spring-Modulith-verified
|
|
modules; all LLM access via one gateway port (adapter owns
|
|
prompts, schema validation, retries, cost telemetry);
|
|
ingestion/eval as versioned pipelines; agent workflow
|
|
orchestrated, not autonomous: agents propose, deterministic
|
|
services decide and book.
|
|
|
|
## Consequences
|
|
+ Provider deprecation = adapter task, not architecture revision
|
|
+ Single measurement point for cost, latency, audit
|
|
- Release coordination across modules (accepted, 2 teams)
|
|
- Async job spine limited; EDA escalation path documented
|
|
|
|
## Measurement contract (falsifies this ADR)
|
|
* ArchUnit/Modulith verify: 0 undeclared cross-module deps
|
|
* Static rule: no domain service imports the LLM gateway
|
|
except via the declared port (0 violations)
|
|
* p95 advisory answer < 20 s (CI gate + production SLO)
|
|
* Eval harness pass rate >= 95% on golden set;
|
|
0 ontology-violating outputs shipped
|
|
* Token cost per request <= CHF 0.40 at p95 (continual)
|
|
* Daily reconciliation booked vs. journaled: 0 discrepancies
|
|
* DORA four keys per deployable unit; review quarterly
|
|
\end{lstlisting}
|
|
|
|
% ============================================
|
|
% SECTION: THE MEASUREMENT CONTRACT
|
|
% ============================================
|
|
\section{The Measurement Contract}
|
|
\label{sec:contract}
|
|
|
|
\emph{How does a decision made this year stay honest in year five?} One case motivates the apparatus of this section. What actually triggered the Prime Video re-architecture was not an architecture review but a telemetry signal: infrastructure cost per stream, measured continuously, crossed what the team was willing to pay -- and that measurement, not an opinion, first forced and then vindicated the redesign \citep{kolny2023primevideo}. The cost dashboard was a fitness function in everything but name: an objective, continuously evaluated check on an architectural characteristic whose breach converted a running structure from ``accepted'' into ``falsified''. The empirical anchor for building such checks systematically is developed below: DORA's finding that loosely coupled architectures and teams are the strongest predictor of continuous delivery \citep{dora2017sodr, forsgren2018accelerate} -- coupling, this theory's leading dimension, is a \emph{measurable} property.
|
|
|
|
Step~(vii) generalises the observation into a concept, and it is where this course differs from a classical architecture lecture: the chosen fit is codified as a \emph{measurement contract} -- the set of executable invariants under which the architecture is allowed to keep evolving. \emph{The architecture may change freely as long as the contract stays green} \citep{ford2022evolutionary}.
|
|
|
|
\subsection{Fitness functions}
|
|
|
|
\begin{definitionbox}[Architectural fitness function]
|
|
An \emph{architectural fitness function} is ``any mechanism that provides an objective integrity assessment of some architectural characteristic'' \citep{ford2022evolutionary}. Fitness functions turn quality attributes into executable, objective checks and thereby move architecture governance from review meetings into the CI/CD pipeline. They are classified along two primary dimensions: \textbf{scope} -- \emph{atomic} (one characteristic in isolation, e.g.\ a dependency rule as a unit test) versus \emph{holistic} (combined characteristics in interplay, e.g.\ security and data freshness under load) -- and \textbf{cadence} -- \emph{triggered} (event-based, on every build or deployment), \emph{continual} (running permanently in operation, e.g.\ chaos experiments), or \emph{temporal} (time-scheduled, e.g.\ dependency-freshness time bombs).
|
|
\end{definitionbox}
|
|
|
|
Three worked instrument families recur throughout the module:
|
|
|
|
\begin{enumerate}
|
|
\item \textbf{Dependency checks as CI gates.} ArchUnit (Java; analogues: NetArchTest for .NET, dependency-cruiser for JavaScript, import-linter for Python) formulates rules such as ``the domain layer imports no framework'', ``no cycles between modules'', or ``repositories are called only by services'' as unit tests that fail the build on violation \citep{archunit2024userguide}. Spring Modulith verification does the same for module boundaries declared in a modular monolith \citep{drotbohm2023modulith}. These are atomic, triggered fitness functions -- and they are what makes the MM ratings of the capability table \emph{enforceable} rather than aspirational: without automated boundary verification, boundary erosion is the documented failure mode of the pattern.
|
|
\item \textbf{Performance and cost budgets as pipeline gates.} Latency thresholds, bundle sizes, or Lighthouse scores are declared in a budget file and gate the pipeline \citep{google2024lighthouseci, ford2022evolutionary}. The transfer to Axis~B is direct: token-cost budgets and p95 latency budgets per AI use case are the same mechanism with new units.
|
|
\item \textbf{Chaos experiments as continual holistic fitness functions.} Netflix's Chaos Monkey terminates production instances to test resilience assumptions permanently; formalised as the principles of chaos engineering \citep{basiri2016chaos}, and cited by \citet{ford2022evolutionary} as the paradigm of a continual, holistic fitness function. For the matrix, chaos experiments are the instrument that verifies the D5 cells: a claimed blast radius is a hypothesis until an instance has actually been killed under load.
|
|
\end{enumerate}
|
|
|
|
\subsection{DORA metrics: the delivery layer}
|
|
|
|
The four DORA metrics measure whether the delivery-relevant promises of a structure are being kept: \textbf{deployment frequency} and \textbf{lead time for changes} (tempo), \textbf{change failure rate} and \textbf{failed-deployment recovery time} (stability) \citep{forsgren2018accelerate, dora2023sodr}. The central empirical finding is that elite performers lead on \emph{all four} -- tempo and stability are not a trade-off. The strongest single result in the field supports coupling as the leading dimension of this entire theory: ``loosely coupled architectures and teams are the strongest predictor of continuous delivery'' -- in the 2017 analysis, the architecture characteristics testability and deployability contributed more to continuous delivery than test and deployment automation itself \citep{dora2017sodr, forsgren2018accelerate}. Two follow-on findings matter for the matrix: high performance is possible with all kinds of systems -- including mainframes -- provided systems and teams are loosely coupled (the label ``microservices'' is neither necessary nor sufficient); and as team count grows, deployments per developer per day \emph{rise} for high performers and \emph{fall} for low performers \citep{forsgren2018accelerate}.
|
|
|
|
Honesty requires the caveat, stated here and repeated in Section~\ref{sec:limits}: DORA's evidence is survey-based and analysed with structural equation models -- prediction, not experimental causal proof \citep{forsgren2018accelerate}. The theory treats it as the best available large-$n$ evidence, to be triangulated against case studies and the reader's own measurements, not as settled law.
|
|
|
|
\subsection{The four-layer measurement cascade}
|
|
|
|
The contract has four layers, forming a cascade from design time to evolution (Table~\ref{tab:cascade}). Each layer answers a different falsification question: is the structure intact (design time)? is the structure delivering (delivery)? is the structure keeping its runtime promises (operation)? is the structure ageing (evolution)?
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\small
|
|
\caption{The four-layer measurement cascade of the measurement contract: instruments and example checks per layer.}
|
|
\label{tab:cascade}
|
|
\begin{tabular}{@{}p{2.2cm}p{5.6cm}p{6.2cm}@{}}
|
|
\toprule
|
|
\textbf{Layer} & \textbf{Instruments} & \textbf{Example checks} \\
|
|
\midrule
|
|
Design time & Dependency rules as CI gates (ArchUnit, Spring Modulith verify, dependency-cruiser); coupling and cohesion metrics \citep{chidamber1994metrics, martin2003agile}; complexity gates \citep{mccabe1976complexity} & ``The domain layer imports no framework''; ``no cycles between modules''; ``no domain service calls the LLM gateway except via the declared port'' \\
|
|
\addlinespace
|
|
Delivery & The four DORA metrics \citep{forsgren2018accelerate, dora2023sodr} & Deployment frequency, lead time, change failure rate, failed-deployment recovery time -- per architecture quantum \\
|
|
\addlinespace
|
|
Operation & SLOs and error budgets; latency and \emph{cost} budgets as pipeline gates; chaos experiments as continual holistic fitness functions \citep{basiri2016chaos, ford2022evolutionary} & p95 latency budget per scenario; token-cost budget per request; blast-radius drills \\
|
|
\addlinespace
|
|
Evolution & Lehman indicators \citep{lehman1980laws}; change scatter; technical-debt inventory \citep{cunningham1992wycash, kruchten2012techdebt} & Complexity trend per module; share of features touching more than two modules; debt-register review \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
Table~\ref{tab:contract} instantiates the cascade as the reference contract for the course-project class C10 -- the concrete table that ADR-007 (Listing~\ref{lst:adr007}) points to. For AI components the contract gains one artefact of the first rank: the \emph{eval harness} -- a versioned suite of test cases, scoring logic, and statistical thresholds that runs in CI like a test suite and gates every prompt change, model update, and provider migration \citep{zheng2023judging}; Part~\ref{part:ai} develops it in full.
|
|
|
|
\begin{table}[!htbp]
|
|
\centering
|
|
\small
|
|
\caption{Reference measurement contract for the course project (application class C10): fitness functions with thresholds and cadences.}
|
|
\label{tab:contract}
|
|
\begin{tabular}{@{}p{2.6cm}p{5.0cm}p{3.4cm}p{2.6cm}@{}}
|
|
\toprule
|
|
\textbf{Concern} & \textbf{Fitness function} & \textbf{Threshold (example)} & \textbf{Cadence} \\
|
|
\midrule
|
|
Module boundaries & ArchUnit / Spring Modulith verify: no undeclared cross-module dependency \citep{archunit2024userguide, drotbohm2023modulith} & 0 violations & triggered (every build) \\
|
|
Determinism boundary & Static rule: no domain service imports the LLM gateway except via the declared port & 0 violations & triggered \\
|
|
Latency & p95 end-to-end per critical scenario & advisory answer $< 20$\,s & triggered + continual \\
|
|
Consistency & Ledger/audit reconciliation job: booked vs.\ journaled & 0 discrepancies & temporal (daily) \\
|
|
Delivery performance & DORA four keys per deployable unit \citep{forsgren2018accelerate} & e.g.\ change failure rate $< 15\,\%$; restore $< 1$ day & continual \\
|
|
Resilience & Chaos experiment: kill one instance/broker under load \citep{basiri2016chaos} & SLO holds; blast radius $\leq$ declared & temporal \\
|
|
AI correctness & Eval-harness pass rate on golden set plus domain axioms & $\geq 95\,\%$ pass; 0 ontology-violating outputs shipped & triggered (every prompt/model change) \\
|
|
AI cost & Token cost per request, per feature & $\leq$ budget (e.g.\ CHF~0.40/request at p95) & continual \\
|
|
\bottomrule
|
|
\end{tabular}
|
|
\end{table}
|
|
|
|
\subsection{The cost of change: what is flat and what is still steep}
|
|
\label{subsec:cost-of-change}
|
|
|
|
\emph{Why does the contract matter economically?} The classical answer is Boehm's cost-of-change escalation: on waterfall project data of the 1970s, fixing a problem after delivery is up to \emph{one hundred times} more expensive than fixing it during requirements and design -- with the honest qualification that for small, uncritical systems the factor is closer to 2:1 \citep{boehm1981economics, boehm2001top10}. Modern practice has empirically \emph{flattened} that curve for changes \emph{within} an architecture: the largest replication to date -- 171 projects from 2006--2014 -- found no consistent delayed-issue effect \citep{menzies2017delayed}. Version control, automated tests, and continuous delivery did exactly what the economic argument of Extreme Programming said they would \citep{beck2004xp, humble2010continuous}.
|
|
|
|
The nuance the module insists on: flattened is the curve for changes within an architecture. For changes \emph{of} the architecture -- splitting a monolith, changing the communication paradigm, moving a data-intensive flow across expensive distributed boundaries -- the curve remains steep, and the evidence is the case studies themselves: Segment's consolidation and Prime Video's rewrite were, at their core, expensive architecture revisions \citep{noonan2018goodbye, kolny2023primevideo}. This asymmetry is the economic justification of the whole apparatus: justify the fit up front (because architecture revision is the change class that still costs), and keep the architecture evolvable under a green contract (because everything else is now cheap to change). Maintenance and evolution consume roughly 40--80\,\% -- typically about 60\,\% -- of life-cycle cost, mostly for enhancement rather than repair \citep{glass2002facts}; the contract is how a structure earns the right to survive that phase.
|
|
|
|
\begin{keypoint}
|
|
The measurement contract converts an architecture decision into a standing experiment: design-time gates verify the structure, DORA metrics verify the delivery, budgets and chaos experiments verify the runtime promises, and Lehman indicators verify the ageing. The cost-of-change curve is flat inside a green contract and steep across architecture boundaries -- which is why the contract, not the diagram, is the artefact that protects the investment \citep{ford2022evolutionary, menzies2017delayed, boehm2001top10}.
|
|
\end{keypoint}
|
|
|
|
\begin{ailinse}[Fitness functions as the operating licence for AI -- both axes]
|
|
\textbf{Axis A (AI as a tool in the SDLC).} An agentic coding tool iterating against a dense test suite and CI-enforced architecture rules is \emph{contained}: every generated change must pass the same dependency rules, budgets, and evals as a human change, so the blast radius of ``almost right'' code is bounded by the contract. Without those gates, every agent change is unpriced risk -- and the empirical record shows AI adoption \emph{amplifying} existing delivery dysfunction rather than fixing it \citep{dora2025aireport}. The measurement contract is therefore the prerequisite for raising the change rate by an order of magnitude safely: fitness functions are the operating licence for agents.
|
|
|
|
\textbf{Axis B (AI as a runtime component).} The contract absorbs AI components through two new fitness-function types with old mechanics: the \emph{eval-harness pass rate} (a triggered gate on every prompt and model change, statistically thresholded \citep{zheng2023judging}) and the \emph{token-cost budget per request} (a continual gate, exactly analogous to a performance budget \citep{ford2022evolutionary}). Cost per request is a runtime quality attribute with no counterpart in classical profiles; making it a fitness function is what turns FinOps from a monthly surprise into an architectural control loop.
|
|
\end{ailinse}
|
|
|
|
\begin{projektbox}
|
|
Your project submission must ship its measurement contract, not just its architecture. Concretely, the repository must contain, wired into CI: (1) module-boundary verification with \textbf{zero violations} (ArchUnit or Spring Modulith verify, including the determinism-boundary rule: no domain service reaches the LLM gateway except via its declared port); (2) an eval harness with a versioned golden set and a \textbf{pass rate $\geq 95\,\%$} gating every prompt or model change; (3) a \textbf{token-cost budget per request} enforced as a pipeline gate and reported per feature; (4) a p95 latency budget for the advisory scenario ($< 20$\,s end-to-end); and (5) the ADR (in MADR form) whose final section \emph{is} this contract. At the project review you will be asked to demonstrate one contract violation being caught by CI -- a contract that has never failed is a contract that has never been tested.
|
|
\end{projektbox}
|
|
|
|
% ============================================
|
|
% SECTION: CONWAY AND TEAM TOPOLOGIES
|
|
% ============================================
|
|
\section{The Third Fit Dimension: Conway's Law and Team Topologies}
|
|
\label{sec:conway}
|
|
|
|
\emph{Why do correct matrix readings still fail in real organisations?} The matrix matches patterns to application classes; D11 (team scaling) has appeared throughout as one dimension among twelve. This section makes explicit why it is more than that: the organisation is a \emph{third} party to the fit, and ignoring it is the most common way correct matrix readings fail in practice.
|
|
|
|
The source is older than every pattern in the matrix. Conway observed in 1968: ``Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure'' \citep{conway1968committees} -- named ``Conway's law'' by Brooks \citep{brooks1975mythical} and empirically supported by mirroring studies of organisation and product structure \citep{maccormack2012mirroring}. The consequence for this theory is direct: every architecture decision is simultaneously a team-structure decision, whether acknowledged or not. A microservices topology assigned to a single five-person team produces a distributed monolith -- many quanta, one communication structure, the worst cells of two columns at once \citep{newman2021building}. A modular monolith assigned to thirty independent teams produces a release-coordination bottleneck that no amount of code quality repairs.
|
|
|
|
Team Topologies turns the law from a hazard into a design instrument \citep{skelton2019team}. Its four fundamental team types -- \emph{stream-aligned} teams delivering end-to-end on one value stream, \emph{platform} teams that reduce the load of stream teams, \emph{enabling} teams that build missing capabilities, and \emph{complicated-subsystem} teams that encapsulate specialist knowledge (an ML inference subsystem is the canonical course-relevant example) -- and three interaction modes (collaboration, X-as-a-service, facilitating) give the vocabulary for matching team structure to pattern choice. Two of its concepts bind directly into the matrix. First, \emph{cognitive load as a design criterion}: team and software boundaries should be cut so that no team's cognitive load exceeds its capacity -- ``team-sized software'' is an architectural yardstick, and it explains why the MS column demands stream-aligned teams with full ownership as a precondition, not an outcome \citep{skelton2019team}. Second, the \emph{inverse Conway manoeuvre}: deliberately structure the organisation to mirror the \emph{target} architecture, so that Conway's law works for the design instead of against it \citep{skelton2019team, forsgren2018accelerate}.
|
|
|
|
The empirical anchor is the DORA scaling finding already cited in Section~\ref{sec:contract}: loose coupling of \emph{architectures and teams} -- measured jointly, which is itself a Conway statement -- is the strongest predictor of continuous delivery, and it is the mechanism that lets deployments per developer per day scale linearly with team count \citep{dora2017sodr, forsgren2018accelerate}. The matrix encodes the organisational variable in D11, and the class rationales repeatedly show it deciding contested rows: the same C1 profile admits LMAX's single-threaded core and Monzo's 2{,}800 services at different organisation sizes \citep{fowler2011lmax, sewell2024monzo}; the same C5 profile splits into Shopify's modular monolith and Amazon's microservices along team count, not traffic \citep{westeinde2019deconstructing}. No twelve-dimensional profile fully captures an organisation -- Section~\ref{sec:limits} lists this as a limit -- but the rule of thumb is teachable:
|
|
|
|
\begin{keypoint}
|
|
The fit is three-way: pattern $\leftrightarrow$ application class $\leftrightarrow$ team structure. Check D11 last but veto on it first: a pattern whose team precondition is not met -- microservices without stream-aligned ownership, a monolith across too many coordinating teams -- will fail regardless of how well the other eleven dimensions match \citep{conway1968committees, skelton2019team, forsgren2018accelerate}. If the target architecture and the organisation disagree, either apply the inverse Conway manoeuvre or change the target -- Conway's law does not negotiate.
|
|
\end{keypoint}
|
|
|
|
% ============================================
|
|
% SECTION: LIMITS OF THE THEORY
|
|
% ============================================
|
|
\section{Limits of the Theory -- Applied to Itself}
|
|
\label{sec:limits}
|
|
|
|
A theory whose declared standard is that unfalsifiable claims have no place in architecture decisions must state how it can itself mislead. Six limits, stated plainly.
|
|
|
|
\begin{enumerate}
|
|
\item \textbf{Ordinal scales, no arithmetic.} The ratings support rankings and exclusions, never percentages. Any weighted-sum reading of the matrix imports the documented defects of additive multi-criteria methods over ordinal data: rank reversal \citep{belton1983shortcoming}, axiomatic conflict with utility theory \citep{dyer1990remarks}, scale misinterpretation \citep{banaecosta2008critical}, and pseudo-precision -- priorities with three decimal places derived from coarse verbal comparisons. We keep the explication discipline of multi-criteria decision analysis and drop its arithmetic pretensions. Sensitivity analysis is mandatory, not decorative; unstable rankings are findings (tradeoff points), not errors.
|
|
\item \textbf{Context-dependence of ratings.} Every capability cell encodes a \emph{typical} workload. The serverless cost cell literally inverts with load shape (Prime Video) \citep{kolny2023primevideo}, and the layered read-scalability cell inverts with cache-friendliness (Stack Overflow) \citep{craver2016stackoverflow}. Skilled teams can move individual cells -- LMAX and Monzo both did \citep{fowler2011lmax, sewell2024monzo}. A rating is a \emph{default hypothesis} to be replaced by measurement in step~(viii); the matrix predicts the default, not the exceptional.
|
|
\item \textbf{Hybrids are the normal case, not the exception.} Eight of ten class recommendations involve a core pattern plus different edge patterns (Section~\ref{sec:hybrids}). The matrix is defined over \emph{subsystems}; applying it to a whole enterprise in one stroke is a category error the theory explicitly forbids.
|
|
\item \textbf{The evidence base is heterogeneous.} The star ratings of \citet{richards2025fundamentals} are expert judgement, not measurements; DORA is survey-based prediction, not causal proof \citep{forsgren2018accelerate}; the case studies are self-reported engineering blogs with selection and framing bias -- Prime Video in particular is routinely misquoted as ``Amazon abandons microservices'' when it documents one service with a data-intensive streaming workload \citep{cockcroft2023prime}; and hexagonal and serverless carry no star ratings at all. The theory compensates by triangulation -- ratings against cases against metrics -- and by the measurement contract, which converts every adopted claim into a testable one.
|
|
\item \textbf{The organisation is a hidden variable.} Conway's law makes every architecture decision a team-structure decision \citep{conway1968committees, skelton2019team}; the same requirements profile admits opposite optimal patterns at different organisation sizes (LMAX versus Monzo; Shopify versus Amazon). D11 partially captures this; no twelve-dimensional profile fully does (Section~\ref{sec:conway}).
|
|
\item \textbf{AI-era volatility.} The D12 ratings encode the 2025/26 state of a field whose tools deprecate in months \citep{openai2026deprecations}. The \emph{method} -- Assumption~A6: scenarios, tactics, trade-off analysis, ADRs, fitness functions -- is the stable part; the specific cells are perishable and carry, in effect, their own temporal fitness function: re-verify on every model generation. Lehman's laws apply to theories too \citep{lehman1980laws}.
|
|
\end{enumerate}
|
|
|
|
\begin{hinweisbox}
|
|
A student who cites the matrix as an \emph{authority} rather than as a \emph{hypothesis} has misunderstood the module. The matrix cannot tell you what to build; it can only force your criteria, weights, and assumptions into the open, pre-filter the candidates, and hand the contested cells to scenario-based analysis. Its numbers are ordinal, its ratings are context-typical defaults, its evidence is triangulated but partly survey-based and partly self-reported -- and it decays: every cell is a claim awaiting your measurement. The canonical exercise in this scepticism is reading contradictory study designs against each other (the METR-versus-Copilot contradiction of Part~\ref{part:ai} \citep{becker2025metr, peng2023copilot}); the assessment of this module tests the discipline, not the memorisation of the grid.
|
|
\end{hinweisbox}
|
|
|
|
\begin{keypoint}
|
|
\textbf{Maxim 9.} The matrix is the argument's skeleton, ATAM is its court of appeal, the ADR is its record, and the fitness function is its parole condition. The matrix, in short, is the lecture-hall form of a discipline whose engineering form is: scenarios with numbers, ATAM for the contested cells, ADRs for the decisions, fitness functions for the lifetime.
|
|
\end{keypoint}
|
|
|
|
\begin{thinkbox}
|
|
Limit~4 says the evidence base is heterogeneous, and limit~2 says skilled teams can move cells. Suppose your team measures, over a year, that its microservices system beats every prediction of the MS column for its class. Has the theory been falsified, or has your measurement contract done exactly what step~(viii) designed it to do? What would have to be true of your \emph{next} project for the difference to matter?
|
|
\end{thinkbox}
|