<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Independent Variation Principle</title>
<link>https://yannickloth.github.io/independentvariation/blog.html</link>
<atom:link href="https://yannickloth.github.io/independentvariation/blog.xml" rel="self" type="application/rss+xml"/>
<description></description>
<generator>quarto-1.10.19</generator>
<lastBuildDate>Sun, 18 Oct 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>The Right Axis Is Not Style: A Response to Fritzsche and Amariles</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-10-18-the-right-axis-is-not-style-a-response-to-fritzsche-and-amariles-8k3p.html</link>
  <description><![CDATA[ 





<p>Two recent posts disagree about Clean Architecture, and the disagreement is instructive: it is an argument about the wrong axis.</p>
<p>Rico Fritzsche’s <a href="https://ricofritzsche.me/why-are-we-still-talking-about-clean-architecture/">“Why Are We Still Talking About Clean Architecture?”</a> argues to retire the layered family in favor of a Functional Core / Imperative Shell split. <a href="https://www.linkedin.com/pulse/why-clean-architecture-functional-core-imperative-rom%C3%A1n-amariles-djcwe">David Román Amariles replies</a> that the two are not mutually exclusive: separating business rules from side effects and controlling the direction of dependencies address different concerns, and a system can have both.</p>
<p>Both arguments hold within their scope, and the scope is what neither argument states. The tool that supplies it is the change-driver structure of the domain. Once it is on the table, the question stops being which style wins and becomes which case the domain is in.</p>
<hr>
<section id="the-formal-apparatus-briefly" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-formal-apparatus-briefly"><span class="header-section-number">1</span> The formal apparatus, briefly</h2>
<p>The Independent Variation Principle (IVP) governs one thing: where elements belong. Given the element set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>E</mi><annotation encoding="application/x-tex">E</annotation></semantics></math> and the change-driver assignment <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e)</annotation></semantics></math> — the set of change drivers whose state changes create a modification requirement for element <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>e</mi><annotation encoding="application/x-tex">e</annotation></semantics></math> — the principle is the conjunction of four conditions <span class="citation" data-cites="loth2026ivpgraph">[1]</span>:</p>
<ol type="1">
<li><strong>Admissibility</strong> — every element has at least one change driver: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>e</mi><mo>∈</mo><mi>E</mi><mo>,</mo><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>≥</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\forall e \in E,\ |\Gamma(e)| \geq 1</annotation></semantics></math>.</li>
<li><strong>Element Form</strong> — every element is either pure (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">|\Gamma(e)| = 1</annotation></semantics></math>) or irreducibly composite: no proper subset of its driver set can achieve its purpose, and no decomposition into sub-elements with strictly smaller driver sets jointly preserves that purpose.</li>
<li><strong>Separation</strong> — elements assigned different sets of change drivers reside in different modules: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>⇒</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e_1) \neq \Gamma(e_2) \Rightarrow M(e_1) \neq M(e_2)</annotation></semantics></math>.</li>
<li><strong>Unification</strong> — elements assigned the same set of change drivers reside in the same module: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>⇒</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e_1) = \Gamma(e_2) \Rightarrow M(e_1) = M(e_2)</annotation></semantics></math>.</li>
</ol>
<p>The modules of a compliant system are the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalence classes of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>E</mi><annotation encoding="application/x-tex">E</annotation></semantics></math>. Separation and Unification are the partition content: failing Separation is <strong>contamination</strong> (elements driven by different conditions co-reside), and failing Unification is <strong>scatter</strong> (elements that change together are split across modules).</p>
<p>A <strong>change driver</strong> is an exogenous forcing condition whose change creates a requirement for governed elements to change — a condition anchored in a regulation, a contract, an interface specification, or another domain artifact whose authority is external to the system. Drivers are discovered, not chosen.</p>
<p>Note what the four conditions leave out: purity of functions, ports, adapters, or dependency direction. Those are shapes the partition takes in particular domains. They are not the principle.</p>
<hr>
</section>
<section id="where-amariles-argument-holds-the-two-concerns-are-independent" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="where-amariles-argument-holds-the-two-concerns-are-independent"><span class="header-section-number">2</span> Where Amariles’ argument holds: the two concerns are independent</h2>
<p>His clearest point is structural, not rhetorical. Moving business rules into a pure function and directing dependencies through an abstraction are two decisions, and nothing forces a choice between them:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode csharp code-with-copy"><code class="sourceCode cs"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">static</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> EvaluateBooking</span>
<span id="cb1-2"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">static</span> BookingResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Execute</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span id="cb1-4">        BookingRequest request<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-5">        BookingContext context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-6">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-7">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Business rules</span></span>
<span id="cb1-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>The service retrieves the data, builds the context, and calls the function. The rules are pure; the orchestration stays in the service; the service can depend on <code>IBookingRepository</code> rather than on PostgreSQL. All three hold at once.</p>
<p>The four conditions account for this. <code>EvaluateBooking</code> and <code>IBookingRepository</code> have different driver sets, so Separation puts them in different modules. The rules inside <code>EvaluateBooking</code> share one driver set, so Unification keeps them together. Nothing in the partition requires a pure function or a port; those are the shapes the partition takes here. The example describes what the partition looks like in this domain. It is not a competing architectural claim.</p>
<p>A second observation in the same section is easy to miss. It quotes Fritzsche’s conclusion —</p>
<blockquote class="blockquote">
<p>What we need are clearly defined business responsibilities and control over consistency within their contextual boundaries. Dependency inversion, ports, and adapters do not provide us with these properties.</p>
</blockquote>
<p>— and observes that these are different concerns that can complement each other. So they are. Dependency direction is a decision about <em>which way a reference points</em>. The location of business responsibility is a decision about <em>what belongs together</em>. Nothing about the first settles the second, or the reverse.</p>
<hr>
</section>
<section id="where-fritzsches-argument-holds-the-port-does-not-remove-the-dependency" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="where-fritzsches-argument-holds-the-port-does-not-remove-the-dependency"><span class="header-section-number">3</span> Where Fritzsche’s argument holds: the port does not remove the dependency</h2>
<p>His point is narrower than a rejection of abstraction. It is that inverting a dependency changes its direction in the source and does nothing else:</p>
<blockquote class="blockquote">
<p>Dependency inversion makes it possible to reverse source code dependencies… However, the functional dependencies remain.</p>
</blockquote>
<p>That is the placement result. A change driver is external and fixed by the domain. No design move adds, removes, or transmutes one. The service still needs the reservation data before it can apply its rules — whether the call passes through a database driver, an adapter, or an interface.</p>
<p>Amariles’ own examples show the same placement at work. The PS5 port in his game example does not eliminate the need to persist progress. It moves that need behind a boundary, and the gameplay code stops naming the mechanism. That is a real and practical benefit, and it is a benefit of <em>placement</em>: the correct implementation of the persistence obligation now sits somewhere the gameplay code need not know about. The obligation itself has not moved.</p>
<p>His .NET example shows the same thing. <code>EvaluateBooking.Execute</code> is pure; the repository call is not. The function is pure because the external call was moved out of it, not because the architecture made it so.</p>
<hr>
</section>
<section id="the-axis-nobody-is-using" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="the-axis-nobody-is-using"><span class="header-section-number">4</span> The axis nobody is using</h2>
<p>Here is where the argument stalls, and it is the same stall on both sides.</p>
<p>Fritzsche’s case against dependency inversion is an observation: “how often have I seen someone come up with the idea of replacing the database technology in an existing application? Exactly zero times!”</p>
<p>Amariles answers with a counterexample: the game that must run where its SQLite binary is unavailable.</p>
<p>Both moves are about how often substitution happens. The observation that database substitution is rare is domain-bound, and the game is a fair counterexample to it. But substituting one frequency claim for another does not settle the question, because frequency is not the criterion. Whether an element’s correctness conditions require knowledge of the infrastructure it depends on is a structural fact about the domain’s governing artifacts, and it holds whether or not the substitution ever occurs <span class="citation" data-cites="loth2026couplingnature">[2]</span>.</p>
<p>The structural fact is a condition. Write <strong>H</strong> for Knowledge Independence: no domain change-driver has correctness conditions that require knowledge of an infrastructure system. Write <strong>H0</strong> for Behavioural Self-Containment: the module computes every required change from its own inputs, with no dependence on external state at all. H0 implies H, and not conversely — a module can read external <em>domain</em> state, such as a customer’s recorded credit history, while remaining entirely ignorant of infrastructure. Two conditions that can fail independently give three cases:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>Case</th>
<th>Condition</th>
<th>What the core can be</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>(a)</td>
<td>H0 holds</td>
<td>A pure functional core — no repository, port, or adapter</td>
</tr>
<tr class="even">
<td>(b)</td>
<td>H holds, H0 fails</td>
<td>A core behind a port expressed in domain vocabulary</td>
</tr>
<tr class="odd">
<td>(c)</td>
<td>H fails</td>
<td>No infra-ignorant core; the knowledge must live somewhere</td>
</tr>
</tbody>
</table>
<p>Both posts reason inside case (a), where a pure functional core is available. Fritzsche’s pure function is case (a) exactly. Amariles’ port is the correct answer in case (b), and his objection that the two coexist is the observation that one system can contain modules in different cases. Neither post reaches case (c), where the question is not which style to use but whether the knowledge can be excluded at all.</p>
<section id="what-case-c-looks-like" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="what-case-c-looks-like"><span class="header-section-number">4.1</span> What case (c) looks like</h3>
<p>H fails in two ways, and neither is a modelling mistake.</p>
<p><strong>Direct.</strong> A governing artifact states a correctness condition in terms of infrastructure behaviour. “A patient record must be retrievable within 500 ms under peak load” is a change driver anchored in a medical-device regulation. Its correctness condition is a statement about storage and indexing performance. No implementation ignorant of storage semantics satisfies it.</p>
<p><strong>Indirect.</strong> A domain rule’s correctness depends on the outcome of an infrastructure process. A credit rule says: “approve an order only if the customer’s outstanding balance, including committed but not yet settled orders, stays within the credit limit.” “Committed but not yet settled” refers to persistence state under concurrent write. Two storage architectures with different isolation levels produce different answer sets for the same underlying events, and therefore different approval outcomes. The domain rule’s correctness is functionally determined by the storage layer’s guarantee.</p>
<p>Fritzsche’s own observation points at the indirect case. He writes: “Query capabilities, transaction behaviour, and consistency guarantees are largely determined by the database used.” When a domain rule’s correctness condition depends on those guarantees, the database is not a detail. It is part of the domain’s causal structure.</p>
<p>When H fails, no reformulation of the domain removes the required knowledge while preserving correctness. The infra-ignorant core is not hard to reach. It is impossible. Enforcing it produces either an incorrect implementation or an abstraction that quietly models a different, simpler domain.</p>
<hr>
</section>
</section>
<section id="the-stability-ordering-what-sets-the-direction" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-stability-ordering-what-sets-the-direction"><span class="header-section-number">5</span> The stability ordering: what sets the direction</h2>
<p>“Clean Architecture is fundamentally concerned with the direction of dependencies” is the style’s own account, and it is worth reading closely, because the direction is not arbitrary — it is fixed by a <strong>stability ordering</strong>.</p>
<p>Clean Architecture’s Dependency Rule points dependencies toward more stable elements. Martin measures stability with two structural metrics: instability <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mo>=</mo><msub><mi>C</mi><mi>e</mi></msub><mi>/</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>C</mi><mi>a</mi></msub><mo>+</mo><msub><mi>C</mi><mi>e</mi></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">I = C_e/(C_a + C_e)</annotation></semantics></math>, the ratio of efferent to total coupling, and abstractness <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>, the fraction of abstract types. The Main Sequence <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>+</mo><mi>I</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">A + I = 1</annotation></semantics></math> is the claimed optimal locus <span class="citation" data-cites="martin2017clean">[3]</span>.</p>
<p>Neither metric references a change driver. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math> counts packages in the import graph; <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math> counts abstract type declarations. They measure structural self-containment — an element is “stable” because nothing imports force it to change — not change-driver identity. The stability ordering is therefore a proxy for the change-driver structure, not a measurement of it.</p>
<p>The proxy is useful where it tracks the domain’s actual ordering, and the theory has a name for the ordering it tracks. A <strong>driver stability ordering</strong> is a partial order on change drivers, where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>γ</mi><mn>1</mn></msub><mo>≻</mo><msub><mi>γ</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\gamma_1 \succ \gamma_2</annotation></semantics></math> holds when <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>γ</mi><mn>1</mn></msub><annotation encoding="application/x-tex">\gamma_1</annotation></semantics></math> activates less often and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>γ</mi><mn>2</mn></msub><annotation encoding="application/x-tex">\gamma_2</annotation></semantics></math>’s requirements are chosen to satisfy decisions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>γ</mi><mn>1</mn></msub><annotation encoding="application/x-tex">\gamma_1</annotation></semantics></math> governs. Read on this ordering, dependency inversion says that elements governed by the volatile driver depend on elements governed by the stable one, rather than the reverse.</p>
<p>That is the strongest defensible reading of Amariles’ position, and on this ordering it is a real result rather than a proxy — provided the ordering holds. It holds for tax law and a payment gateway. It fails where a domain rule’s correctness depends on what the storage layer guarantees; there, the stable element is the infrastructure behaviour, because the domain rule’s correctness now depends on its outcome. The dependency should then point the other way, and the style’s blanket inward rule asserts a direction the domain does not have.</p>
<p>Two constraints guard this reading, and both bear on the exchange. First, the ordering is a property of the domain’s causal structure, not a rank intrinsic to a driver: stability is one of the two relations in the pair, and it never licenses calling any driver “primary,” “dominant,” or “main.” Second, it informs the direction decision only — it does not change which elements belong in which module, which is the partition’s job. Direction and partition are separate questions, and the two get conflated when the exchange is read as a disagreement about styles rather than about which question is being asked.</p>
<hr>
</section>
<section id="what-the-theory-confirms-in-each" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="what-the-theory-confirms-in-each"><span class="header-section-number">6</span> What the theory confirms in each</h2>
<p>Read against the three cases, the exchange resolves into scope conditions rather than verdicts.</p>
<p><strong>The two approaches operate on different questions.</strong> Purity is a property of an element’s driver set (case (a)); a port is the shape a module takes when it needs external domain state (case (b)); dependency direction is a separate decision, governed by the stability ordering where that ordering holds. Nothing in the theory requires choosing one, which is the substance of Amariles’ argument.</p>
<p><strong>The port relocates a need; it does not delete one.</strong> “The functional dependencies remain” holds in every case. It is <em>decisive</em> only in case (c). In cases (a) and (b) the family’s prescriptions match what the domain calls for, and a pure functional core is a restatement of case (a). The scope of the conclusion is narrower than the argument’s reach.</p>
<p><strong>Both arguments rest on frequency.</strong> Fritzsche observes that database substitutions are rare; Amariles answers that other domains differ. Both observations may be accurate. Neither is the criterion. The criterion is whether the domain’s governing artifacts place infrastructure knowledge in a module’s correctness conditions — a fact about the domain, not about substitution rates.</p>
<p><strong>Case (c) appears in neither.</strong> Which is where the discussion has real consequences. A conclusion that the style is wrong understates the domain’s latitude; a conclusion that the styles coexist leaves the reader without the case where no style applies.</p>
<hr>
</section>
<section id="what-to-do-instead" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="what-to-do-instead"><span class="header-section-number">7</span> What to do instead</h2>
<p>The question “Clean Architecture or Functional Core / Imperative Shell?” sets the axis on style. The right axis is the domain’s change-driver structure, which the style does not select.</p>
<p>It is, for each module, two questions answered from the domain’s governing artifacts:</p>
<ol type="1">
<li>Does any correctness condition require knowledge of an infrastructure system? (This decides H.)</li>
<li>Does the module depend on any external state at all? (This decides H0.)</li>
</ol>
<p>Then:</p>
<ul>
<li><strong>Case (a), H0.</strong> A pure functional core. No repository, port, or adapter. Adding one is unnecessary indirection. This is what Functional Core / Imperative Shell describes.</li>
<li><strong>Case (b), H holds.</strong> A port or repository expressed in domain vocabulary. The module needs external state, but the state is domain-governed, so the contract is expressible in domain terms. This is the case the hexagonal prescription was designed for.</li>
<li><strong>Case (c), H fails.</strong> Accommodate the infrastructure knowledge. Either keep it in the domain module, or move it to an explicitly domain-scoped adapter whose change-driver assignment is stated and whose behaviour is independently testable against the domain change-driver. What is not sound is enforcing infra-ignorance and accepting an incorrect or unverifiable model as the cost of structural conformance.</li>
</ul>
<p>The style does not choose the case. The domain does.</p>
<hr>
</section>
<section id="wrapping-up" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="wrapping-up"><span class="header-section-number">8</span> Wrapping up</h2>
<p>The theory confirms both observations under their scope. Dependency inversion moves a dependency without removing the driver behind it. Direction and separation are independent concerns that a system can satisfy at once.</p>
<p>The qualification worth adding is one of scope. The infra-ignorant core exists if and only if H holds, and H is discovered from the domain’s governing artifacts, not assumed. When H fails, every style in the family — Clean, Hexagonal, Onion, and Functional Core / Imperative Shell alike — arrives at the same fork: embody the required knowledge, or ship a model that cannot satisfy its obligations.</p>
<p>The two posts are not in conflict. They are answering different halves of a question that has three answers, and neither half needs the other retired.</p>
<hr>
<p><strong>The formal development.</strong> The definitions, theorems, and proofs behind this page are published in:</p>
<ul>
<li><em>The Independent Variation Principle: Deriving Optimal Module Boundaries from the Element–Change-Driver Graph</em> — Zenodo, 2026 — <a href="https://doi.org/10.5281/zenodo.20794332">doi:10.5281/zenodo.20794332</a></li>
<li><em>On the Nature of Coupling: All Coupling as Shared Resource Access</em> — Zenodo, 2026 — <a href="https://doi.org/10.5281/zenodo.21925122">doi:10.5281/zenodo.21925122</a></li>
</ul>
<p>The conditional analysis of the infra-ignorant core is developed in <em>The Domain–Infrastructure Boundary as a Structural Property of the Driver Set</em>.</p>
<p><a href="../reference/papers.html">All published papers</a></p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body" data-entry-spacing="0">
<div id="ref-loth2026ivpgraph" class="csl-entry">
<div class="csl-left-margin">[1] </div><div class="csl-right-inline">Y. Loth, <span>“The independent variation principle.”</span> Zenodo, Jun. 2026. doi: <a href="https://doi.org/10.5281/zenodo.20794332">10.5281/zenodo.20794332</a>.</div>
</div>
<div id="ref-loth2026couplingnature" class="csl-entry">
<div class="csl-left-margin">[2] </div><div class="csl-right-inline">Y. Loth, <span>“On the nature of coupling: All coupling as shared resource access.”</span> Zenodo, Aug. 2026. doi: <a href="https://doi.org/10.5281/zenodo.21925122">10.5281/zenodo.21925122</a>.</div>
</div>
<div id="ref-martin2017clean" class="csl-entry">
<div class="csl-left-margin">[3] </div><div class="csl-right-inline">R. C. Martin, <em>Clean architecture: A craftsman’s guide to software structure and design</em>. Prentice Hall, 2017.</div>
</div>
</div></section></div> ]]></description>
  <category>ivp</category>
  <category>engineering</category>
  <category>architecture</category>
  <category>coupling</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-10-18-the-right-axis-is-not-style-a-response-to-fritzsche-and-amariles-8k3p.html</guid>
  <pubDate>Sun, 18 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Inheritance vs Composition: What the Independent Variation Principle Actually Tells Us</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-08-27-inheritance-vs-composition.html</link>
  <description><![CDATA[ 





<p>“Favor composition over inheritance” is one of the most cited design guidelines in software engineering. It is tempting to read this as a rule IVP prescribes. It is not.</p>
<p>The <strong>Independent Variation Principle (IVP)</strong> is precise about what it governs and what it leaves open. This post uses a payment-processing example to show what IVP actually tells us about inheritance and composition — and, just as importantly, what it does not.</p>
<section id="what-ivp-governs-and-what-it-does-not" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="what-ivp-governs-and-what-it-does-not"><span class="header-section-number">1</span> What IVP governs — and what it does not</h2>
<p>IVP’s normative content is a <strong>module partition</strong>, not a mechanism choice <span class="citation" data-cites="loth2026ivpgraph">[1]</span>. Given a system’s elements <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>E</mi><annotation encoding="application/x-tex">E</annotation></semantics></math> and its set of change drivers <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>, IVP assigns each element <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>e</mi><annotation encoding="application/x-tex">e</annotation></semantics></math> a <em>set</em> of change drivers <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e)</annotation></semantics></math> — the change drivers whose state changes create a modification requirement for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>e</mi><annotation encoding="application/x-tex">e</annotation></semantics></math> — and prescribes, in its structural formulation <span class="citation" data-cites="loth2026ivpgraph">[1]</span>:</p>
<ol type="1">
<li><strong>Admissibility</strong> — every element has at least one change driver: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>∀</mo><mi>e</mi><mo>∈</mo><mi>E</mi><mo>,</mo><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>≥</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\forall e \in E,\ |\Gamma(e)| \geq 1</annotation></semantics></math>.</li>
<li><strong>Element Form</strong> — every element is either pure (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">|\Gamma(e)| = 1</annotation></semantics></math>) or irreducibly composite: no proper subset of its driver set can achieve its purpose, and no decomposition into sub-elements with strictly smaller driver sets jointly preserves that purpose.</li>
<li><strong>Separation</strong> — elements assigned different sets of change drivers reside in different modules: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>⇒</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e_1) \neq \Gamma(e_2) \Rightarrow M(e_1) \neq M(e_2)</annotation></semantics></math>.</li>
<li><strong>Unification</strong> — elements assigned the same set of change drivers reside in the same module: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>⇒</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>M</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e_1) = \Gamma(e_2) \Rightarrow M(e_1) = M(e_2)</annotation></semantics></math>.</li>
</ol>
<p>Equivalently, the modules of an IVP-compliant system are the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalence classes of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>E</mi><annotation encoding="application/x-tex">E</annotation></semantics></math> <span class="citation" data-cites="loth2026ivpgraph">[1]</span>. The first two clauses are the ones the composition-vs-inheritance discussion must not skip. <em>Admissibility</em> says every element answers to some change driver. <em>Element Form</em> ties the assignment to purpose and to the domain knowledge the element embodies: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>e</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e)</annotation></semantics></math> is not an arbitrary label — <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>e</mi><annotation encoding="application/x-tex">e</annotation></semantics></math> embodies the knowledge governed by its drivers, so the assignment is grounded in what the element exists to realize <span class="citation" data-cites="loth2026cohesion">[2]</span>. Separation and Unification then say how those grounded assignments group elements into modules.</p>
<p>Inheritance and composition are both such mechanisms. The theory treats inheritance — <code>class B extends A</code> — as a <strong>structural dependency</strong>: a relation observable directly in the artifact, like a function call or an import. IVP does not have a “composition directive” and an “inheritance directive.” What it does have is a coupling criterion, and that is where the real guidance lies.</p>
</section>
<section id="what-ivp-mandates-its-own-minimal-coupling" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-ivp-mandates-its-own-minimal-coupling"><span class="header-section-number">2</span> What IVP mandates: its own minimal coupling</h2>
<p>IVP’s coupling criterion follows from its rule <span class="citation" data-cites="loth2026ivpgraph">[1]</span>. The partition induced by <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalence is fixed by the change drivers; the coupling that survives a compliant partition is <strong>IVP’s minimal coupling</strong> — the necessary coupling: essential same-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> coupling inside a module, plus the essential cross-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> coupling between modules that is the irreducible cost of communication between <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-classes.</p>
<p>One thing IVP’s minimal coupling forbids:</p>
<ul>
<li><strong>Accidental coupling</strong> — coupling not required by any domain artifact. Two elements are coupled when one depends on something the other defines or maintains; that dependency is <strong>essential</strong> when a domain artifact (a statute, contract, standard, specification) requires it, and <strong>accidental</strong> when no domain artifact mandates it — a framework convention, a language limitation, a deployment detail.</li>
</ul>
<p>The accidental coupling IVP is most concerned with is <strong>cross-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> accidental coupling</strong> — accidental coupling that connects elements assigned different sets of change drivers.</p>
<p>IVP also leaves no room for accidental coupling between elements that should be apart. If two elements with <em>different</em> change-driver sets sit in the same module and are accidentally coupled, the module is impure: the partition has co-located elements that Separation would keep in different modules, and the system does not faithfully embody the domain’s change structure <span class="citation" data-cites="loth2026ivpgraph">[1]</span>. IVP’s Separation directive eliminates this case by construction — cross-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> elements are never co-located in a compliant partition. The only accidental coupling that can remain inside a module is the same-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> kind — a concrete reference where an abstraction would do — and that is a code-quality defect, not a failure to embody the domain.</p>
<p>Because the coupling verdict is relative to the chosen rule, it is not a property of the code in the abstract — it is a property of the code <em>under a given partition</em>. IVP’s verdict is IVP’s because IVP picks <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalence as its modularization rule. A different rule would classify the same dependencies differently.</p>
</section>
<section id="the-payment-example-what-ivp-diagnoses" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-payment-example-what-ivp-diagnoses"><span class="header-section-number">3</span> The payment example: what IVP diagnoses</h2>
<p>Consider a payment-processing system designed with an inheritance hierarchy:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Payment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Infrastructure methods</span></span>
<span id="cb1-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logTransaction</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> details<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectFraud</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sendNotification</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-6"></span>
<span id="cb1-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Template method pattern</span></span>
<span id="cb1-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-9">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-10">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectFraud</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-11">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-12">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logTransaction</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment processed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-13">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sendNotification</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-14">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-15"></span>
<span id="cb1-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-17">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-18"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-19"></span>
<span id="cb1-20"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> CreditCardPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Payment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-21">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* credit card validation */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* credit card processing */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-23"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-24"></span>
<span id="cb1-25"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PayPalPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Payment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-26">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* PayPal validation */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-27">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* PayPal processing */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-28"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>IVP’s diagnosis of this structure is specific. Two different change drivers are at work:</p>
<ul>
<li><strong>Payment-method variety</strong> — the set of accepted payment methods (credit card, PayPal, crypto, bank transfer) varies as new providers, fee structures, and regulations emerge.</li>
<li><strong>Payment infrastructure</strong> — logging, fraud detection, and notification vary with performance, security, and observability demands.</li>
</ul>
<p>These are not the same change driver. Under the interpretive claim that these two forcing conditions vary independently, IVP assigns <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">CreditCardPayment</mtext><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">infrastructure</mtext><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(\text{CreditCardPayment}) \neq \Gamma(\text{infrastructure})</annotation></semantics></math> — the payment-method element’s change-driver set differs from the infrastructure’s. A compliant partition therefore puts them in <strong>different modules</strong>.</p>
<p>Now the mechanism matters. <code>class CreditCardPayment extends Payment</code> does not merely reuse code. It makes the subclass embody the base class’s knowledge: everything <code>Payment</code> references — the logging, fraud-detection, and notification services — becomes knowledge the subclass carries with it. That is the crux. Those knowledge pieces are <strong>not part of the payment-method’s causal domain knowledge</strong>. The payment-method domain does not require the element that validates a card and settles a charge to also embody how transactions are logged, fraud is screened, or notifications are sent. By inheriting them, <code>CreditCardPayment</code> embodies knowledge its causal domain does not mandate — <strong>accidental embodiment</strong> — and that embodiment drags with it coupling to infrastructure the domain never required it to share.</p>
<p>That coupling connects elements assigned different sets of change drivers and is required by no domain artifact — it is <strong>cross-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> accidental coupling</strong>, which IVP’s minimal coupling forbids. This is the precise defect IVP identifies in the inheritance hierarchy. The verdict is not “you used inheritance” — it is “this mechanism made the element embody knowledge outside its causal domain, and that accidental embodiment became accidental coupling.”</p>
<p>A mechanism choice is therefore a faithfulness check on domain knowledge. When the domain already dictates that payment-method knowledge and infrastructure knowledge are separate bodies of causal knowledge, the correct structure is derived directly from that structure: separate elements in separate modules. Inheritance that blurs the boundary adds nothing the domain had not already decided. If you cannot tell whether the <code>extends</code> coupling is domain-required, you have not found that inheritance is wrong — you have found that your causal domain knowledge is incomplete.</p>
</section>
<section id="why-composition-avoids-that-specific-defect" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="why-composition-avoids-that-specific-defect"><span class="header-section-number">4</span> Why composition avoids that specific defect</h2>
<p>The composition version:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentMethod <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-3">    PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-5"></span>
<span id="cb2-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> CreditCardPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> PaymentMethod <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-7">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* credit card validation */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* credit card processing */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-10"></span>
<span id="cb2-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> FraudDetector <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">analyze</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PaymentMethod m<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> TransactionLogger <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> d<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> NotificationService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> m<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-14"></span>
<span id="cb2-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> FraudDetector fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-17">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> TransactionLogger logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-18">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> NotificationService notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-19"></span>
<span id="cb2-20">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentProcessor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>FraudDetector f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> TransactionLogger l<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> NotificationService n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-21">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fraudDetector</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logger</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> l<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">notifier</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-22">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-23"></span>
<span id="cb2-24">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PaymentMethod method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-25">        method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">analyze</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-27">            PaymentResult r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-28">            logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment processed: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-29">            notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment confirmation"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-30">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-31">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-32"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Here <code>CreditCardPayment</code> couples to the infrastructure <em>only where the domain requires it</em>. The <code>PaymentProcessor</code> composes the two variation domains — but the payment-method element and the infrastructure services are separate elements, coupled through interfaces only where a genuine causal dependency exists. Nothing forces the payment-method class to absorb the infrastructure’s dependency footprint.</p>
<p>The point is not that composition is magic. The point is narrower: <strong>composition lets the developer form the coupling at the points the domain mandates, whereas inheritance’s <code>extends</code> edge couples the subclass to the base’s whole dependency footprint transitively, mandated or not.</strong> IVP does not endorse composition — it diagnoses the coupling a mechanism actually produces against its <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-partition.</p>
</section>
<section id="what-ivp-does-not-say" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="what-ivp-does-not-say"><span class="header-section-number">5</span> What IVP does <em>not</em> say</h2>
<p>IVP does <strong>not</strong> endorse “prefer composition over inheritance” as a universal rule. Three specific caveats:</p>
<p><strong>Inheritance is not forbidden.</strong> Where the two sides genuinely share the same change driver — so IVP assigns them the same <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> and the same module — the coupling inheritance creates is <em>essential</em>, not accidental, and IVP is satisfied. The composition example itself uses this: <code>CreditCardPayment</code> and <code>PayPalPayment</code> <em>implement</em> <code>PaymentMethod</code>, an “is-a” relationship to an abstraction that genuinely shares the payment-method change driver. That inheritance is IVP-compliant. What the example removes is inheritance <em>across</em> the two change drivers — subclassing a base that pulls in infrastructure the payment-method domain does not mandate. A geometric-shape hierarchy is IVP-compliant if all its elements are <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalent, so that every change modifying one also creates a modification requirement for the others. A framework’s intentional extension points are IVP-compliant only when the extension and the base are same-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>; a low activation frequency does not by itself make them compliant. The defect is coupling <em>different</em> change drivers, not using inheritance.</p>
<p><strong>Composition can violate IVP too.</strong> Composition that couples elements assigned different sets of change drivers across a module boundary is just as much cross-<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> accidental coupling. Mechanism alone does not determine compliance; the change-driver assignment <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math> does.</p>
<p><strong>The verdict is rule-relative.</strong> “The hierarchy couples independent change drivers” is an <em>IVP-specific</em> diagnosis. It follows from choosing <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equivalence as the modularization rule. Another rule would partition the elements differently and classify the same edges differently. IVP’s answer is the answer <em>given its choice of rule</em>, not a mechanism-independent fact.</p>
</section>
<section id="the-takeaway" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="the-takeaway"><span class="header-section-number">6</span> The takeaway</h2>
<p>IVP does not tell you to reach for composition and avoid inheritance. It tells you something more useful: <strong>start with the domain.</strong> Ask what the domain actually prescribes: what are the change drivers, and what does each element’s specification require it to embody and depend on? The change drivers determine the partition; then couple elements only where the domain requires the dependency, and never make an element embody knowledge its causal domain does not mandate. When you evaluate a design, ask not “inheritance or composition?” but “what does the structure of the causal domain knowledge dictate, and does this mechanism add coupling the domain never had?”</p>
<p>In the payment example, inheritance happens to manufacture accidental embodiment and cross-driver accidental coupling — through the knowledge the <code>extends</code> edge forces the subclass to carry — and composition happens to avoid it. That is why the classical guideline <em>points the right way in this example</em>. But IVP explains the <em>reason</em>: the best structure is derived directly from the structure of the causal domain knowledge, and the mechanism is faithful exactly when it adds no coupling the domain did not already decide.</p>
<hr>
</section>
<section id="learn-more" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">7</span> Learn More</h2>
<p>IVP formalizes the module partition a system’s change drivers prescribe and the coupling a compliant partition tolerates — giving a precise, decidable answer where classical heuristics rely on intuition. The formal development — the module partition and the coupling-floor argument — is proved in the paper on the Independent Variation Principle <span class="citation" data-cites="loth2026ivpgraph">[1]</span>, with the change-driver partition and purity/completeness accounted for in Causal Cohesion <span class="citation" data-cites="loth2026causal">[3]</span> and the cohesion-as-correctness framework in On the Nature of Cohesion <span class="citation" data-cites="loth2026cohesion">[2]</span>.</p>
<p>This site’s overview sections — IVP (software) and Software design — present the theory and its applications in more depth, and the <a href="../software/design/languages/index.html">language coupling analysis</a> applies the coupling lens across 65 programming languages.</p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body" data-entry-spacing="0">
<div id="ref-loth2026ivpgraph" class="csl-entry">
<div class="csl-left-margin">[1] </div><div class="csl-right-inline">Y. Loth, <span>“The independent variation principle.”</span> Zenodo, Jun. 2026. doi: <a href="https://doi.org/10.5281/zenodo.20794332">10.5281/zenodo.20794332</a>.</div>
</div>
<div id="ref-loth2026cohesion" class="csl-entry">
<div class="csl-left-margin">[2] </div><div class="csl-right-inline">Y. Loth, <span>“On the nature of cohesion: Cohesion as correctness relative to a partitioning rule.”</span> Zenodo, Jul. 2026. doi: <a href="https://doi.org/10.5281/zenodo.21703193">10.5281/zenodo.21703193</a>.</div>
</div>
<div id="ref-loth2026causal" class="csl-entry">
<div class="csl-left-margin">[3] </div><div class="csl-right-inline">Y. Loth, <span>“Causal cohesion.”</span> Zenodo, Jul. 2026. doi: <a href="https://doi.org/10.5281/zenodo.21703156">10.5281/zenodo.21703156</a>.</div>
</div>
</div></section></div> ]]></description>
  <category>design</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-08-27-inheritance-vs-composition.html</guid>
  <pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>The Cohesion Series and IVP — Five Papers Published</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-07-14-the-cohesion-series-and-ivp-five-papers-published-40b.html</link>
  <description><![CDATA[ 





<p>The cohesion paper series is now published in full — five papers that build a chain from the concept of cohesion to the <strong>Independent Variation Principle (IVP)</strong>.</p>
<p>The chain:</p>
<ol type="1">
<li><p><strong>On the Nature of Cohesion</strong> — defines cohesion as a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>k</mi></mrow><annotation encoding="application/x-tex">2k</annotation></semantics></math>-tuple: for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math> partitioning rules, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math> (purity, completeness) pairs. Proves the knowledge-embodiment theorem: maximal cohesion under a rule coincides with exact knowledge embodiment under that rule. Shows that every published algorithmic cohesion metric measures a structural proxy (method-call overlap, shared-field density), not cohesion as defined by a principle. <a href="https://doi.org/10.5281/zenodo.21703193">DOI: 10.5281/zenodo.21703193</a></p></li>
<li><p><strong>Causal Cohesion</strong> — instantiates the schema under change-driver-assignment identity: elements belong together iff <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>e</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\Gamma(e_1) = \Gamma(e_2)</annotation></semantics></math>. Develops the metric <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mtext mathvariant="normal">causal</mtext></msub><mo stretchy="false" form="prefix">(</mo><mi>M</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mtext mathvariant="normal">purity</mtext><mo stretchy="false" form="prefix">(</mo><mi>M</mi><mo stretchy="false" form="postfix">)</mo><mo>,</mo><mtext mathvariant="normal">completeness</mtext><mo stretchy="false" form="prefix">(</mo><mi>M</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">H_\text{causal}(M) = (\text{purity}(M), \text{completeness}(M))</annotation></semantics></math>, a two-dimensional score that fills one slot of the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>k</mi></mrow><annotation encoding="application/x-tex">2k</annotation></semantics></math>-tuple. <a href="https://doi.org/10.5281/zenodo.21703156">DOI: 10.5281/zenodo.21703156</a></p></li>
<li><p><strong>Four Necessary Conditions for Optimal Modularization</strong> — from the schema plus the objective of minimizing change propagation, proves four conditions — Admissibility, Element Form, Separation, Unification — are necessary and jointly exhaustive, uniquely pinning the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equality partition <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi><mi>/</mi><mover><mi mathvariant="normal">Γ</mi><mo accent="true">̃</mo></mover></mrow><annotation encoding="application/x-tex">E / \tilde{\Gamma}</annotation></semantics></math>. <a href="https://doi.org/10.5281/zenodo.21362420">DOI: 10.5281/zenodo.21362420</a></p></li>
<li><p><strong>Why Minimizing Change Propagation Minimizes Maintenance Cost</strong> — decomposes total maintenance cost into access, alignment, cognitive, and domain-fixed components. Proves that minimizing change propagation cost is equivalent to minimizing total maintenance cost under an explicit coefficient condition, justifying the objective paper 5 assumed. <a href="https://doi.org/10.5281/zenodo.21362542">DOI: 10.5281/zenodo.21362542</a></p></li>
<li><p><strong>The Independent Variation Principle</strong> — synthesizes the chain into a single structural principle and examines the premises (change drivers, functional model, change isolation), preconditions (driver independence, decisional autonomy), and scope boundary. <a href="https://doi.org/10.5281/zenodo.21362618">DOI: 10.5281/zenodo.21362618</a></p></li>
</ol>
<p>Additional paper: the historical survey of 24 cohesion metrics — <a href="https://doi.org/10.5281/zenodo.21703227">DOI: 10.5281/zenodo.21703227</a>.</p>
<section id="two-derivations" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="two-derivations"><span class="header-section-number">1</span> Two derivations</h2>
<p>Last month’s preprint — <em>Deriving Optimal Module Boundaries from the Element–Change-Driver Graph</em> — proved that the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Γ</mi><annotation encoding="application/x-tex">\Gamma</annotation></semantics></math>-equality partition is the unique cost-minimizing modularization through a self-contained graph-theoretic counting argument: two lemmas on the element–change-driver incidence graph show that scattering same-driver elements or mixing different-driver elements strictly increases cost.</p>
<p>The cohesion series derives the same conclusion through a different route: define cohesion as a schema parameterized by partitioning rules, instantiate a metric, prove optimality under change-isolation, and justify that objective against a richer maintenance-cost model. Different apparatus, same endpoint.</p>
</section>
<section id="how-the-series-builds-a-cohesion-schema" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="how-the-series-builds-a-cohesion-schema"><span class="header-section-number">2</span> How the series builds a cohesion schema</h2>
<p>The cohesion-2 paper argues that cohesion is correctness relative to a partitioning rule — an equivalence relation on elements anchored in domain artifacts (regulations, contracts, protocols). Under <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math> rules, it is a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>k</mi></mrow><annotation encoding="application/x-tex">2k</annotation></semantics></math>-tuple — <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math> (purity, completeness) pairs, one per rule — because each coupling concern, modeled by its governing change driver, resolves into a partitioning rule over the one element set. Cohesion-4 fills one slot with a concrete metric. Cohesion-5 proves which partition is optimal. Cohesion-6 justifies the cost objective. Cohesion-7 states the principle and examines its assumptions.</p>
<hr>
<p>All papers free on Zenodo. Also referenced: the <a href="https://doi.org/10.5281/zenodo.20794332">graph proof</a> (June 2026).</p>


</section>

 ]]></description>
  <category>cohesion</category>
  <category>architecture</category>
  <category>ivp</category>
  <category>engineering</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-07-14-the-cohesion-series-and-ivp-five-papers-published-40b.html</guid>
  <pubDate>Tue, 14 Jul 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>IVP Has a Proof — The Γ-Equality Partition Is the Unique Cost-Minimizing Modularization</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-06-22-ivp-has-a-proof-the-g-equality-partition-is-the-unique-cost-minimizing-modularization-356o.html</link>
  <description><![CDATA[ 





<p><strong>How should software be modularized, and why that way?</strong> A new preprint answers both questions with a proof — and the answer is the <strong>Independent Variation Principle (IVP)</strong>.</p>
<blockquote class="blockquote">
<p>Elements with identical change-driver sets belong in the same module; elements with different change-driver sets belong in different modules.</p>
</blockquote>
<p>A <em>change-driver</em> is an external condition — a regulation, a contract, a protocol specification — whose change forces governed elements to change. The <strong>how</strong> is the rule itself; the <strong>why</strong> is that this exact grouping, and no other, minimizes the cost of change. For fifty years that second question — <em>why these boundaries rather than those</em> — had only well-motivated opinion behind it. This paper turns the answer into a theorem.</p>
<section id="the-proof-is-a-counting-argument" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-proof-is-a-counting-argument"><span class="header-section-number">1</span> The proof is a counting argument</h2>
<p>Draw a bipartite incidence graph: elements on one side, change-drivers on the other, edges recording which drivers govern which elements. On that graph, two lemmas show that any modularization deviating from the IVP prescription pays a strictly higher cost — either by <em>scattering</em> same-driver elements across modules, or by <em>mixing</em> different-driver elements in the same module.</p>
<p>The Γ-equality partition — the one that groups elements by identical change-driver sets — is not one good option among several. <strong>It is the unique cost-minimizing modularization.</strong></p>
</section>
<section id="why-more-than-five-decades-of-principles-couldnt-settle-this" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="why-more-than-five-decades-of-principles-couldnt-settle-this"><span class="header-section-number">2</span> Why more than five decades of principles couldn’t settle this</h2>
<p>Information hiding, the SOLID and package rules, layered and hexagonal architectures, domain-driven boundaries — each distilled real experience into advice about where to draw module boundaries, and each is a <em>heuristic</em>. They share one structural limitation: <strong>none was derived from a cost objective, or any other clearly stated objective</strong>, so none can prove its boundaries are optimal rather than merely reasonable, and where two of them disagree there is no principled way to say which is right.</p>
<p>Some are also internally inconsistent. Martin’s Common Closure and Reuse/Release principles, for instance, cannot both be satisfied under client-driven interface evolution — and the framework names no winner. The common root is the absence of a single objective to optimize against.</p>
</section>
<section id="what-the-proof-gives-you" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="what-the-proof-gives-you"><span class="header-section-number">3</span> What the proof gives you</h2>
<p>This paper supplies that objective and proves the consequence. Once the change-drivers are identified, the question <em>“which elements change for the same reasons?”</em> becomes the precise predicate Γ(e₁) = Γ(e₂) — grouping by the external conditions that govern an element, not by which changes happen to be probable or which have co-occurred in the commit history — and the optimal boundaries follow from it <strong>by counting</strong>. No competing rules to reconcile, no judgment, no taste, no appeal to accumulated experience.</p>
<hr>
<p><strong>Yannick Loth.</strong> <em>The Independent Variation Principle: Deriving Optimal Module Boundaries from the Element–Change-Driver Graph.</em> June 2026.</p>
<p>📄 Free preprint on Zenodo — DOI: <a href="https://doi.org/10.5281/zenodo.20794332">10.5281/zenodo.20794332</a></p>


</section>

 ]]></description>
  <category>engineering</category>
  <category>architecture</category>
  <category>modularization</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-06-22-ivp-has-a-proof-the-g-equality-partition-is-the-unique-cost-minimizing-modularization-356o.html</guid>
  <pubDate>Mon, 22 Jun 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>On the Nature of Cohesion</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-06-01-on-the-nature-of-cohesion-16oc.html</link>
  <description><![CDATA[ 





<p>I’ve published a new paper: <em>On the Nature of Cohesion: Cohesion as a Two-Axis Schema.</em></p>
<p>Cohesion is one of the oldest concepts in software design — introduced by Stevens, Myers, and Constantine in 1974, taught in every curriculum, invoked in every code review. For fifty years, the field has struggled to define it formally. Every published definition is a characterization, not an operational criterion. Every published metric measures a structural proxy.</p>
<p>The paper surveys the major cohesion metrics from the literature, formalizes what cohesion is under any admissible modularization principle, develops the necessary conditions a principled cohesion metric must satisfy, and diagnoses why existing approaches fall short.</p>
<p>If you teach cohesion, apply it in code reviews, or work on software metrics — this paper directly concerns the concept you’re using.</p>
<p><strong>Yannick Loth.</strong> <em>On the Nature of Cohesion: Cohesion as a Two-Axis Schema.</em> June 2026.</p>
<p>DOI: <a href="https://doi.org/10.5281/zenodo.20492913">10.5281/zenodo.20492913</a> — free on Zenodo.</p>



 ]]></description>
  <category>architecture</category>
  <category>engineering</category>
  <category>cohesion</category>
  <category>data</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-06-01-on-the-nature-of-cohesion-16oc.html</guid>
  <pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>SRP’s Vocabulary Problem: Why Every Reformulation Failed</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-05-29-srps-vocabulary-problem-why-every-reformulation-failed-1mbm.html</link>
  <description><![CDATA[ 





<p>I’ve just published <em>SRP’s Vocabulary Problem: Why Every Reformulation Failed</em>.</p>
<p>The Single Responsibility Principle has been criticized as vague, ambiguous, and arbitrary for thirty years. A companion paper shows it carries a demonstrable cardinality error — but that error was hiding in plain sight. Why did no one see it?</p>
<p>This paper answers that question. The vocabulary SRP inherited — “concern” from Dijkstra, “responsibility” from Martin — imports a cardinality assumption before any reasoning begins. The words make the right question unaskable.</p>
<p>📄 <strong>Read the paper:</strong> <a href="https://zenodo.org/records/20445691">10.5281/zenodo.20445691</a></p>
<p>📄 <strong>Companion paper:</strong> <a href="https://zenodo.org/records/20415656">SRP Is Wrong: The Cardinality Error in the Single Responsibility Principle</a></p>



 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-05-29-srps-vocabulary-problem-why-every-reformulation-failed-1mbm.html</guid>
  <pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>SRP Is Wrong: The Cardinality Error in the Single Responsibility Principle</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-05-27-srp-is-wrong-the-cardinality-error-in-the-single-responsibility-principle-n1m.html</link>
  <description><![CDATA[ 





<p>I’ve published a new paper: <em>Why SRP Is Wrong: The Cardinality Error in the Single Responsibility Principle.</em></p>
<p>SRP — “a class should have only one reason to change” — is wrong. Not vague or misunderstood. Wrong.</p>
<p>The adapter pattern is a counterexample. A Stripe payment adapter has two reasons to change: the internal <code>PaymentProcessor</code> interface changes, or Stripe’s API changes. Under Martin’s own interpretation of his terms, that’s two — not one.</p>
<p>SRP’s prescribed remedy is to split the module. But splitting an adapter destroys its function — mediation requires both domains’ knowledge in the same reasoning step. Three salvage attempts (DTO intermediate, mapping table, delegation) all fail. The adapter is irreducibly composite.</p>
<p>The class of counterexamples is not marginal. Every façade, bridge, API gateway, protocol translator, and anti-corruption layer that mediates between independent domains is equally a counterexample. Most complex systems contain them.</p>
<p>The paper formalizes the refutation in the change-driver apparatus with complete theorems and proofs. The formal apparatus is not needed to follow the argument — the counterexample stands alone — but is provided for readers who want the argument in precise, verifiable form.</p>
<p>Paper: <a href="https://zenodo.org/records/20415656">Why SRP Is Wrong: The Cardinality Error in the Single Responsibility Principle.</a>, May 2026.</p>
<p>If you teach SRP or apply it in code reviews: does this refutation change how you think about the principle?</p>



 ]]></description>
  <category>solid</category>
  <category>architecture</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-05-27-srp-is-wrong-the-cardinality-error-in-the-single-responsibility-principle-n1m.html</guid>
  <pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>SOLID Heuristics Reveal Incomplete Domain Knowledge — Nothing More</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-05-24-solid-heuristics-reveal-incomplete-domain-knowledge-nothing-more-3h9j.html</link>
  <description><![CDATA[ 





<p>SOLID — Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion — has been taught for three decades as five independent design principles [Martin 1996a, 1996b, 2000, 2003]. Every software engineer learns them. Every code review invokes them.</p>
<p>This article argues that each SOLID heuristic is not a design principle in the formal sense. It is a <em>diagnostic pattern for a specific way domain knowledge is incomplete or incorrectly expressed</em>. The heuristics exist only because we do not, in practice, document causal domain knowledge completely. Were we to do so, the correct design follows automatically — no heuristic check required.</p>
<section id="how-each-case-is-presented" class="level3" data-number="0.1">
<h3 data-number="0.1" class="anchored" data-anchor-id="how-each-case-is-presented"><span class="header-section-number">0.1</span> How each case is presented</h3>
<p>For each heuristic that addresses change management (SRP, OCP, ISP, DIP), the analysis follows a three-step method:</p>
<ol type="1">
<li><p><strong>Knowledge with the gap.</strong> A domain statement as it is typically written — incomplete or compound — producing flawed code. The SOLID heuristic correctly flags this code. But the heuristic identifies the <em>symptom</em>, not the cause.</p></li>
<li><p><strong>Knowledge without the gap.</strong> The same domain knowledge expressed correctly — decomposed into irreducible sub-statements, each governed by a distinct change driver. This is the knowledge correction. It is not a code refactoring; it is an epistemic act: recognizing what can independently cause each element to change.</p></li>
<li><p><strong>IVP application.</strong> The corrected knowledge yields driver assignments Γ. IVP-2 decomposes reducible composites. IVP-3 and IVP-4 produce the unique module partition. The structure the heuristic prescribed emerges automatically. The heuristic itself was never invoked — it was only needed because the knowledge had a gap.</p></li>
</ol>
<p>LSP is treated separately: it is a hybrid. IVP still determines which types share a driver and therefore belong in the same module. When the structural placement is wrong — types with different invariants forced into a hierarchy — correcting Γ resolves the violation like the others. When the structural placement is correct but the behavioral contract is broken, Bertrand Meyer’s Design by Contract — a type-theoretic discipline — takes over.</p>
<p>The argument rests on the Independent Variation Principle (IVP), a formal theory of software modularization. I state it first.</p>
<hr>
</section>
<section id="the-independent-variation-principle" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-independent-variation-principle"><span class="header-section-number">1</span> The Independent Variation Principle</h2>
<p>IVP defines a software system as a six-tuple <em>S = (F, κ_F, E, K, C, Γ)</em> where:</p>
<ul>
<li><em>F</em> is the set of functional purposes the system must fulfill</li>
<li><em>κ_F</em> is the causal domain knowledge the system must embody to fulfill <em>F</em></li>
<li><em>E</em> is the set of software elements — classes, functions, modules</li>
<li><em>K</em> is the universe of all possible domain knowledge</li>
<li><em>C</em> is the set of change drivers — forces that can causally require elements to be modified (regulations, contracts, interface specifications, stakeholder commitments, hardware evolution)</li>
<li><em>Γ : E → P(C)</em> is the driver assignment function, mapping each element to the set of change drivers that can cause it to require modification</li>
</ul>
<p>The driver assignment Γ is the central object. <em>Γ(e)</em> answers one question: what can cause this element to change? The answer is not a design preference — it is a fact about the system’s causal reality. Two engineers who correctly analyze the same system must arrive at the same Γ. If they disagree, at least one analysis is incomplete.</p>
<p>The four IVP directives are:</p>
<p><strong>IVP-1 — Element Admissibility.</strong> Every element must have at least one change driver: <em>|Γ(e)| ≥ 1</em> for all <em>e ∈ E</em>. An element with no driver serves no purpose and should be removed.</p>
<p><strong>IVP-2 — Change Driver Assignment.</strong> Every element is either pure (<em>|Γ(e)| = 1</em>) or irreducibly composite (<em>|Γ(e)| &gt; 1</em> with no decomposition possible without losing function). A reducible composite — an element that could be split to reduce its driver set — is a design defect. A reducible element is evidence that domain knowledge was over-specified, conflated, or incompletely analyzed.</p>
<p><strong>IVP-3 — Unit Purity (Separation).</strong> Elements with different driver assignments must not occupy the same module: <em>∀ M ∈ M, ∀ e, e’ ∈ M : Γ(e) = Γ(e’)</em>.</p>
<p><strong>IVP-4 — Unit Completeness (Unification).</strong> Elements with the same driver assignment must occupy the same module: <em>∀ e, e’ : Γ(e) = Γ(e’) ⇒ ∃ M ∈ M : {e, e’} ⊆ M</em>.</p>
<p>IVP-3 and IVP-4 together form a biconditional: two elements belong in the same module if and only if they share the same driver assignment. The modularization is precisely the partition of <em>E</em> induced by <em>e₁ ∼ e₂ ⇔ Γ(e₁) = Γ(e₂)</em>.</p>
<p>Four directives. No heuristics. No weighing of trade-offs. The answer falls out of Γ.</p>
<hr>
</section>
<section id="srp-bundled-causal-concerns" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="srp-bundled-causal-concerns"><span class="header-section-number">2</span> SRP: Bundled Causal Concerns</h2>
<section id="knowledge-with-the-gap" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="knowledge-with-the-gap"><span class="header-section-number">2.1</span> Knowledge with the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “The system calculates employee pay, formats pay statements, and emails them to employees.”</p>
</blockquote>
<p>This is a compound statement bundling three independent concerns. The resulting code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PayCalculator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BigDecimal</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calculatePay</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Employee e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* tax rules, benefits, overtime */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-3">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">formatPayStatement</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Employee e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* PDF layout, company logo, line items */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emailPayStatement</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Employee e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> statement<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* SMTP config, attachments */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>SRP says: “A class should have only one reason to change” [Martin 2003]. <code>PayCalculator</code> has three: tax rules change, statement layout changes, email infrastructure changes. SRP flags this — correctly — as a defect.</p>
<p>But SRP does not tell you <em>why</em> the defect exists.</p>
</section>
<section id="knowledge-without-the-gap" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="knowledge-without-the-gap"><span class="header-section-number">2.2</span> Knowledge without the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement (corrected):</strong> - “Pay calculation is governed by tax regulations and benefits contracts.” - “Pay statement formatting is governed by document layout standards.” - “Pay statement delivery is governed by the organization’s mail infrastructure.”</p>
</blockquote>
<p>Three irreducible statements, each governed by a distinct authority. The correction is not a code refactoring — it is a knowledge revision: the compound statement has been decomposed.</p>
</section>
<section id="ivp-application" class="level3" data-number="2.3">
<h3 data-number="2.3" class="anchored" data-anchor-id="ivp-application"><span class="header-section-number">2.3</span> IVP application</h3>
<p>From the corrected knowledge, the driver assignments follow directly:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Element</th>
<th>Γ (change drivers)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>TaxCalculator</code></td>
<td>{γ_tax}</td>
</tr>
<tr class="even">
<td><code>PayStatementFormatter</code></td>
<td>{γ_format}</td>
</tr>
<tr class="odd">
<td><code>PayStatementMailer</code></td>
<td>{γ_email}</td>
</tr>
</tbody>
</table>
<p>Each element is pure: <em>|Γ(e)| = 1</em>. IVP-2 is satisfied.</p>
<p>The driver sets differ (<em>{γ_tax} ≠ {γ_format} ≠ {γ_email}</em>). IVP-3 places each element in its own module:</p>
<ul>
<li><strong>Payroll module:</strong> <code>TaxCalculator</code> (driven by γ_tax)</li>
<li><strong>Formatting module:</strong> <code>PayStatementFormatter</code> (driven by γ_format)</li>
<li><strong>Delivery module:</strong> <code>PayStatementMailer</code> (driven by γ_email)</li>
</ul>
<p>SRP was never invoked. The decomposition falls out of Γ. The resulting class structure — three separate classes, each with a single driver — is identical to what SRP would prescribe. But SRP needed a heuristic check to get there. IVP needed only correct Γ.</p>
</section>
<section id="accidental-coupling-with-the-gap-vs.-without" class="level3" data-number="2.4">
<h3 data-number="2.4" class="anchored" data-anchor-id="accidental-coupling-with-the-gap-vs.-without"><span class="header-section-number">2.4</span> Accidental coupling: with the gap vs.&nbsp;without</h3>
<p>With the gap, the compound knowledge statement creates <em>accidental coupling</em> between three independent driver domains. <code>TaxCalculator</code>’s pay calculation logic is coupled to the formatting code and the email delivery code — not because they share causal drivers, but because the knowledge bundled them into one statement. A change to statement layout (γ_format) touches tax calculation code in the diff. A change to email infrastructure (γ_email) forces recompilation of the pay calculation module. These are accidental dependencies: <code>PayCalculator</code> depends on formatting and email delivery code, but not because the domain requires it.</p>
<p>Without the gap, there is no accidental coupling. Each module contains elements governed by exactly one driver. A dependency exists only where the domain demands it: <code>PayStatementMailer</code> depends on <code>TaxCalculator</code> because the delivery module genuinely needs pay data to construct the email. That is an intentional, domain-justified dependency. The coupling that remains is of the form <em>dependency</em> — one module depends on another. All the coupling discussed in this example is dependency coupling; other forms of coupling exist (data coupling, temporal coupling, coupling via shared state) but do not arise here.</p>
</section>
<section id="when-srp-is-wrong" class="level3" data-number="2.5">
<h3 data-number="2.5" class="anchored" data-anchor-id="when-srp-is-wrong"><span class="header-section-number">2.5</span> When SRP is wrong</h3>
<p>SRP says “a class should have only one reason to change” — it demands <em>|Γ(e)| = 1</em> for every element. But some elements are irreducibly composite: they genuinely embody knowledge from multiple drivers and cannot be split without losing function. SRP would demand splitting them anyway. That is not a knowledge correction — it is a design error.</p>
<p>An adapter between a payment system (γ_payment) and a foreign exchange service (γ_fx) genuinely needs to know both domains: payment message formats <em>and</em> currency conversion protocols. The domain knowledge is not reducible:</p>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “A payment-to-FX adapter translates payment instructions into currency exchange requests.”</p>
</blockquote>
<p>This is one statement — not a compound of two independent ones — because the translation <em>is</em> the element’s function. Splitting it into two elements would leave each unable to perform the translation. Γ(adapter) = {γ_payment, γ_fx} is irreducible. IVP-2 permits this. SRP does not.</p>
<p>SRP is not just unnecessary when knowledge is complete — it is <em>wrong</em> for systems that contain legitimate multi-driver elements. IVP-2’s irreducibility test distinguishes the two cases: reducible (PayCalculator — defect, must split) from irreducible (payment-to-FX adapter — legitimate, must not split). SRP makes no such distinction.</p>
<p><strong>The knowledge flaw SRP detects (when correct):</strong> Domain knowledge expressed as a compound statement rather than as irreducible sub-statements. SRP is the diagnostic for the reducible case; Γ and the irreducibility test handle both cases correctly.</p>
<hr>
</section>
</section>
<section id="ocp-failure-to-anticipate-driver-independent-variation" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="ocp-failure-to-anticipate-driver-independent-variation"><span class="header-section-number">3</span> OCP: Failure to Anticipate Driver-Independent Variation</h2>
<section id="knowledge-with-the-gap-1" class="level3" data-number="3.1">
<h3 data-number="3.1" class="anchored" data-anchor-id="knowledge-with-the-gap-1"><span class="header-section-number">3.1</span> Knowledge with the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “The system sends notifications by email.”</p>
</blockquote>
<p>This statement embeds the notification channel into the notification act. The resulting code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> NotificationService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">notify</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> message<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-3">        emailSender<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>message<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// hard-coded to email</span></span>
<span id="cb2-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>OCP says: “Software entities should be open for extension but closed for modification” [Meyer 1988]. Adding SMS requires modifying <code>NotificationService</code> — a violation.</p>
<p>But OCP does not tell you <em>what</em> knowledge is missing.</p>
</section>
<section id="knowledge-without-the-gap-1" class="level3" data-number="3.2">
<h3 data-number="3.2" class="anchored" data-anchor-id="knowledge-without-the-gap-1"><span class="header-section-number">3.2</span> Knowledge without the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement (corrected):</strong> - “The system sends notifications.” - “Email delivery is governed by the SendGrid API and email template standards.” - “SMS delivery is governed by the Twilio API.” - “Push notification delivery is governed by Firebase Cloud Messaging.”</p>
</blockquote>
<p>Each channel is governed by its own change driver: the email infrastructure (γ_email), the SMS provider (γ_sms), and the push notification service (γ_push). The notification act itself is governed by the notification-content driver (γ_notification). Adding a new channel — say, WhatsApp — means adding a new driver (γ_whatsapp) without modifying existing code.</p>
</section>
<section id="ivp-application-1" class="level3" data-number="3.3">
<h3 data-number="3.3" class="anchored" data-anchor-id="ivp-application-1"><span class="header-section-number">3.3</span> IVP application</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Element</th>
<th>Γ (change drivers)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>NotificationService</code></td>
<td>{γ_notification}</td>
</tr>
<tr class="even">
<td><code>NotificationChannel</code> (interface)</td>
<td>{γ_notification}</td>
</tr>
<tr class="odd">
<td><code>EmailChannel</code></td>
<td>{γ_notification, γ_email}</td>
</tr>
<tr class="even">
<td><code>SmsChannel</code></td>
<td>{γ_notification, γ_sms}</td>
</tr>
<tr class="odd">
<td><code>PushChannel</code></td>
<td>{γ_notification, γ_push}</td>
</tr>
</tbody>
</table>
<p><code>NotificationService</code> and <code>NotificationChannel</code> share {γ_notification} — IVP-4 unifies them in the same module.</p>
<p>Each channel implementation is an <em>irreducible composite</em>: it must know the notification contract (γ_notification — the interface it realizes) and its own delivery mechanism (γ_email, γ_sms, or γ_push). Splitting either driver out would destroy the element’s function — it could not send notifications without knowing the contract, and could not deliver without knowing the infrastructure. IVP-2 permits this: the composite is irreducible.</p>
<p>The driver sets differ: {γ_notification} ≠ {γ_notification, γ_email} ≠ {γ_notification, γ_sms} ≠ {γ_notification, γ_push}. IVP-3 places each in its own module:</p>
<ul>
<li><strong>Notification module:</strong> <code>NotificationService</code>, <code>NotificationChannel</code></li>
<li><strong>Email module:</strong> <code>EmailChannel</code></li>
<li><strong>SMS module:</strong> <code>SmsChannel</code></li>
<li><strong>Push module:</strong> <code>PushChannel</code></li>
</ul>
<p>OCP was never invoked. The resulting structure — an abstraction (<code>NotificationChannel</code>) with separate channel implementations, each in its own module — is identical to what OCP would prescribe. But OCP needed a heuristic check to get there. IVP needed only correct Γ.</p>
<p>The same design also satisfies ISP and DIP. ISP: each channel depends only on the <code>NotificationChannel</code> contract it uses — no channel is forced to depend on other channels’ delivery methods. DIP: <code>NotificationService</code> depends on the <code>NotificationChannel</code> abstraction, not on concrete channels; the interface is owned by the notification domain (high-level), not by the channel implementations (low-level). The three heuristics converge on the same structure because they all address the same underlying reality: variation forces are independent, and dependencies must honor that independence.</p>
</section>
<section id="accidental-coupling-with-the-gap-vs.-without-1" class="level3" data-number="3.4">
<h3 data-number="3.4" class="anchored" data-anchor-id="accidental-coupling-with-the-gap-vs.-without-1"><span class="header-section-number">3.4</span> Accidental coupling: with the gap vs.&nbsp;without</h3>
<p>With the gap, the knowledge statement “the system sends notifications by email” creates <em>accidental coupling</em> between the notification dispatch logic and the email delivery infrastructure. <code>NotificationService</code> is coupled to <code>EmailSender</code> — not because the domain requires dispatch logic to know about email delivery, but because the knowledge embedded the channel into the notification act. A change to SMS delivery (γ_sms) touches <code>NotificationService</code> in the diff. The coupling is accidental: <code>NotificationService</code> depends on email delivery code, but the domain only requires it to depend on the abstract notion of sending a notification.</p>
<p>Without the gap, there is no accidental coupling. <code>NotificationService</code> depends only on <code>NotificationChannel</code> — an abstraction governed by its own driver (γ_notification). Each channel module carries an intentional, irreducible dependency on both γ_notification (the contract it implements) and its infrastructure driver. The coupling that remains is of the form <em>dependency</em> — the service depends on the abstraction, each channel depends on the abstraction. Again, all the coupling visible here is dependency coupling. Adding WhatsApp adds a new module governed by γ_whatsapp. No existing module is modified. OCP says “open for extension, closed for modification.” Γ makes the statement structural: a new driver means a new module. Existing modules are closed.</p>
<p><strong>The knowledge flaw OCP detects:</strong> Knowledge that treats variation points as fixed, when the domain contains forces — each channel’s governing infrastructure — that will activate independently. OCP is the diagnostic; recognizing each variation force as a distinct change driver resolves it.</p>
<hr>
</section>
</section>
<section id="lsp-structural-placement-first-behavioral-validity-second" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="lsp-structural-placement-first-behavioral-validity-second"><span class="header-section-number">4</span> LSP: Structural Placement First, Behavioral Validity Second</h2>
<p>LSP is different from the other four, but not as different as it first appears. The other four are <em>purely</em> knowledge diagnostics: the knowledge is wrong, correct it, the design follows. LSP is a hybrid. IVP still decides where types live — and the LSP violation often reveals that the structural placement was wrong.</p>
<section id="knowledge-with-the-gap-2" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="knowledge-with-the-gap-2"><span class="header-section-number">4.1</span> Knowledge with the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “The system models geometric shapes. Rectangle and Square are shapes with width and height.”</p>
</blockquote>
<p>This statement treats Rectangle and Square as sharing the same driver — geometry. But they don’t. A Rectangle has two independent dimensions. A Square has one dimension with the constraint that width equals height. They are governed by different invariants.</p>
<p>The resulting code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setWidth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setHeight</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">height</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Square <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb3-7">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setWidth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">height</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// breaks invariant</span></span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb3-9">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setHeight</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">height</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>LSP says: “Subtypes must be substitutable for their base types” [Liskov 1987, Liskov and Wing 1994]. <code>Square</code> is not — a method accepting <code>Rectangle</code> that calls <code>setWidth(5); setHeight(10)</code> gets a 10×10 square instead of a 5×10 rectangle. But the heuristic only flags the behavioral violation. It does not tell you <em>why</em> the violation exists.</p>
</section>
<section id="knowledge-without-the-gap-2" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="knowledge-without-the-gap-2"><span class="header-section-number">4.2</span> Knowledge without the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement (corrected):</strong> - “A rectangle is a shape with independent width and height.” - “A square is a shape with a single side length.”</p>
</blockquote>
<p>These are two distinct knowledge statements. The invariant “width = height” is a domain fact about squares, not a property derivable from rectangles. Treating Square as a subtype of a mutable Rectangle is the knowledge error — the domain knowledge was incorrectly modeled as an inheritance relationship rather than as two separate shape types.</p>
</section>
<section id="ivp-application-2" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="ivp-application-2"><span class="header-section-number">4.3</span> IVP application</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Element</th>
<th>Γ (change drivers)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>Rectangle</code></td>
<td>{γ_rect}</td>
</tr>
<tr class="even">
<td><code>Square</code></td>
<td>{γ_square}</td>
</tr>
</tbody>
</table>
<p>The drivers differ: {γ_rect} ≠ {γ_square}. IVP-3 places them in separate modules — no inheritance hierarchy connecting them. Each type governs its own invariant. The LSP violation was a symptom of a structural misplacement: two types with different drivers were forced into a subtype relationship.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setWidth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> w<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setHeight</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">height</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> h<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Square <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setSide</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">side</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> s<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// No inheritance. No shared invariant to break.</span></span>
<span id="cb4-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</section>
<section id="when-lsp-is-not-a-knowledge-gap" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="when-lsp-is-not-a-knowledge-gap"><span class="header-section-number">4.4</span> When LSP is not a knowledge gap</h3>
<p>LSP can also surface purely behavioral problems even when IVP placement is correct. Two elements genuinely share a driver and IVP-3/4 place them together in the same module. Inheritance is the chosen mechanism for sharing behavior. But the subtype breaks the behavioral contract — it strengthens preconditions or weakens postconditions relative to the base type. Here the driver assignments are correct; the defect is in the contract design, not in Γ. This is where Bertrand Meyer’s Design by Contract — a type-theoretic discipline — takes over from IVP.</p>
<p><strong>LSP is a hybrid.</strong> When the structural placement is wrong — types with different invariants forced into a hierarchy — correcting Γ resolves the violation. The resulting class structure — two independent types, no inheritance — is what the corrected knowledge demands. LSP would have flagged the behavioral violation but could not diagnose the structural cause. IVP provides the structural diagnosis; when that suffices, the behavioral violation disappears because the hierarchy no longer exists.</p>
</section>
<section id="accidental-coupling-with-the-gap-vs.-without-2" class="level3" data-number="4.5">
<h3 data-number="4.5" class="anchored" data-anchor-id="accidental-coupling-with-the-gap-vs.-without-2"><span class="header-section-number">4.5</span> Accidental coupling: with the gap vs.&nbsp;without</h3>
<p>With the gap, the knowledge statement treats Rectangle and Square as sharing a driver. The subtype relationship creates <em>accidental coupling</em>: Square is coupled to Rectangle’s invariant that width and height are independent — not because the domain requires squares to have two independent dimensions, but because the knowledge modeled Square as a special case of Rectangle. A change to Rectangle’s invariant (γ_rect) forces re-verification of every Square in the system. Any client code that passes a Square where a Rectangle is expected may silently produce wrong results. The coupling is accidental: Square inherits from Rectangle, but the domain says Square has one dimension, not two.</p>
<p>Without the gap, there is no accidental coupling. Rectangle and Square are separate types in separate modules, each governed by its own driver. γ_rect activates → only Rectangle changes. Square is untouched. No invariant re-verification across types. No substitution surprise. Each type governs its own change space. The only coupling between them — if any — would be an intentional dependency in code that genuinely uses both, not a forced subtype relationship. The coupling that was eliminated is behavioral (substitution via inheritance); the coupling that would remain, if any, is of the form <em>dependency</em>. Coupling is not a single thing.</p>
<hr>
</section>
</section>
<section id="isp-conflated-client-contracts" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="isp-conflated-client-contracts"><span class="header-section-number">5</span> ISP: Conflated Client Contracts</h2>
<section id="knowledge-with-the-gap-3" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="knowledge-with-the-gap-3"><span class="header-section-number">5.1</span> Knowledge with the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “The system has a reporting interface that serves accounting, analytics, and management reporting needs.”</p>
</blockquote>
<p>This statement bundles three distinct client contracts into one. The resulting code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> ReportService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-2">    Report <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generatePdf</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>FinancialData data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>     <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// accounting</span></span>
<span id="cb5-3">    Report <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generateCsv</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>MetricsData data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// analytics</span></span>
<span id="cb5-4">    Report <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generateExcel</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>DashboardData data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// management</span></span>
<span id="cb5-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> AccountingClient <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-7">    ReportService service<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// forced to depend on generateCsv, generateExcel</span></span>
<span id="cb5-8">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> service<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generatePdf</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>ledgerData<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>ISP says: “Many client-specific interfaces are better than one general-purpose interface” [Martin 1996b]. <code>AccountingClient</code> depends on methods it never uses — a violation.</p>
<p>But ISP does not tell you <em>why</em> the violation exists.</p>
</section>
<section id="knowledge-without-the-gap-3" class="level3" data-number="5.2">
<h3 data-number="5.2" class="anchored" data-anchor-id="knowledge-without-the-gap-3"><span class="header-section-number">5.2</span> Knowledge without the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement (corrected):</strong> - “Accounting requires PDF reports of financial data.” - “Analytics requires CSV exports of operational metrics.” - “Management requires Excel dashboards of KPIs.”</p>
</blockquote>
<p>Each client’s contract is a distinct knowledge slice, governed by its own change driver — accounting regulations, analytics requirements, and management reporting standards, respectively.</p>
</section>
<section id="ivp-application-3" class="level3" data-number="5.3">
<h3 data-number="5.3" class="anchored" data-anchor-id="ivp-application-3"><span class="header-section-number">5.3</span> IVP application</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Element</th>
<th>Γ (change drivers)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>AccountingClient</code></td>
<td>{γ_accounting}</td>
</tr>
<tr class="even">
<td><code>AccountingReport</code> (interface)</td>
<td>{γ_accounting}</td>
</tr>
<tr class="odd">
<td><code>AnalyticsClient</code></td>
<td>{γ_analytics}</td>
</tr>
<tr class="even">
<td><code>AnalyticsReport</code> (interface)</td>
<td>{γ_analytics}</td>
</tr>
<tr class="odd">
<td><code>ManagementClient</code></td>
<td>{γ_management}</td>
</tr>
<tr class="even">
<td><code>ManagementReport</code> (interface)</td>
<td>{γ_management}</td>
</tr>
</tbody>
</table>
<p>Each interface shares its client’s Γ. IVP-4 unifies each client-interface pair. {γ_accounting} ≠ {γ_analytics} ≠ {γ_management}, so IVP-3 separates them:</p>
<ul>
<li><strong>Accounting module:</strong> <code>AccountingClient</code>, <code>AccountingReport</code></li>
<li><strong>Analytics module:</strong> <code>AnalyticsClient</code>, <code>AnalyticsReport</code></li>
<li><strong>Management module:</strong> <code>ManagementClient</code>, <code>ManagementReport</code></li>
</ul>
<p>ISP was never invoked. The resulting structure — each client with its own interface, no shared general-purpose interface — is identical to what ISP would prescribe. But ISP needed a heuristic check to get there. IVP needed only correct Γ. No client depends on methods it does not use, because no interface contains methods governed by another client’s driver.</p>
</section>
<section id="accidental-coupling-with-the-gap-vs.-without-3" class="level3" data-number="5.4">
<h3 data-number="5.4" class="anchored" data-anchor-id="accidental-coupling-with-the-gap-vs.-without-3"><span class="header-section-number">5.4</span> Accidental coupling: with the gap vs.&nbsp;without</h3>
<p>With the gap, the knowledge statement “the system has a reporting interface serving accounting, analytics, and management” creates <em>accidental coupling</em> between three independent client domains. <code>AccountingClient</code> is coupled to <code>generateCsv</code> and <code>generateExcel</code> — not because accounting requires CSV exports or Excel dashboards, but because the knowledge bundled all three contracts into one interface. A change to analytics requirements (γ_analytics) — adding a new CSV field — forces recompilation of <code>AccountingClient</code>, even though accounting’s driver is unchanged. The dependency is accidental: <code>AccountingClient</code> depends on methods it does not use, forced by a shared interface that couples three independent driver domains.</p>
<p>Without the gap, there is no accidental coupling. Each client depends only on its own interface — an abstraction governed by the same driver. γ_analytics activates → only the Analytics module (<code>AnalyticsClient</code>, <code>AnalyticsReport</code>) changes. <code>AccountingClient</code> is not in the diff, not recompiled, not re-verified. The coupling that remains is of the form <em>dependency</em> — each client depends on its own interface, which is governed by the same driver. All the coupling discussed here is dependency coupling. ISP says “no client should depend on methods it doesn’t use.” Γ makes that structural: no module depends on code governed by another module’s driver.</p>
<p><strong>The knowledge flaw ISP detects:</strong> Conflated client contracts — domain knowledge that bundles what should be separate slices, each governed by a distinct client’s change driver. ISP is the diagnostic; identifying each client’s driver resolves it.</p>
<hr>
</section>
</section>
<section id="dip-bundled-abstraction-and-implementation" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="dip-bundled-abstraction-and-implementation"><span class="header-section-number">6</span> DIP: Bundled Abstraction and Implementation</h2>
<section id="knowledge-with-the-gap-4" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="knowledge-with-the-gap-4"><span class="header-section-number">6.1</span> Knowledge with the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement:</strong> “OrderProcessor persists orders to MySQL.”</p>
</blockquote>
<p>This statement compounds an abstract capability (persist orders) with a specific realization (MySQL). The resulting code:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> OrderProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> MySQLOrderRepository repository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// concrete dependency</span></span>
<span id="cb6-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Order order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-4">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ... business rules ...</span></span>
<span id="cb6-5">        repository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">save</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb6-6">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-7"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>DIP says: “Depend on abstractions, not on concretions” [Martin 1996a]. <code>OrderProcessor</code> directly depends on a concrete database technology — a violation.</p>
<p>But DIP does not tell you <em>what</em> knowledge is incorrectly expressed.</p>
</section>
<section id="knowledge-without-the-gap-4" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="knowledge-without-the-gap-4"><span class="header-section-number">6.2</span> Knowledge without the gap</h3>
<blockquote class="blockquote">
<p><strong>Domain statement (corrected):</strong> - “Order processing applies business rules to orders and persists the result.” - “Persistence technology — MySQL, PostgreSQL, in-memory — varies independently of order business rules.”</p>
</blockquote>
<p>The correction separates abstract capability from implementation technology. The persistence mechanism is recognized as an independent change driver (γ_persistence) whose activation — switching databases — should not modify <code>OrderProcessor</code>.</p>
</section>
<section id="ivp-application-4" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="ivp-application-4"><span class="header-section-number">6.3</span> IVP application</h3>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Element</th>
<th>Γ (change drivers)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>OrderProcessor</code></td>
<td>{γ_order}</td>
</tr>
<tr class="even">
<td><code>OrderRepository</code> (interface)</td>
<td>{γ_order}</td>
</tr>
<tr class="odd">
<td><code>MySqlOrderRepository</code></td>
<td>{γ_persistence}</td>
</tr>
<tr class="even">
<td><code>PostgreSqlOrderRepository</code></td>
<td>{γ_persistence}</td>
</tr>
</tbody>
</table>
<p>The interface <code>OrderRepository</code> shares {γ_order} with <code>OrderProcessor</code> — IVP-4 unifies them. The implementations share {γ_persistence} — IVP-4 places them together. {γ_order} ≠ {γ_persistence}, so IVP-3 separates the two modules:</p>
<ul>
<li><strong>Order module:</strong> <code>OrderProcessor</code>, <code>OrderRepository</code></li>
<li><strong>Persistence module:</strong> <code>MySqlOrderRepository</code>, <code>PostgreSqlOrderRepository</code></li>
</ul>
<p>DIP was never invoked. The resulting structure — an abstraction owned by the high-level module, with implementations in a separate module — is identical to what DIP would prescribe. But DIP needed a heuristic check to get there. IVP needed only correct Γ. <code>OrderProcessor</code> depends on an interface governed by its own driver — exactly the dependency structure DIP prescribes, derived from Γ alone.</p>
</section>
<section id="accidental-coupling-with-the-gap-vs.-without-4" class="level3" data-number="6.4">
<h3 data-number="6.4" class="anchored" data-anchor-id="accidental-coupling-with-the-gap-vs.-without-4"><span class="header-section-number">6.4</span> Accidental coupling: with the gap vs.&nbsp;without</h3>
<p>With the gap, the knowledge statement “OrderProcessor persists orders to MySQL” creates <em>accidental coupling</em> between order processing and persistence technology. <code>OrderProcessor</code> is coupled to <code>MySQLOrderRepository</code> — not because order business rules require MySQL, but because the knowledge bundled the abstraction with a specific implementation. A change to persistence technology (γ_persistence) — switching to PostgreSQL — forces modification of <code>OrderProcessor</code>, even though order business rules are unchanged. The concrete dependency couples two independent driver domains. The coupling is accidental: <code>OrderProcessor</code> depends on MySQL, but the domain only requires it to depend on the abstract capability of persisting orders.</p>
<p>Without the gap, there is no accidental coupling. <code>OrderProcessor</code> depends only on <code>OrderRepository</code> — an abstraction governed by its own driver (γ_order). γ_persistence activates → only the Persistence module (<code>MySqlOrderRepository</code>, <code>PostgreSqlOrderRepository</code>) changes. The Order module is not in the diff — the interface <code>OrderRepository</code> insulates it. γ_order activates → only the Order module changes. The coupling that remains is of the form <em>dependency</em> — <code>OrderProcessor</code> depends on the interface, implementations depend on the interface. Again, all the coupling discussed here is dependency coupling. The abstraction (<code>OrderRepository</code>) is the structural seam where IVP-3 separates the two driver domains, and the interface ownership — with the order module, not the persistence module — ensures that changes to persistence technology cannot force changes to order processing.</p>
<p><strong>The knowledge flaw DIP detects:</strong> Bundled abstraction and implementation — domain knowledge that compounds an abstract capability with a specific realization, when the two are governed by independent change drivers. DIP is the diagnostic; recognizing the implementation technology as an independent driver resolves it.</p>
<hr>
</section>
</section>
<section id="the-synthesis" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-synthesis"><span class="header-section-number">7</span> The Synthesis</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 11%">
<col style="width: 24%">
<col style="width: 27%">
<col style="width: 21%">
<col style="width: 16%">
</colgroup>
<thead>
<tr class="header">
<th>Heuristic</th>
<th>Knowledge with the gap</th>
<th>Knowledge without the gap</th>
<th>Γ after correction</th>
<th>IVP resolution</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>SRP</td>
<td>“The system calculates pay, formats statements, and emails them”</td>
<td>Three separate statements, each with its own governing authority</td>
<td>Three pure elements, each {γ_i}</td>
<td>IVP-2 decomposes reducible composites; IVP-3 separates. <em>Wrong in general:</em> SRP also demands splitting irreducible composites (adapters) that IVP-2 correctly permits.</td>
</tr>
<tr class="even">
<td>OCP</td>
<td>“The system sends notifications by email”</td>
<td>“Notification is governed by notification requirements. Each channel — email, SMS, push — has its own governing infrastructure.”</td>
<td>{γ_notification} for service and interface; {γ_notification, γ_email}, {γ_notification, γ_sms}, {γ_notification, γ_push} for channels (irreducible composites)</td>
<td>IVP-3 separates per channel; IVP-2 permits the irreducible composite; IVP-4 unifies service with its interface</td>
</tr>
<tr class="odd">
<td>LSP</td>
<td>“Rectangle and Square are shapes with width and height”</td>
<td>“Rectangle has independent width and height. Square has a single side length with the constraint width = height.”</td>
<td>{γ_rect} for Rectangle, {γ_square} for Square</td>
<td>IVP-3 separates; the subtype relationship was forced onto two types with different invariants. <em>Hybrid:</em> when Γ is correct but contract is broken, Bertrand Meyer’s Design by Contract is needed.</td>
</tr>
<tr class="even">
<td>ISP</td>
<td>“The system has a reporting interface serving accounting, analytics, and management”</td>
<td>Three separate client contracts, each governed by its own driver</td>
<td>Interface-client pairs share Γ</td>
<td>IVP-4 unifies each pair; IVP-3 separates across clients</td>
</tr>
<tr class="odd">
<td>DIP</td>
<td>“OrderProcessor persists orders to MySQL”</td>
<td>“Order processing and persistence technology vary independently”</td>
<td>{γ_order} for processor and interface, {γ_persistence} for implementations</td>
<td>IVP-3 separates abstraction from implementation</td>
</tr>
</tbody>
</table>
<p>The pattern is uniform for SRP, OCP, ISP, and DIP. Each identifies a particular way domain knowledge is incomplete or incorrectly expressed. The prescription is always the same: <strong>decompose the compound or incomplete knowledge statement into irreducible sub-statements with distinct driver assignments; let the code structure emerge from correct Γ.</strong></p>
<p>SRP is additionally wrong in general: it demands purity (<em>|Γ(e)| = 1</em>) for every element, failing to recognize legitimate irreducible composites such as adapters, facades, and protocol translators. IVP-2’s irreducibility test is the correct criterion — it decomposes the reducible (PayCalculator) and permits the irreducible (payment-to-FX adapter). SRP lacks this distinction.</p>
<p>LSP is a hybrid. When the structural placement is wrong — types with different invariants forced into a hierarchy — the violation resolves like the others: correct Γ, IVP separates, the problem disappears. When the structural placement is correct but the behavioral contract is broken, Bertrand Meyer’s Design by Contract is needed. The other four heuristics are purely knowledge diagnostics; LSP spans both domains.</p>
</section>
<section id="what-this-means" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="what-this-means"><span class="header-section-number">8</span> What This Means</h2>
<p>Were domain knowledge always causally complete and correctly documented, the four IVP directives would produce the correct design automatically. Γ would capture every element’s causal dependencies. IVP-2 would flag every reducible composite. IVP-3 and IVP-4 would produce the unique module partition. There would be nothing for SRP, OCP, ISP, or DIP to do.</p>
<p>The heuristics exist only because, in practice, domain knowledge is incomplete or incorrectly expressed. When a designer applies SRP to a class with multiple reasons to change, they are correcting a knowledge defect — the statement “the system calculates pay, formats statements, and emails them” should be three statements. When a designer applies DIP to a concrete dependency, they are correcting a knowledge defect — the statement “OrderProcessor persists to MySQL” bundled abstract capability with implementation detail.</p>
<p>SOLID heuristics are <em>reports of incomplete knowledge</em>. They do not produce correct structure from correct inputs — they diagnose incorrect inputs. IVP is the general law that would be sufficient if knowledge were complete.</p>
<p>The fact that the IVP-derived structures are identical to what each heuristic prescribes — same class decomposition, same abstraction boundaries, same interface segregation — is not a coincidence. Three independent discovery paths converge on the same structural conclusions: mathematical derivation from cost axioms, empirical debugging experience encoded in SOLID, and epistemic insight that software design is knowledge work. When a heuristic’s prescription matches what IVP derives from correct Γ, the heuristic identifies a genuine structural condition; IVP explains <em>why</em> that condition holds. When a heuristic diverges — SRP demanding splits of irreducible composites — IVP identifies the error and supplies the correct criterion.</p>
<p>This framing has practical consequences. A designer who understands IVP has no need for SRP, OCP, ISP, or DIP as separate rules. IVP provides a strictly stronger and more precise criterion — one that avoids the errors those heuristics introduce outside their narrow conditions. SRP demands splitting legitimate multi-driver modules (irreducible composites). OCP and ISP are silent about unification (IVP-4). IVP’s four directives cover both separation and unification, pure and composite elements, with formal precision.</p>
<p>The question to ask when a SOLID heuristic appears to apply is not “how do I fix this code?” but <em>“what causal domain knowledge is missing or incorrectly expressed such that this code structure emerged?”</em> The code defect is a symptom. The knowledge defect is the cause.</p>
<hr>
</section>
<section id="a-note-on-robert-c.-martins-achievement" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="a-note-on-robert-c.-martins-achievement"><span class="header-section-number">9</span> A note on Robert C. Martin’s achievement</h2>
<p>This article argues that SOLID heuristics are diagnostic patterns for incomplete knowledge, not design principles. That does not diminish Robert C. Martin’s contribution. Identifying five recurrent patterns across decades of practitioner experience — and giving them names that the entire industry adopted — is a remarkable feat of pattern recognition [Martin 1996a, 1996b, 2000, 2003]. The heuristics are not principles in the formal sense, but their identification was an act of genuine discovery.</p>
<p>Several authors have previously observed that SOLID’s five heuristics are not all independent. Henney [2016] argued that ISP becomes redundant if SRP is properly applied. Oldwood [2014] proposed that all five reduce to two concepts. Kaminski [2019] noted that SRP, ISP, and DIP rehash similar concepts around managing dependencies. Terhorst-North [2022] proposed replacing SOLID entirely with a different framework. None of these critiques identified the specific mechanism that IVP reveals: each heuristic is a diagnostic pattern for a particular way domain knowledge is incomplete or incorrectly expressed.</p>
<p>This interpretation is itself only possible because of a formal theoretical development of the matter. The Independent Variation Principle provides a fundamental, principled design practice — four directives derived from the Change Management Hypothesis — that determines a unique module partition from causal domain knowledge alone. Without this formal foundation, SOLID’s heuristics remain disconnected rules of thumb. Earlier critics could sense overlap and redundancy. They could not specify <em>why</em> each heuristic arises or <em>what</em> structural situation it addresses — because those answers require the apparatus of change drivers, driver assignments, and the IVP directives. IVP does not merely critique SOLID. It provides the formal framework within which SOLID’s contribution — and its limits — become legible.</p>
<p>Three of the five — OCP, ISP, and DIP — have been essential in module boundary design for roughly thirty years. They address what happens at the seam between modules: OCP says don’t modify existing code, extend through a boundary. ISP says segregate interfaces per client at the boundary. DIP says depend on abstractions owned by the high-level module, not on concretions from the low-level one. These three are the practical workhorses of boundary design. They converge on the same structural truth IVP formalizes: variation forces are independent, and module boundaries must honor that independence.</p>
<p>SRP is different. It addresses internal cohesion — what belongs inside a class — not boundary structure. Its prescription (“one reason to change”) is correct for reducible composites but wrong for irreducible ones. LSP is also different: it addresses behavioral contracts within a type hierarchy, not boundaries between modules. The three boundary heuristics are where SOLID’s lasting value lies. The other two diagnose real problems but lack the generality of the boundary principles — and the formal foundation that IVP provides.</p>
<hr>
</section>
<section id="further-reading" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="further-reading"><span class="header-section-number">10</span> Further Reading</h2>
<p>The formal theory is developed in Volume 1 of the IVP book series, with Chapter 9 providing the full IVP–SOLID analysis and Chapter 3 developing the structural formulation.</p>
<ul>
<li>IVP formalization (preprint): <a href="https://doi.org/10.5281/zenodo.18024111">DOI: 10.5281/zenodo.18024111</a></li>
<li>ISP Is a Conditional Corollary of DIP Applied Per Client - An Asymmetric Relationship Gated by Interface Evolution Origin: <a href="https://doi.org/10.5281/zenodo.20350293">DOI: 10.5281/zenodo.20350293</a> — a formal proof that ISP is a conditional corollary of DIP applied per client, and that the two heuristics address the same structural constraint from different vantage points.</li>
</ul>
<p>If this framing — SOLID as diagnostic patterns for incomplete domain knowledge — resonates, the ISP–DIP paper is the natural next read. It shows the same phenomenon at closer range: two heuristics that converge on one structure, differing only in which knowledge gap they are named after.</p>
<hr>
<p>If you teach SOLID or use it daily in code reviews: does the “diagnostic pattern for incomplete knowledge” framing change how you apply these heuristics? I would value your perspective.</p>
<hr>
</section>
<section id="references" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="references"><span class="header-section-number">11</span> References</h2>
<ul>
<li>[Henney 2016] Kevlin Henney. <em>SOLID Deconstruction.</em> NDC London, January 2016.</li>
<li>[Kaminski 2019] Tomasz Kamiński. <em>Deconstructing SOLID design principles.</em> Blog post, April 2019.</li>
<li>[Liskov 1987] Barbara Liskov. <em>Data Abstraction and Hierarchy.</em> OOPSLA 1987, Addendum to the Proceedings.</li>
<li>[Liskov and Wing 1994] Barbara Liskov and Jeannette M. Wing. <em>A Behavioral Notion of Subtyping.</em> ACM Transactions on Programming Languages and Systems, 16(6):1811–1841, 1994.</li>
<li>[Martin 1996a] Robert C. Martin. <em>The Dependency Inversion Principle.</em> C++ Report, May 1996.</li>
<li>[Martin 1996b] Robert C. Martin. <em>The Interface Segregation Principle.</em> C++ Report, August 1996.</li>
<li>[Martin 2000] Robert C. Martin. <em>Design Principles and Design Patterns.</em> Object Mentor, 2000.</li>
<li>[Martin 2003] Robert C. Martin. <em>Agile Software Development: Principles, Patterns, and Practices.</em> Prentice Hall, 2003.</li>
<li>[Meyer 1988] Bertrand Meyer. <em>Object-Oriented Software Construction.</em> Prentice Hall, 1988.</li>
<li>[Oldwood 2014] Chris Oldwood. <em>KISSing SOLID Goodbye.</em> ACCU Overload, 22(122), August 2014.</li>
<li>[Terhorst-North 2022] Daniel Terhorst-North. <em>CUPID — for joyful coding.</em> Blog post, 2022.</li>
</ul>


</section>

 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>ivp</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-05-24-solid-heuristics-reveal-incomplete-domain-knowledge-nothing-more-3h9j.html</guid>
  <pubDate>Sun, 24 May 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Where Do Interfaces Live? IVP Answers What SOLID Cannot</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-18-where-do-interfaces-live-ivp-answers-what-solid-cannot-kin.html</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>If you know a software architect, a professor who teaches SOLID, or anyone who takes design principles seriously — I’d appreciate you sharing this with them.</p>
</blockquote>
<p>Two companion papers established the structural biconditional between ISP and per-client DIP (<a href="https://zenodo.org/records/19633560">paper 1</a>) and proved that Martin’s packaging principles are jointly unsatisfiable for the resulting configuration — specifically, CCP and REP cannot both be satisfied (<a href="https://zenodo.org/records/19636635">paper 2</a>).</p>
<p>This third paper applies the Independent Variation Principle (IVP) to the same five-element setup and obtains two results from a single application.</p>
<section id="result-1-dip-isp-formalized-in-ivp-terms" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="result-1-dip-isp-formalized-in-ivp-terms"><span class="header-section-number">1</span> Result 1: DIP → ISP, formalized in IVP terms</h2>
<p>The first companion paper proved the structural biconditional: ISP ↔︎ per-client DIP. This paper formalizes the forward direction (DIP implies ISP) in IVP terms. Each interface slice shares its client’s change-driver assignment. The IVP biconditional (elements co-reside iff they share driver assignments) closes the proof: the slices are disjoint because the clients belong to different modules. IVP adds formalism to one direction of a valid structural biconditional; it is useful here but not indispensable.</p>
</section>
<section id="result-2-a-unique-modularization" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="result-2-a-unique-modularization"><span class="header-section-number">2</span> Result 2: A unique modularization</h2>
<p>This is where IVP is essential.</p>
<p>Five elements: provider A, clients B and C, interface slices I_B and I_C. Three distinct driver assignments: {γ_ord} for B and I_B, {γ_rep} for C and I_C, {γ_ord, γ_rep, γ_impl} for A.</p>
<p>IVP-3 (elements with different driver assignments cannot co-reside) and IVP-4 (elements with identical driver assignments must co-reside) together admit exactly one partition:</p>
<ul>
<li><strong>Module B:</strong> B and I_B (both driven by γ_ord)</li>
<li><strong>Module C:</strong> C and I_C (both driven by γ_rep)</li>
<li><strong>Module A:</strong> A alone (composite: γ_ord, γ_rep, γ_impl)</li>
</ul>
<p>Each interface slice lives with its client — not as a design preference, but as a consequence of the axioms applied to the causal structure of change.</p>
</section>
<section id="what-this-settles" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="what-this-settles"><span class="header-section-number">3</span> What this settles</h2>
<p>The packaging paper showed that eight principles — DIP, ISP, and six packaging principles (REP, CCP, CRP, ADP, SDP, SAP) — give three incompatible answers (with client, with provider, own module) and no meta-criterion for choosing. IVP eliminates two of the three by deriving the answer from Γ.</p>
<p>If two engineers disagree about where I_B belongs, the disagreement traces to a disagreement about Γ — about what can cause I_B to require modification. That is an epistemic question about the system, not a design preference. IVP converts a judgment call into a falsifiable claim.</p>
</section>
<section id="what-ivps-placement-produces" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="what-ivps-placement-produces"><span class="header-section-number">4</span> What IVP’s placement produces</h2>
<p>The paper verifies that the unique IVP partition delivers:</p>
<ul>
<li><strong>Change isolation:</strong> a change to γ_ord modifies Module B (containing B and I_B) and nothing else. Module C is untouched.</li>
<li><strong>No shotgun surgery:</strong> the pathology that scattered interface placement creates is eliminated by construction.</li>
<li><strong>Acyclic dependencies in the provider–client subgraph:</strong> A depends on Module B and Module C (for the interface specifications it implements). Neither client module depends on A. No cycle exists in this subgraph.</li>
<li><strong>Independent deployability:</strong> each module can be released independently.</li>
</ul>
</section>
<section id="the-paper" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-paper"><span class="header-section-number">5</span> The paper</h2>
<p><strong>“The Interface Segregation Principle Is a Corollary of the Dependency Inversion Principle — A Formal Proof via the Independent Variation Principle”</strong></p>
<ul>
<li>Paper: <a href="https://zenodo.org/records/19641242">https://zenodo.org/records/19641242</a></li>
<li>Companion 1 (ISP = DIP, structural): <a href="https://zenodo.org/records/19633560">https://zenodo.org/records/19633560</a></li>
<li>Companion 2 (packaging unsatisfiability): <a href="https://zenodo.org/records/19636635">https://zenodo.org/records/19636635</a></li>
</ul>
<hr>
<ul>
<li>Companion 1 dev.to article: <a href="https://dev.to/yannick555/solid-isp-is-just-dip-applied-twice-46jk">SOLID: ISP Is Just DIP Applied Twice</a></li>
<li>Companion 2 dev.to article: <a href="https://dev.to/yannick555/solids-packaging-principles-are-jointly-unsatisfiable-27mh">SOLID’s Packaging Principles Are Jointly Unsatisfiable</a></li>
</ul>
<hr>
<p>The first paper showed ISP and DIP produce the same structure. The second showed SOLID’s principles can’t agree on where to put it. This one shows IVP can.</p>
<p>If you think the unique partition is wrong — that I_B belongs somewhere other than with B — I’d like to hear the argument. What change driver does I_B respond to, if not B’s?</p>


</section>

 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>engineering</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-18-where-do-interfaces-live-ivp-answers-what-solid-cannot-kin.html</guid>
  <pubDate>Sat, 18 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>SOLID: ISP Is Just DIP Applied Twice</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-17-solid-isp-is-just-dip-applied-twice-46jk.html</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>If you know someone who teaches or researches software design principles, I’d appreciate you sharing this — the argument needs to be challenged by people who take SOLID seriously.</p>
</blockquote>
<p>The Interface Segregation Principle (ISP) is widely taught as the fourth independent letter in SOLID. I’ve written a short paper showing it isn’t independent at all: it is a special case of DIP’s ownership clause applied once per client–provider edge.</p>
<p>Once both principles are stated precisely enough to reason about formally, the argument is straightforward. DIP’s ownership clause says the client defines the interface it depends upon. Apply that to one client: you get one client-specific interface. Apply it to a second client of the same provider: you get a second, different interface. The provider now implements both, each client sees only its own slice, and no client depends on methods it doesn’t use — which is exactly what ISP prescribes. At the class level, the two principles produce the identical structure: the same classes, the same interfaces, the same dependency and implementation relationships.</p>
<p>The converse also holds: any ISP-compliant segregation is structurally indistinguishable from the result of applying DIP’s ownership clause per client.</p>
<p>I’m not saying that naming ISP is useless — naming the corollary directs attention to the per-client application of DIP, which textbooks consistently underemphasize. The claim is narrower: ISP prescribes no design action that per-client DIP doesn’t already prescribe.</p>
<p>The paper also examines why this connection went unnoticed for nearly thirty years. The most fundamental reason is that both principles were stated as informal design directives illustrated by examples, making logical derivation impossible until they are stated precisely. Other factors include DIP’s single-client framing, ISP’s status as the least-scrutinized SOLID principle, and the strong prior created by the five-letter acronym.</p>
<p>Building on observations by Henney, Oldwood, Kaminski, and North that SOLID’s principles overlap, I traced a specific derivation that, to my knowledge, has not been identified before: DIP’s ownership clause applied per client <em>is</em> ISP.</p>
<p>The full structural proof (at the class level), worked example, and historical analysis are freely available:</p>
<p><strong>“The Interface Segregation Principle Is a Corollary of the Dependency Inversion Principle: A Structural Proof”</strong></p>
<ul>
<li>Paper: <a href="https://zenodo.org/records/19633560">https://zenodo.org/records/19633560</a></li>
<li>DOI: <a href="https://doi.org/10.5281/zenodo.19633560">10.5281/zenodo.19633560</a></li>
</ul>
<hr>
<p>At the class level, is there a case where ISP prescribes a different structure than per-client DIP? If you think ISP adds something at other levels (packages, APIs, services), I’d be interested in that too — the paper’s scope is class-level, and extensions are future work.</p>
<hr>



 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>engineering</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-17-solid-isp-is-just-dip-applied-twice-46jk.html</guid>
  <pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>SOLID’s Packaging Principles Are Jointly Unsatisfiable</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-17-solids-packaging-principles-are-jointly-unsatisfiable-27mh.html</link>
  <description><![CDATA[ 





<blockquote class="blockquote">
<p>If you know a software architect, a professor who teaches SOLID or packaging principles, or anyone who takes design principles seriously — I’d appreciate you sharing this with them. The argument needs to be challenged by practitioners and researchers alike.</p>
</blockquote>
<p>A <a href="https://dev.to/yannick555/solid-isp-is-just-dip-applied-twice-46jk">companion paper</a> showed that ISP is a corollary of DIP at the class level. That settles <em>which</em> elements exist. It doesn’t settle <em>where</em> they live in the package structure.</p>
<p>The paper I’m announcing here asks that question — and provides a <strong>formal proof</strong> that <strong>Martin’s packaging principles cannot be applied simultaneously in general, and are in fact contradictory for a common class of dependency configurations</strong>.</p>
<section id="the-setup" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-setup"><span class="header-section-number">1</span> The setup</h2>
<p>Five elements: a provider A implementing two client-specific interfaces I_B and I_C, and two clients B and C depending on their respective interfaces. This is the minimal non-trivial DIP/ISP-compliant configuration — and a routine dependency pattern in object-oriented software.</p>
<p>52 ways to partition five elements into packages. Martin gives us eight principles (DIP, ISP, and six packaging principles: REP, CCP, CRP, ADP, SDP, SAP) to narrow the space.</p>
</section>
<section id="the-result" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-result"><span class="header-section-number">2</span> The result</h2>
<p>CCP and REP are jointly unsatisfiable.</p>
<p>CCP says: elements that change for the same reasons belong in the same package. Under DIP’s ownership clause, I_B changes for the same reasons as B. So CCP puts I_B with B.</p>
<p>REP says: every package must be a viable unit of reuse — no consumer should be forced to accept elements it doesn’t use. A must implement I_B, so A’s package must depend on whichever package contains I_B. If I_B is packaged with B (as CCP requires), A is forced to take a dependency on B even though it never uses B. REP is violated.</p>
<p>No partition satisfies both. The proof is two steps, and it generalizes to any system where a provider serves two or more clients through client-specific interfaces.</p>
</section>
<section id="it-gets-worse" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="it-gets-worse"><span class="header-section-number">3</span> It gets worse</h2>
<p>Martin presents CCP, CRP, and REP as a “tension triangle” — three principles pulling in different directions, with the architect choosing which vertex to sacrifice. This sounds like a navigable trade-off space. It isn’t.</p>
<p>Dropping REP from the triangle still yields zero satisfying partitions: CCP and CRP together remain unsatisfiable for the same configuration. Dropping CRP fares no better — the CCP/REP conflict that started this analysis is still there, unresolved. Only dropping CCP produces any solutions at all, and even then five partitions survive with no principle left to select among them. Two of the three escape hatches lead nowhere. The triangle has no navigable interior.</p>
<p>Adding DIP back into the picture doesn’t rescue things. The co-location reading contradicts REP; the examples reading contradicts ISP; and the ownership reading adds no packaging constraint at all. The only DIP interpretation that doesn’t eliminate the five surviving partitions is the one that stays silent on where packages should go.</p>
</section>
<section id="every-recommendation-is-self-defeating" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="every-recommendation-is-self-defeating"><span class="header-section-number">4</span> Every recommendation is self-defeating</h2>
<p>The three natural placements — with client, with provider, own package — each have principled support <em>and</em> principled condemnation from within the same framework. The principles don’t just fail to agree on a winner; they actively indict every candidate they put forward.</p>
</section>
<section id="why-this-matters" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="why-this-matters"><span class="header-section-number">5</span> Why this matters</h2>
<p>If no packaging satisfies all principles, then any system containing a multi-client provider configuration violates at least one principle at every point in its history. The concept of “technical debt” implies a principled ideal to return to. For packaging, no such ideal exists.</p>
<p>Students who learn SOLID and the packaging principles as a coherent methodology will attempt to satisfy all of them, fail, and draw one of two wrong conclusions: (a) “I’m not skilled enough yet,” or (b) “principles are just guidelines.” Neither is correct. The correct conclusion — that these specific principles are collectively unsatisfiable — has not been available because the unsatisfiability was never demonstrated.</p>
</section>
<section id="the-paper" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="the-paper"><span class="header-section-number">6</span> The paper</h2>
<p><strong>“SOLID: Where Do Client-Owned Interfaces Live? DIP, ISP, and the Packaging Principles”</strong></p>
<ul>
<li>Paper: <a href="https://zenodo.org/records/19636635">https://zenodo.org/records/19636635</a></li>
<li>DOI: <a href="https://doi.org/10.5281/zenodo.19636635">10.5281/zenodo.19636635</a></li>
</ul>
<hr>
<p>Can you find a packaging of any multi-client provider configuration that satisfies CCP and REP simultaneously? If you think the formalization is too strict — that CCP should be a preference rather than a constraint — what does it mean to call something a “principle” if it can always be overridden by judgment?</p>


</section>

 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>engineering</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-17-solids-packaging-principles-are-jointly-unsatisfiable-27mh.html</guid>
  <pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Process-First Design and the Independent Variation Principle: Two Paths to the Same Territory</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-15-process-first-design-and-the-independent-variation-principle-two-paths-to-the-same-territory-c8j.html</link>
  <description><![CDATA[ 





<p><em>In response to Sergiy Yevtushenko’s “The Quiet Consensus” and “Java Backend Design Technology: A Process-First Methodology”</em></p>
<hr>
<p>Sergiy Yevtushenko’s two recent articles make a concrete empirical observation: practitioners from F#, Rust/TypeScript, Java, Scala, and .NET have independently arrived at a shared structural insight about software decomposition. The insight is that processes — not data entities — are the more natural primary unit. Each practitioner he cites — Scott Wlaschin, Rico Fritzsche, Roman Weis, Sandro Mancuso, Jimmy Bogard, Debasish Ghosh — arrived at this conclusion from within their own tradition, without coordinating, solving problems at different scales and in different domains.</p>
<p>Independent convergence of this kind is methodologically significant. It suggests that the structural insight is not an artifact of a particular language or paradigm, but a response to a genuine property of the design problem itself. The problem, as Sergiy frames it, is that entity-first decomposition creates coupling through shared data models, and that coupling grows as the system grows. Process-first decomposition scopes data types to the processes that use them, so that changes in one process’s requirements do not propagate through another process’s code.</p>
<p>I have been developing a framework — the Independent Variation Principle (IVP) — that approaches the same structural territory from a different angle. This article examines where the two approaches meet, where they differ, and what each contributes.</p>
<hr>
<section id="the-process-first-framework" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-process-first-framework"><span class="header-section-number">1</span> The process-first framework</h2>
<p>Sergiy’s eight-question framework extracts a process structure from a feature description: what triggers the process, what data it needs, what success and failure look like, what its steps are, which steps depend on each other, whether there are conditional paths, and whether there is collection processing. The answers produce typed inputs, typed outputs, typed failure modes, step interfaces, and a dependency structure among the steps.</p>
<p>The dependency structure is the key output. Steps whose outputs are independent of each other can be composed in parallel. Steps where one requires the output of another must chain sequentially. The resulting composition — expressed as a data dependency graph using three operators (Sequential, ALL, ANY) — maps to code. Sequential becomes <code>flatMap</code>. ALL becomes a fork-join. ANY becomes a fallback that takes the first successful result.</p>
<p>The knowledge-gathering framing underlying this methodology has a structural consequence that extends beyond the surface description. Each step acquires a piece of knowledge. The process ends when enough knowledge has accumulated to formulate a response — success if the knowledge supports it, failure otherwise. A declined payment is not a mechanical error; it is a learned fact, and the process’s response to it is structurally the same as its response to a successful payment, just with a different answer. This makes the semantics of failure modes explicit in the composition rather than leaving them as exception handling layered over a happy path.</p>
<p>The consequence for data modeling follows directly: rather than asking what data exists in the system, you ask what this process needs to know. Types are scoped to processes. Entities emerge afterward as the intersection of processes that need the same persistent facts. To use Sergiy’s seat example: what booking needs to know about a seat differs from what pricing needs to know, which differs from what reservation management needs to know. A shared entity that serves all three is a compromise that fits none of them precisely.</p>
<hr>
</section>
<section id="the-independent-variation-principle" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-independent-variation-principle"><span class="header-section-number">2</span> The Independent Variation Principle</h2>
<p>IVP starts from a different question: what causes each element of a software system to require modification? For each element, there is a set of change drivers — domain rules, regulations, operational constraints, anything that, when it changes, forces that element to change. The principle states that elements with the same set of change drivers belong in the same module, and elements with different sets belong in different modules.</p>
<p>Formally, this is a mapping Γ from elements to their driver sets. Two elements e and e′ belong in the same module if and only if Γ(e) = Γ(e′). The module structure that satisfies this condition is the partition of the element set induced by driver-set equality. This partition is unique given a fixed driver assignment, and it is a fact about the causal structure of the domain rather than a design preference.</p>
<p>The practical consequence is that IVP provides a criterion for adjudicating boundary decisions. When two engineers disagree about whether two elements belong together, the disagreement can be localized: instead of arguing about whether the boundary feels right, they are arguing about whether the elements share change drivers. That is a question domain expertise can investigate, and it is a question to which there is a fact of the matter.</p>
<hr>
</section>
<section id="where-the-two-frameworks-meet" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="where-the-two-frameworks-meet"><span class="header-section-number">3</span> Where the two frameworks meet</h2>
<p>Both frameworks address the question of which elements of a software system should be grouped together and which should be separated. Sergiy’s framework identifies what each process needs and scopes types accordingly. IVP asks what causes each element to change and groups by driver-set equality. The two approaches converge on the same structural observation: elements whose change is driven by independent forces should be separated, and elements driven by the same forces should be grouped.</p>
<p>The “entities are discovered, not invented” claim in process-first design maps onto what IVP would predict from driver analysis. Two processes share a persistent type when they share facts about the world governed by the same change drivers. If the price of a product changes for the same reasons regardless of which process queries it, the price data has a single driver set and belongs in a single location. If what booking calls a “seat” changes for logistics reasons and what pricing calls a “seat” changes for revenue management reasons, those are different driver sets, and the shared entity is a coupling that will surface as a coordination cost when either driver changes.</p>
<p>The knowledge-gathering framing and the driver analysis framing are also consistent at a deeper level. Knowledge is acquired by a process because the process needs facts about the world to formulate its response. Those facts are governed by domain rules, regulations, and operational constraints — precisely the forces IVP formalizes as change drivers. A process that needs to know whether a customer’s credit score qualifies them for a loan is sensitive to credit scoring rules; if those rules change, the process changes. The two descriptions refer to the same underlying causal structure.</p>
<hr>
</section>
<section id="where-the-two-frameworks-diverge" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="where-the-two-frameworks-diverge"><span class="header-section-number">4</span> Where the two frameworks diverge</h2>
<p>The eight-question framework is primarily an elicitation tool. Given a feature description, it extracts a process structure: the types, the failure modes, the steps, and the dependency graph among the steps. For most of the questions, the extraction is fairly direct. Question 6 — which steps depend on each other — requires more judgment, and this is where the frameworks diverge in what they offer.</p>
<p>Determining step dependencies requires knowing the causal relationships among the pieces of knowledge the process is acquiring. Sometimes this is unambiguous. Validation must precede inventory checking because the inventory check needs to know what was requested. Other cases are less clear. Whether fraud detection runs in parallel with payment processing or gates it depends on the failure semantics of the system — on what the process is supposed to do if fraud is detected while payment is being processed — and on operational constraints that may not be stated in the feature description. Two engineers reading the same requirements may answer question 6 differently, and both compositions may satisfy the stated requirements while behaving differently under failure.</p>
<p>IVP does not resolve this question directly either, but it provides a lens for examining it. If fraud detection changes for regulatory compliance reasons and payment processing changes for financial settlement reasons, their driver sets are different. The question of how they should be composed then becomes a question about the protocol between two independently varying modules — a question about interface design rather than step ordering. The driver analysis does not determine whether to run them in parallel or sequentially, but it identifies that the design goal should be to minimize coupling between them, because they will change for different reasons and at different times.</p>
<hr>
</section>
<section id="what-the-two-approaches-contribute-to-each-other" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="what-the-two-approaches-contribute-to-each-other"><span class="header-section-number">5</span> What the two approaches contribute to each other</h2>
<p>Process-first design contributes an elicitation methodology: a set of questions that, applied to a feature description, extracts a process structure that can be encoded in types and compositions. The data dependency graph notation makes the dependency structure explicit in a form readable by both developers and domain experts. The three operators — Sequential, ALL, ANY — cover the structural cases that arise in practice.</p>
<p>IVP contributes an adjudication criterion: a way to evaluate proposed boundaries by asking whether the elements on each side of the boundary share change drivers. This is useful when elicitation produces ambiguous results, when a proposed boundary is challenged, or when a composition has evolved over time and its original rationale is no longer clear.</p>
<p>The two approaches are compatible and, in practice, complementary. A team doing process-first design and arriving at a contested step boundary can apply driver analysis to determine whether the proposed boundary reflects genuine causal independence in the domain. A team doing driver analysis and trying to understand what types and compositions a boundary implies can use the process-first framework to elicit the process structure from requirements.</p>
<p>Neither framework tells you what the change drivers actually are. Driver analysis consumes a driver assignment and produces a partition — it does not produce the driver assignment from a requirements description. The eight-question framework extracts a process structure from a feature description — it does not tell you at what granularity to define the steps, or when two candidate steps should be merged or split. Both frameworks shift the locus of judgment from “what structure feels right?” to “what are the causal facts about this domain?” That shift is their shared contribution. Causal facts can be investigated with domain experts and updated as understanding develops. Structural intuitions about what feels right cannot be grounded in the same way.</p>
<p>The convergence Sergiy documents across languages points toward a structural insight that both frameworks are approaching from different directions. The insight is that software boundaries should track causal independence in the domain. Process-first design operationalizes this by asking what each process needs to know. IVP operationalizes it by asking what causes each element to change. That they arrive at the same structural territory from different starting points is additional evidence that the territory is real.</p>
<hr>
<p><em>Sergiy Yevtushenko’s articles: <a href="https://dev.to/siy/the-quiet-consensus-5hhk">The Quiet Consensus</a> · <a href="https://dev.to/siy/java-backend-design-technology-a-process-first-methodology-2p4m">Java Backend Design Technology</a></em></p>
<p><em>Independent Variation Principle (Preprint): <a href="https://doi.org/10.5281/zenodo.17677315">doi.org/10.5281/zenodo.17677315</a></em></p>


</section>

 ]]></description>
  <category>architecture</category>
  <category>engineering</category>
  <category>languages</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-15-process-first-design-and-the-independent-variation-principle-two-paths-to-the-same-territory-c8j.html</guid>
  <pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Which Java Construct Should You Use? Let Change Drivers Decide</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-11-which-java-construct-should-you-use-let-change-drivers-decide-3159.html</link>
  <description><![CDATA[ 





<p>A <em>change driver</em> is anything that, when it changes, forces an element of a system to change. The Independent Variation Principle (IVP) constrains how modules and their elements relate to these drivers: elements sharing a module must have the same driver assignment, and elements with different driver assignments must live in different modules.</p>
<p>Applied to Java constructs, the lens separates <em>essential coupling</em> — the drivers the situation actually requires — from <em>accidental coupling</em> — the drivers the chosen construct drags in for reasons that have nothing to do with the situation. Picking the right construct is picking the one whose realization carries only the essential drivers. Throughout the article, “before” constructs carry accidental coupling (typically an implicit outer-instance reference, a synthetic class file, or a mutation channel the situation does not need); “after” constructs remove the accidental artifacts and keep only what the situation requires.</p>
<section id="non-static-inner-class" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="non-static-inner-class"><span class="header-section-number">1</span> Non-static inner class</h2>
<p>A non-static inner class carries an implicit <code>OuterClass.this</code> reference, generated by the compiler whether or not the inner class body ever uses it. The structural consequence is that the inner class’s driver set automatically includes all of the outer class’s change drivers. If <code>OuterClass</code> has three independent reasons to change, the inner class inherits all three.</p>
<p>Non-static inner classes are often the right choice. When the inner class’s behavior must observe live changes to the outer instance’s state — not just read its fields once, but see every write that happens between construction and use — the driver import is warranted: any change to how the outer tracks that state forces a corresponding change in the inner class. The canonical case is a fail-fast iterator over a mutable collection:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Warranted: RingBufferIterator must observe structural modification of the</span></span>
<span id="cb1-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// buffer during iteration — fail-fast, single-threaded. modCount is</span></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// outer-instance state that the iterator reads on every step; the coupling</span></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// to the outer instance is structural, not convenience.</span></span>
<span id="cb1-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> RingBuffer<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Object</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[]</span> elements<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-7">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> head<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> modCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// bumped before every structural change</span></span>
<span id="cb1-10"></span>
<span id="cb1-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Iterator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">iterator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">RingBufferIterator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-13">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-14"></span>
<span id="cb1-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>T value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-16">        modCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span>          <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// bump first, then mutate</span></span>
<span id="cb1-17">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ... store into elements[(head + size) % elements.length]</span></span>
<span id="cb1-18">        size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb1-19">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-20"></span>
<span id="cb1-21">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> RingBufferIterator <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Iterator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-22">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> cursor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-23">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> expectedModCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> modCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-24"></span>
<span id="cb1-25">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb1-26">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">hasNext</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-27">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> cursor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-28">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-29"></span>
<span id="cb1-30">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb1-31">        <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@SuppressWarnings</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"unchecked"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-32">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> T <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">next</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-33">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>modCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> expectedModCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-34">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ConcurrentModificationException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-35">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-36">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>cursor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-37">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">NoSuchElementException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-38">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-39">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> elements<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[(</span>head <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> cursor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> elements<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">];</span></span>
<span id="cb1-40">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-41">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-42"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>The <code>modCount</code> check is what makes the outer coupling load-bearing: a static iterator that received <code>elements</code>, <code>head</code>, and <code>size</code> as constructor parameters would see a frozen snapshot and could not detect mutation. Because the iterator must observe <code>modCount</code> on every <code>next()</code>, it must hold a live reference to the buffer — that is exactly what a non-static inner class provides.</p>
<p>Essential coupling: live access to the buffer’s <code>modCount</code> and backing array. Accidental coupling introduced by the non-static inner class: none — the compiler-synthesized <code>this$0</code> reference is exactly what the fail-fast check needs. A static nested class would achieve the same thing by taking an explicit <code>RingBuffer&lt;T&gt;</code> constructor parameter; the reference would be user-declared instead of compiler-synthesized, but otherwise identical. For this situation the non-static syntax is the right choice precisely because the outer-instance reference it imports is essential.</p>
<p>The case to watch for is the subset where the inner class body never references <code>OuterClass.this</code> at all — there the compiler-generated outer reference is present but the body does not exercise it, and promoting the class to <code>static</code> (or extracting it entirely) removes the reference at no other cost.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Unwarranted: Address is a plain data bundle whose definition depends</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// only on what an address is — street, city, postal code. Address does</span></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// not reference any Customer field, yet the Java compiler adds an implicit</span></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Customer.this reference to every Address instance. Java serialization</span></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// of a non-static inner class drags the enclosing Customer along; tests</span></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// that want an Address must construct a Customer first; and every</span></span>
<span id="cb2-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Address holds a reference preventing its enclosing Customer from</span></span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// being collected.</span></span>
<span id="cb2-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Customer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> email<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-12"></span>
<span id="cb2-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Address <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-14">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> street<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-15">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> city<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-16">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> postalCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-17">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-18"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-19"></span>
<span id="cb2-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Corrected: Address is a top-level record. Its definition depends on</span></span>
<span id="cb2-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// the concept of an address, not on which entity happens to have one.</span></span>
<span id="cb2-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The same Address type is reusable across Customer, Supplier, Shipment,</span></span>
<span id="cb2-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// serializable on its own, and testable without any outer instance.</span></span>
<span id="cb2-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">record</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Address</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> street<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> city<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> postalCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb2-25"></span>
<span id="cb2-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Customer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-27">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-28">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> email<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-29">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> Address address<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-30"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Essential coupling: the address schema (street, city, postal code) and whatever validation or formatting rules apply to addresses. Accidental coupling introduced by the non-static inner class: a compiler-synthesized <code>this$0</code> field pointing at a <code>Customer</code> instance, plus the constructor parameter that populates it. Address’s body never references either; the compiler emits them because the JLS requires them of every non-static inner class, regardless of whether the body uses them. The top-level record removes those artifacts entirely — no enclosing-instance field, no constructor parameter for one, no binding to any <code>Customer</code> contract. Every <code>Address</code> now depends on the essentials and nothing more.</p>
</section>
<section id="static-nested-class" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="static-nested-class"><span class="header-section-number">2</span> Static nested class</h2>
<p>A static nested class has no implicit outer reference and no coupling to the enclosing instance. Its driver set is its own. Use it when code needs to reside inside the enclosing type for visibility reasons — package-private access, logical grouping — but varies independently of the outer class. If a non-static inner class never references the outer <code>this</code>, promoting it to <code>static</code> removes the compiler-synthesized outer reference at no other cost.</p>
<p>A linked-list <code>Node</code> is the canonical case. Each node stores a value and a pointer to the next node — nothing it does depends on the particular list instance it belongs to, and promoting it from non-static to static lets the node be used across list instances, serialized independently, and tested in isolation:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Before: Node is non-static. It implicitly shares LinkedList's</span></span>
<span id="cb3-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// type parameter T, but the compiler also adds a synthetic this$0</span></span>
<span id="cb3-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// field of type LinkedList&lt;T&gt; to every node instance — even though</span></span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Node's body does not depend on the list it happens to live in.</span></span>
<span id="cb3-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">LinkedList</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-6">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span> first<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// implicitly Node of the enclosing LinkedList&lt;T&gt;</span></span>
<span id="cb3-7">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span> last<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-8"></span>
<span id="cb3-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-10">        T value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-11">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span> next<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-12"></span>
<span id="cb3-13">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>T value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">value</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-14">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-15"></span>
<span id="cb3-16">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>T value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-17"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-18"></span>
<span id="cb3-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// After: Node is static and generic in its own right. It carries</span></span>
<span id="cb3-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// only value + next; no synthetic enclosing-instance reference,</span></span>
<span id="cb3-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// no dependency on any particular list.</span></span>
<span id="cb3-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">LinkedList</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-23">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> first<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-24">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>T<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> last<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-25"></span>
<span id="cb3-26">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">static</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>E<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-27">        E value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-28">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>E<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> next<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-29"></span>
<span id="cb3-30">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Node</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>E value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">value</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-31">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-32"></span>
<span id="cb3-33">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>T value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-34"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Essential coupling: a value cell and a pointer to the next node. Accidental coupling introduced by the non-static form: a <code>this$0</code> field pointing at a specific <code>LinkedList</code> instance, and its constructor parameter. <code>Node</code>’s body needs neither — a node’s behavior does not change based on which list it happens to be in. The static form keeps only the essential artifacts. This is the choice <code>java.util.LinkedList</code> makes in the JDK source: its private <code>Node</code> is <code>static</code>, for the same structural reason.</p>
</section>
<section id="lambda" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="lambda"><span class="header-section-number">3</span> Lambda</h2>
<p>A lambda closes over exactly what its body references. Its driver set contains only the drivers of what it explicitly captures. A <code>this</code> reference inside the lambda body lexically binds to the enclosing instance, not to any identity the lambda introduces, and the enclosing instance is captured only when the body actually uses it. Lambdas are the correct form for single-operation, stateless behavior.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Both forms sit in a non-static context (an instance method on some service).</span></span>
<span id="cb4-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// batchId is a local value — captured by reference by whichever form we pick.</span></span>
<span id="cb4-3"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">long</span> batchId <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">nextBatchId</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb4-4"></span>
<span id="cb4-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Before: anonymous class — the compiler emits a synthetic class file</span></span>
<span id="cb4-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// (Outer$1.class), and because we are in a non-static context every</span></span>
<span id="cb4-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// instance also carries an implicit Outer.this field alongside the</span></span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// captured batchId, regardless of whether run() ever uses it.</span></span>
<span id="cb4-9">executor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">submit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Runnable</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-10">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb4-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-12">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">System</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">out</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"processing batch "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> batchId<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-13">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-14"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">});</span></span>
<span id="cb4-15"></span>
<span id="cb4-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// After: lambda — the compiler extracts the body into a private static</span></span>
<span id="cb4-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// method; LambdaMetafactory generates a hidden class (no .class file on</span></span>
<span id="cb4-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// disk) holding only batchId. No synthetic Outer.this field is added,</span></span>
<span id="cb4-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// because the body does not reference anything on the enclosing instance.</span></span>
<span id="cb4-20">executor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">submit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">System</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">out</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"processing batch "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> batchId<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span></code></pre></div></div>
<p>Essential coupling: the captured <code>batchId</code> value and whatever the body actually references. Accidental coupling introduced by the anonymous class: a <code>this$0</code> field pointing at the enclosing instance, emitted whether or not <code>run()</code> uses it, because the anonymous class sits in a non-static context. The lambda pays for the enclosing-instance reference only when the body actually needs it — if the body touched <code>this.someField</code>, the compiler would emit the lambda body as an instance method and bind the receiver; when it does not, as here, nothing is bound. The anonymous class binds unconditionally.</p>
<p>The JVM reflects this structurally. Lambdas are not compiled as anonymous classes. The compiler extracts the body into a private static method in the enclosing class, then emits an <code>invokedynamic</code> instruction at the lambda site. At runtime, <code>LambdaMetafactory</code> generates a hidden class — a class with no classloader-visible name, no <code>.class</code> file on disk, eligible for garbage collection when no longer referenced — that implements the target SAM interface backed by the static method. No outer instance is captured unless the body actually uses it.</p>
<p>A SAM interface (Single Abstract Method) is any interface with exactly one abstract method: <code>Runnable</code>, <code>Comparator&lt;T&gt;</code>, <code>Predicate&lt;T&gt;</code>, <code>Function&lt;A,B&gt;</code>. Any lambda can be used wherever such an interface is expected.</p>
</section>
<section id="method-reference" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="method-reference"><span class="header-section-number">4</span> Method reference</h2>
<p>A method reference (<code>ClassName::method</code>, <code>instance::method</code>) introduces no new structural unit. The referenced method already exists with its own driver set; the reference passes behavior without adding coupling. Prefer it over a delegating lambda that does nothing but forward the call:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Delegating lambda — adds nothing, obscures the reference</span></span>
<span id="cb5-2">list<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">forEach</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Method reference — explicit, no additional coupling</span></span>
<span id="cb5-5">list<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">forEach</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span></code></pre></div></div>
<p>Essential coupling: the existing <code>Logger.log</code> behavior, for each element of the list. Accidental coupling introduced by the delegating lambda: a wrapper method on the enclosing class whose only purpose is to forward <code>x</code> into <code>logger.log(x)</code>. The method reference skips the wrapper — the compiler binds <code>invokedynamic</code> directly to <code>Logger.log</code> with <code>logger</code> as the bound receiver. The wrapper artifact disappears from the compiled output, and so does anything that might make the wrapper itself a maintenance liability.</p>
</section>
<section id="anonymous-class" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="anonymous-class"><span class="header-section-number">5</span> Anonymous class</h2>
<p>An anonymous class generates a named <code>.class</code> file, always captures <code>OuterClass.this</code> in a non-static context, and carries the full infrastructure of a class definition. The situation that genuinely warrants one — needing state, multiple methods, and no desire for a named type, simultaneously — is less common in Java 25 than it was pre-lambda, though it still arises in listener-heavy and UI codebases. When it arises, a static nested class with a descriptive name communicates intent more clearly. For the common case of implementing a single-method interface with no state, a lambda is structurally correct.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Before: anonymous class — a synthetic class file plus, in a non-static</span></span>
<span id="cb6-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// context, an implicit Outer.this reference that the comparator's body</span></span>
<span id="cb6-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// does not use.</span></span>
<span id="cb6-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Comparator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> byPriority <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Comparator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb6-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compare</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Order a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Order b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Integer</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compare</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">priority</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(),</span> a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">priority</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb6-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb6-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">};</span></span>
<span id="cb6-10"></span>
<span id="cb6-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// After: lambda — same behavior, no synthetic class file, no Outer.this</span></span>
<span id="cb6-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// unless the body references it. Driver set is bounded to what the body</span></span>
<span id="cb6-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// actually uses: Order.priority() and Integer.compare.</span></span>
<span id="cb6-14"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Comparator</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>Order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> byPriority <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Integer</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">compare</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">priority</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(),</span> a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">priority</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span></code></pre></div></div>
<p>Essential coupling: the two <code>Order</code> arguments and the priority comparison. Accidental coupling introduced by the anonymous class: a <code>this$0</code> field pointing at the enclosing instance, emitted because the comparator sits in a non-static context, even though <code>compare</code> never references it. The lambda removes the enclosing-instance binding. A separate, orthogonal refactor replaces the body with <code>Comparator.comparingInt(Order::priority).reversed()</code>; that is a library-idiom choice and does not change the accidental-coupling picture — the lambda form already removed the accidental part.</p>
</section>
<section id="record" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="record"><span class="header-section-number">6</span> Record</h2>
<p>A <code>record</code> is an immutable data carrier whose driver set is bounded to the drivers of its declared components. The only things that can force a record to change are changes to the identity or semantics of those components.</p>
<p>Mutability introduces a hidden class of change drivers: anything that writes to a mutable field becomes a change driver for every reader of that field. In a shared mutable object, the driver set of every holder is infected by the write patterns of every other holder. Records eliminate this class of coupling by construction.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Mutable: any writer is a change driver for any reader</span></span>
<span id="cb7-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Money <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-3">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BigDecimal</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-4">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Currency</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-6"></span>
<span id="cb7-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Record: driver set bounded to amount and currency semantics</span></span>
<span id="cb7-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">record</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Money</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BigDecimal</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Currency</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span></code></pre></div></div>
<p>Essential coupling: an amount and a currency, and whatever operations the domain needs on them. Accidental coupling introduced by the mutable class: a mutation channel — every holder of a <code>Money</code> reference is coupled to every other holder’s write pattern, because the language lets any code with a reference rewrite the fields. Synchronization discipline exists only in convention, not in the class. The record closes the mutation channel at the language level. The fields are final, construction is canonical, and no write path exists for other holders to cause surprises on this one. The remaining coupling is exactly what the domain requires.</p>
<p>Java 25 records support compact constructors, custom accessor methods, and <code>implements</code> clauses, handling most data-carrier needs that previously required a hand-written immutable class.</p>
</section>
<section id="sealed-interface-with-pattern-matching" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="sealed-interface-with-pattern-matching"><span class="header-section-number">7</span> Sealed interface with pattern matching</h2>
<p>A sealed interface restricts which classes can implement it, making the driver space explicit and finite. An <code>instanceof</code> chain imports the driver set of every concrete type into the caller and silently becomes incomplete when a new subtype is added:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Caller's driver set grows to include the union of Γ(Circle), Γ(Rectangle), Γ(Triangle)</span></span>
<span id="cb8-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>shape <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">instanceof</span> Circle c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb8-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>shape <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">instanceof</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb8-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// New subtype added later — silently falls through</span></span></code></pre></div></div>
<p>A sealed hierarchy with exhaustive pattern matching bounds the caller’s coupling to the interface contract. The compiler enforces exhaustiveness: adding a permitted subtype requires every switch site to acknowledge it.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Caller's driver set is Γ(Shape) — the sealed interface only</span></span>
<span id="cb9-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">switch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">case</span> Circle c    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span></span>
<span id="cb9-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">case</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span></span>
<span id="cb9-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">case</span> Triangle t  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">...</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// required once Triangle is permitted</span></span>
<span id="cb9-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Java 25 pattern matching in <code>switch</code> covers deconstruction patterns, guarded cases, and primitive patterns, giving sealed hierarchies the expressive range to handle realistic variant spaces.</p>
<p>Essential coupling: the caller varies with each permitted <code>Shape</code> subtype — that is unavoidable and equally present in both forms. Accidental coupling introduced by the <code>instanceof</code> chain: the risk that a new subtype is added somewhere in the codebase and the chain silently misses it. That failure mode is not in the shape of the code itself — it is in the gap between what the compiler checks and what the source says. The sealed switch closes the gap: the compiler knows the permitted subtypes from the <code>sealed ... permits ...</code> declaration and refuses to compile the switch until every permitted subtype is either handled or covered by a <code>default</code>. A new variant forces a visible compile error rather than a silent runtime fall-through. The coupling to the variants remains essential; the accidental failure mode is gone.</p>
</section>
<section id="optional-and-result" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="optional-and-result"><span class="header-section-number">8</span> Optional and Result</h2>
<p>In plain Java without static nullability tooling, <code>null</code> is an invisible driver: callers must defensively check for it without any compile-time signal that the absent case exists. (JSpecify, the Checker Framework, and NullAway have been closing this gap at the annotation level; <code>Optional&lt;T&gt;</code> closes it at the type level, which is what follows here.) <code>Optional&lt;T&gt;</code> makes the driver explicit in the type and propagatable via <code>map</code> and <code>flatMap</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// null: absent-case driver invisible at call site</span></span>
<span id="cb10-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> city <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getAddress</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">().</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCity</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// NullPointerException possible</span></span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Optional: driver explicit, propagation compositional</span></span>
<span id="cb10-5">Optional<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ofNullable</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb10-6">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>User<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>getAddress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb10-7">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Address<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>getCity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb10-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ifPresent</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>processCity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span></code></pre></div></div>
<p>A checked exception imposes the same problem on error conditions: every intermediate caller in the stack must declare it, importing the error driver regardless of whether that caller handles it. A <code>Result&lt;T, E&gt;</code> type — not part of the JDK, but available via Vavr or straightforward to write by hand — makes the error a value. Intermediate callers propagate it via <code>map</code> and <code>flatMap</code>; only the caller that actually handles the error depends on the error type’s change drivers.</p>
<p><code>Result&lt;T, E&gt;</code> is the right tool in two situations. First, when the failure is a domain concern the caller should branch on — a payment decline, a validation failure, a lookup miss with multiple possible reasons. Second, when your module sits on a boundary and an upstream system can hand you values it contractually should not — a null where the documentation promised non-null, a response with a missing required field, a database row with a broken invariant. In both cases the failure is <em>data</em> from your module’s perspective: you cannot fix the upstream, you can only observe it and give your caller a typed value to decide with. The discriminator is trust: a boundary is the line past which you cannot assume contracts hold, and <code>Result</code> is the shape that lets the boundary absorb a violation without propagating a surprise into deeper code.</p>
<p>For bugs in your own code — invariants your module was supposed to enforce and did not, unreachable code that was reached, impossible states, broken casts — an unchecked exception remains the right form. The JVM’s exception machinery is built for this case: it preserves a stack trace at the point of violation, propagates loudly to a top-level handler, and does not force innocent intermediate callers to pattern-match on a failure that means their collaborator is broken. Wrapping a bug in a <code>Result.Failure</code> loses the stack trace, silently carries the broken state through combinator chains, and delays the crash past the point where it would have told you what went wrong. The trade-off is real: <code>Result</code> gives up stack traces, demands a dependency or a hand-rolled type, and requires the team to adopt a paradigm shift around error handling — all of which is worth it for expected failures at boundaries, and none of which is worth it for bugs you actually want to find.</p>
</section>
<section id="enum" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="enum"><span class="header-section-number">9</span> Enum</h2>
<p>An <code>enum</code> is the correct construct when the driver space itself is finite and closed, the variants carry no per-instance state, and the entire variant set is a stable fact about the domain (days of the week, HTTP method verbs, file open modes). When the variants need per-instance fields or independent evolution, a sealed interface over records is the better fit: each permitted record carries its own drivers, composition is free, and new variants can be added without touching a shared constant declaration. The dividing line is stateful variance: enums for closed stateless sets, sealed hierarchies for closed stateful ones.</p>
</section>
<section id="the-direction-of-javas-evolution" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="the-direction-of-javas-evolution"><span class="header-section-number">10</span> The direction of Java’s evolution</h2>
<p>Each major Java addition since Java 8 has moved toward constructs that reduce the gap between what the language forces you to couple to and what the structural situation requires. Lambdas gave single-operation behavior a minimum-footprint form. <code>Optional</code> made absence drivers explicit in the type. Records eliminated mutable-state coupling. Sealed interfaces bounded the driver space to the declared set. Pattern matching made exhaustive dispatch over sealed driver spaces compiler-enforced. Hidden classes removed the last artifact of the anonymous-class era from lambda compilation.</p>
<p>Read through IVP’s lens, the direction is legible: each addition gives developers a way to express a structural situation with a narrower set of compiled artifacts than the construct it replaces, which is the same thing as saying less accidental coupling. Whether every JEP was deliberately motivated by coupling analysis is beside the point — the effect, observed across the language’s evolution, is that the gap between what the constructs force you to couple to and what the situation requires has narrowed. Framework and ecosystem realities push in the other direction: JPA entities still require mutability and no-arg constructors, reflection-based serialization libraries still call setters, Spring-managed beans still participate in proxy machinery that forbids <code>final</code>. The language’s direction is visible, but the ecosystem constrains which parts of it a given codebase can adopt. The practical split in a typical Java 25 service is records for value objects and DTOs, sealed interfaces for domain hierarchies the developer fully controls, and mutable classes for entities and beans the framework manages.</p>
</section>
<section id="the-decision" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="the-decision"><span class="header-section-number">11</span> The decision</h2>
<p>The question is always the same: does this construct force more coupling than the situation requires? The answer determines the choice. If the code needs the outer instance’s state, a non-static inner class is warranted. If it needs state or multiple methods but not the outer instance, a static nested class is correct. If it needs neither, a lambda is the right form. Records replace mutable data carriers. Sealed interfaces replace open hierarchies when the variant space is closed. <code>Optional</code> and <code>Result</code> replace invisible null and exception drivers with explicit types. Each substitution is structural, and the structure is what determines how much the code costs to change.</p>


</section>

 ]]></description>
  <category>languages</category>
  <category>engineering</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-11-which-java-construct-should-you-use-let-change-drivers-decide-3159.html</guid>
  <pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Three Questions Before You Add a Microservice — and Why They All Collapse Into One</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-07-three-questions-before-you-add-a-microservice-and-why-they-all-collapse-into-one-3op1.html</link>
  <description><![CDATA[ 





<p>A recent <a href="https://www.linkedin.com/posts/johncrickett_before-you-add-another-microservice-ask-activity-7446942307318198272-1643?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAEuBW_YBL9MhmpcmMr-e02KLNSfUbxuKQqY">LinkedIn post from John Crickett</a> has been making the rounds. It offers three questions to ask before adding another microservice:</p>
<ol type="1">
<li>Does this need to be a service?</li>
<li>Does this need to be its own service?</li>
<li>Does this need to be its own service right now?</li>
</ol>
<p>Crickett credited Craig Ferguson, the comedian, for the format — Ferguson has a bit about three questions a man should ask himself before he speaks. The post is in that register: deliberately light, deliberately compressed, the kind of aphorism a practitioner can carry in their head into a Monday-morning design meeting. Crickett’s questions have spread because they work. They surface the right conversation in teams that might otherwise never have it.</p>
<p>What I want to do is unpack what the aphorism is compressing. My claim isn’t that Crickett’s questions are wrong or incomplete — it’s that they’re pointing very precisely at something a formal theory of modularization can name. And the something they’re pointing at is more unified than the three-part structure suggests: the three questions turn out to be three natural-language phrasings of <strong>one</strong> structural question. Seeing why is, I think, the most interesting thing you can do with the post.</p>
<p>Let me walk through it.</p>
<section id="the-criterion-same-drivers-together-different-drivers-apart" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-criterion-same-drivers-together-different-drivers-apart"><span class="header-section-number">1</span> The criterion: same drivers together, different drivers apart</h2>
<p>I’ll use the <strong>Independent Variation Principle (IVP)</strong> as the lens. You don’t need to have read the formalization to follow this article. The idea in plain words is:</p>
<blockquote class="blockquote">
<p>Every element in a system — every function, every class, every module — has a set of <strong>change drivers</strong>. A change driver is anything that, when it changes, forces that element to change. Requirements, domain rules, regulations, performance targets, deployment constraints — any cause of future modification.</p>
<p>The principle says: group together elements that share the exact same set of change drivers, and separate elements whose sets of change drivers differ.</p>
</blockquote>
<p>That’s it. Once the driver sets are fixed, the <em>comparison</em> is binary: two elements either have the same set of change drivers or they don’t. No gradient, no threshold, no “similar enough.” Same set → together. Different set → apart.</p>
<p>That binary comparison is what distinguishes this principle from SRP’s “one reason to change” or CCP’s “things that change together.” Both of those formulations leave the comparison itself underspecified — <em>reason</em> and <em>change together</em> admit interpretations a team can argue about indefinitely. IVP shifts the imprecision: the comparison step becomes mechanical, but the <em>driver discovery</em> step — figuring out what’s actually in the driver set for a real element — still requires deep engineering judgment. The principle doesn’t make the hard work disappear. It moves it from “how do we compare these modules?” to “what are the actual causes of change for these elements?”, which is the question domain expertise can answer.</p>
<p>We’ll come back to the discovery step. The point for now is that once the inputs are fixed, the answer follows. That’s a stronger guarantee than the classical principles offer, even if it isn’t the magic-wand guarantee absolute decidability would suggest.</p>
</section>
<section id="question-2-first-because-its-the-cleanest" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="question-2-first-because-its-the-cleanest"><span class="header-section-number">2</span> Question 2 first, because it’s the cleanest</h2>
<p>Let me take the questions out of order and start with Q2: “Does this need to be its own service?”</p>
<p>Read literally, Q2 is a yes-or-no question. “Its own” means separate from existing services — a binary property. And that maps directly onto the principle’s criterion:</p>
<blockquote class="blockquote">
<p>Is there an existing service whose set of change drivers equals the set of change drivers for this new capability?</p>
</blockquote>
<p>If yes: the new capability belongs inside that existing service from a structural standpoint. Putting them in separate services would mean two services that must change in lockstep whenever any of their shared drivers change — which is the structural shape of a distributed monolith. Other constraints (security boundaries, regulatory isolation, organizational ownership) may still justify keeping them apart, but those would be explicit trade-offs against the structural ideal, not refutations of it.</p>
<p>If no: the new capability belongs in a separate module from a structural standpoint. Keeping it inside an existing service would mean that service now has elements changing for different reasons, tangling concerns that should be independent.</p>
<p>Q2, read structurally, is asking exactly this. It doesn’t <em>say</em> “change drivers,” but the question it poses is the one the principle formalizes. What it lacks is a method for answering — it tells you to ask the question but doesn’t tell you how to compute the answer. We’ll come back to that.</p>
</section>
<section id="question-3-the-temporal-illusion" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="question-3-the-temporal-illusion"><span class="header-section-number">3</span> Question 3: the temporal illusion</h2>
<p>Now Q3: “Does this need to be its own service <strong>right now</strong>?”</p>
<p>This looks like it adds a new dimension — timing — to Q2. On closer inspection, it doesn’t. It adds nothing the principle can see.</p>
<p>Here’s why. The principle evaluates a module structure against the <em>current</em> set of change drivers. It has no temporal dimension. It doesn’t care about drivers you imagine will exist in the future, or drivers you had last year, or drivers you might have if the product succeeds. It cares about the drivers that actually cause modification <em>now</em>, in the system as it exists.</p>
<p>So “right now” is either redundant or incoherent:</p>
<ul>
<li><strong>Redundant</strong> if the asker means “given the drivers we actually have today.” That’s what the principle already assumes. Q3 reduces to Q2.</li>
<li><strong>Incoherent</strong> if the asker means “given drivers we imagine might emerge later.” The principle doesn’t accept imagined future drivers as inputs. If you don’t have evidence that a driver exists and applies to these elements, it isn’t in the set, and speculating about it doesn’t put it there.</li>
</ul>
<p>There’s a third reading: “should we do this decomposition work in this sprint versus later.” That’s a project scheduling question, and it has nothing to do with modularization theory. You might defer the work because you’re busy, because the team is tired, because another priority dominates — those are real reasons, but the principle says nothing about them.</p>
<p>So Q3 either collapses into Q2 (structural reading) or dissolves into something outside the theory’s scope (scheduling reading). Either way, it adds no new structural content.</p>
<p>There is, however, something the “right now” phrasing accidentally brushes against, and it’s worth saying explicitly — not as part of Q3, but as a warning about the “drivers we imagine might emerge later” reading above. IVP has a consequence sometimes called the <strong>knowledge theorem</strong>: the correct partition reflects the causal knowledge you actually have about the system’s current drivers. When you add elements designed to serve drivers that don’t yet exist — speculative extensibility points, plugin systems waiting for plugins, abstractions anticipating requirements that haven’t arrived — those elements don’t share drivers with anything real in the system. They land in their own cells, structurally disconnected from the rest, and they push real elements into shapes that accommodate hypothetical concerns rather than actual ones. The partition the principle produces over the enlarged element set is structurally incorrect relative to the system’s actual causal reality.</p>
<p>That’s a structural claim, not a moral verdict. The principle isn’t saying “speculative design is bad.” It’s saying that a partition built on drivers that haven’t materialized doesn’t match the partition the system’s actual change history will reward, and that mismatch shows up as elements getting touched together for reasons the structure didn’t anticipate. Whether the cost of that mismatch outweighs the cost of waiting until the drivers are real is an engineering judgment IVP doesn’t make for you. What IVP does say is that the cost is structural and not free. There’s an important exception: extensibility justified by <em>currently observed</em> drivers — plugin systems for which plugins already exist, abstractions over already-shipping variations — is a different case. Those drivers are real, the elements that serve them have a place in the partition, and the principle has no objection.</p>
<p>So if Q3 is doing any work beyond Q2, it’s this: don’t import imagined future drivers into a decomposition you’re making today. Decide based on what you actually know causes change in the system as it stands.</p>
<p><strong>Q3 collapses into Q2.</strong></p>
</section>
<section id="question-1-the-technology-trap" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="question-1-the-technology-trap"><span class="header-section-number">4</span> Question 1: the technology trap</h2>
<p>Now Q1: “Does this need to be a service?”</p>
<p>There’s an intuitive reading of Q1 that makes it look orthogonal to the principle — that it asks about <em>realization technology</em> (service vs.&nbsp;library vs.&nbsp;in-process module) rather than about module boundaries. On this reading, the principle tells you the logical partition, and then a separate engineering decision picks how each module is deployed. Modularization and deployment are treated as two layers: first decide what goes with what, then decide how to ship it. It’s a sensible-looking division of labor, and it’s something close to the default mental model in much architecture writing.</p>
<p>I want to argue it’s incomplete, and the gap it leaves is the one Q1 is actually pointing at.</p>
<p>The gap lies in what counts as a change driver. The two-layer reading tacitly restricts the driver set to <em>functional</em> drivers — business rules, domain concepts, user-facing requirements — and treats everything else as “non-functional” concerns that live downstream. But that split is a convention, not a principle. A change driver, in IVP’s sense, is anything whose change forces a corresponding modification of the element. And architectural quality requirements clearly cause modifications:</p>
<ul>
<li>“Must scale independently to 10,000 requests per second.” If that target shifts — up to 100,000, or down to 100 — caching strategy, concurrency model, data structures, and possibly the storage layer have to change. It’s a driver.</li>
<li>“Must survive the failure of neighboring components.” If the failure-tolerance target changes, retry logic, circuit breakers, state replication, and idempotency guarantees have to change. It’s a driver.</li>
<li>“Must be deployable without coordinating with team X.” If that independence requirement changes, interface contracts, versioning strategy, and backward-compatibility code have to change. It’s a driver.</li>
</ul>
<p>These satisfy the definition of a driver in the same sense as “the tax code might change” or “the pricing model might be revised” do. There’s no principled way to admit one kind and exclude the other.</p>
<p>But just admitting architectural-quality drivers into the set isn’t by itself what reshapes the partition. There’s an intermediate step that’s easy to skip past: a quality requirement doesn’t act on the system as an abstract force — it acts through <em>concrete elements that implement it</em>. A scalability target above what a single instance can handle isn’t satisfied by wishing; some element has to actually distribute the work. A failure-isolation target isn’t satisfied by intent; some element has to actually contain failures. A deployment-independence requirement isn’t satisfied by good will; some element has to actually broker compatibility. These elements are real components with their own implementations and their own change profiles. They aren’t optional decorations on the functional code; they’re the concrete carriers of the quality requirements, and the quality requirements can’t act on the partition without going through them.</p>
<p>The interesting question is what driver sets those carrier elements have. A circuit breaker’s behavior is shaped primarily by the failure modes it guards against, the observability it reports to, and the retry policies it coordinates with. Its implementation responds to changes in those drivers, not to changes in the business rules of the service it fronts. (There’s a real edge case here: a circuit breaker whose failure-classification logic is driven by business semantics — “treat this as a failure only for premium customers” — does have business drivers in its set. In that case the principle would correctly group it with the business logic, not with other infrastructure. The general claim isn’t that infrastructure drivers and functional drivers never overlap; it’s that they often don’t, and where they don’t, the partition reflects that.) A caching layer’s drivers are cache-invalidation semantics and memory pressure, not the functional logic of what’s being cached. When the typical case holds — when the carrier element’s drivers are genuinely distinct from the functional element’s — the principle separates them into different cells, and the resulting partition is different from the one functional drivers alone would produce.</p>
<p>This is where the service-versus-library choice connects to the partition rather than sitting after it. The principle determines the <em>logical</em> module boundary: which elements share a driver set and therefore belong in the same cell. Whether that cell can be realized as an in-process module is a separate question, answered by whether the drivers in the cell are <em>operationally compatible</em> with sharing a process. A driver that requires independent failure containment is not operationally compatible with in-process coexistence — failures inside one process take everything in that process with them, so the failure-isolation driver can’t be made actionable inside a shared process. A driver that requires independent horizontal scaling is not operationally compatible with in-process coexistence — you can’t scale one component of a process without scaling the whole process. These operational-compatibility judgments aren’t part of IVP’s formal apparatus; they’re engineering facts about runtimes, processes, and networks. But they connect <em>directly</em> to the partition: when a cell’s drivers include any whose operational requirements rule out shared-process realization, the only realization that lets all the drivers in the cell be satisfied at once is a separate deployable unit.</p>
<p>So the “is this a service?” question is really asking: <em>when we account for the elements that carry the system’s quality requirements, and we let the principle partition over the enlarged element set, does this element land in a cell whose drivers — functional and quality — collectively rule out sharing a process with anything else?</em> That’s the same shape as Q2 — is there an existing module this element’s driver set matches? — but evaluated over the full driver set rather than just the functional one. The realization decision isn’t downstream of the partition; it’s the operational consequence of <em>which</em> drivers are in the partition’s cells, evaluated against engineering facts about how those drivers can actually be served.</p>
<p><strong>Q1 collapses into Q2.</strong></p>
</section>
<section id="one-question-not-three" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="one-question-not-three"><span class="header-section-number">5</span> One question, not three</h2>
<p>Here’s where we land. Crickett’s three questions, read structurally, aren’t three independent checks. They’re three natural-language phrasings of the same underlying question:</p>
<blockquote class="blockquote">
<p>Taking into account the full set of change drivers for this element — functional drivers and quality drivers alike — does its set of drivers equal that of some existing module? If yes, the structural answer is to merge. If no, the structural answer is to separate, and which realization (in-process module, library, separate service) the separated module needs is determined by which drivers are in its cell and how those drivers can be operationally served.</p>
</blockquote>
<p>That’s the whole decision, once the inputs are fixed. One question, one criterion, binary comparison. The principle’s contribution is making the question precise: given an agreed-upon driver assignment, the answer is determined.</p>
<p>That precision is the gap classical principles haven’t quite closed. Parnas, in his 1972 paper on decomposing systems into modules, came close — his “design decisions likely to change” is essentially a change driver in everything but the formal apparatus. The intuition was right; what was missing was the explicit treatment of driver-set equality as the criterion. SRP points at separation by reason-to-change but leaves “reason” undefined. Separation of Concerns points at orthogonal grouping but leaves “concern” undefined. CCP correctly targets co-variation but doesn’t distinguish causal co-variation (shared drivers) from accidental co-modification (drivers that happened to fire together). All three are pointing at something genuine. What IVP adds is the formal apparatus that makes the criterion precise enough for two engineers who disagree to identify exactly <em>what</em> they disagree about — which driver applies to which element — rather than talking past each other about “reasons” and “concerns.”</p>
</section>
<section id="but-heres-the-catch" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="but-heres-the-catch"><span class="header-section-number">6</span> But here’s the catch</h2>
<p>The principle makes the question <em>well-posed</em> and <em>decidable</em>. It does not make the question <em>answerable without expertise</em>.</p>
<p>This is the part that matters for practitioners, and it’s the part I want to be careful about. The principle consumes a driver set and produces a partition. It does <strong>not</strong> produce the driver set. Identifying what actually belongs in the driver set for a real system — which architectural qualities are genuine drivers versus current accidental properties, which functional requirements are real causes of future change versus one-time decisions, which deployment constraints are inherent versus incidental — is empirical work. It requires:</p>
<ul>
<li><strong>Performance engineering expertise</strong> to know which scaling drivers are real. Splitting a service “for independent scalability” when nothing in the system’s actual or projected load suggests the element will ever need independent scaling means splitting on a driver that isn’t there. The partition looks principled, but the input it rests on is imagined.</li>
<li><strong>Reliability engineering expertise</strong> to know which failure-isolation drivers are real. Blast-radius concerns are drivers when there’s a credible failure mode that actually needs to be contained; in their absence, they’re a split justified by a driver the system doesn’t have.</li>
<li><strong>Capacity planning and load analysis</strong> to distinguish current properties from future causes of change. “It runs fast enough today” is not a driver. “It must maintain sub-10ms latency as traffic grows ten-fold over the next two years” is.</li>
<li><strong>Deployment and organizational analysis</strong> to know which independence drivers are real. Team-autonomy is a driver when teams genuinely need to deploy independently; it isn’t when the organization doesn’t actually work that way.</li>
<li><strong>Domain knowledge</strong> to identify the functional drivers without confusing them with implementation choices.</li>
</ul>
<p>None of that is the principle. The principle has no method for deciding whether “must scale to 10K RPS independently” is a real driver or an imagined one. That determination comes from engineering disciplines IVP doesn’t subsume.</p>
<p>The honest picture is: <strong>the principle plus quality knowledge together answer the question Crickett is pointing at. Neither alone does.</strong> Quality knowledge without the principle gives you a list of architectural concerns but no principled way to combine them into a partition. The principle without quality knowledge gives you a partition machine with no inputs. Both are common in isolation; the combination is rarer than it should be, and that’s where the leverage is.</p>
</section>
<section id="a-worked-example-10000-users-and-four-servers" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="a-worked-example-10000-users-and-four-servers"><span class="header-section-number">7</span> A worked example: 10,000 users and four servers</h2>
<p>Let me make this concrete, because the interaction between capacity math and the principle is where a lot of confusion lives.</p>
<p>Suppose you’re told: “this system must serve 10,000 concurrent users on hardware X.” A natural question is: <em>does the principle tell you how to modularize this?</em> The honest answer is that the principle, on its own, has nothing to say about the number 10,000, or about hardware X, or about how many servers you’ll end up running. It has no model of throughput, queuing, concurrency, or hardware characteristics. If you ask it “how many servers do I need?” it has no answer, not because it’s incomplete, but because that’s not a modularization question. It’s a capacity-planning question, and capacity planning is a separate engineering discipline with its own methods: load modeling, benchmarking, queuing analysis, back-of-envelope arithmetic against hardware specs.</p>
<p>So where does a number like “four servers” come from? From that capacity calculation, done entirely outside the principle. You measure or estimate per-request cost on hardware X, you multiply by concurrency, you apply a safety margin, you get a count. Maybe it’s four. Maybe it’s fourteen. The principle doesn’t care and couldn’t produce the number if it tried.</p>
<p>But now something important happens, and this is where the principle re-enters. The capacity calculation has produced <em>knowledge about the system</em> — structural knowledge, not just a number. You now know:</p>
<ul>
<li>A single instance cannot handle the required load.</li>
<li>The workload must be distributable across multiple instances running in parallel.</li>
<li>Distribution requires elements that didn’t previously exist: a way to route requests across instances, a way to share or partition state, a way to coordinate on things that can’t be freely replicated, a way to detect and recover from instance failure.</li>
</ul>
<p>Those “requires” introduce new elements into the system. A load balancer. A session store or sticky-routing scheme. A distributed lock or a partition-key strategy. A health-check mechanism. A failure handler. None of these existed in the pre-analysis system. They exist now because the capacity knowledge forced them into existence.</p>
<p>And here’s the key point: each of those new elements carries its own driver set, and those drivers are typically distinct from the drivers of the business logic they serve. They’re genuinely new drivers, brought into the system by the structural decisions the capacity analysis forced.</p>
<ul>
<li>The load balancer’s drivers are the routing strategy, the health-check protocol, the traffic patterns it has to handle. They are not the business rules of the requests passing through it.</li>
<li>The session store’s drivers are the consistency model, the eviction policy, the replication strategy. They are not the domain rules that produced the sessions.</li>
<li>The partition-key strategy’s drivers are the skew characteristics of the key space and the rebalancing cost. They are not the semantics of the partitioned entities.</li>
</ul>
<p>Once these elements are added to the system, the principle does its usual work over the enlarged element set. Functional elements group with functional elements that share their functional drivers. Infrastructure elements group with infrastructure elements that share <em>their</em> drivers. Where a functional element genuinely participates in an infrastructure driver — say, a business rule whose modification is itself triggered by scaling constraints because it encodes a degradation policy — the principle correctly groups it with the infrastructure cluster rather than its original functional one. The partition is recomputed over a richer set of inputs, and the result is a different modularization than functional drivers alone would give.</p>
<p>Concretely, the resulting cells look something like this:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 8%">
<col style="width: 31%">
<col style="width: 60%">
</colgroup>
<thead>
<tr class="header">
<th>Cell</th>
<th>Representative drivers</th>
<th>Operational compatibility with other cells</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>App logic</td>
<td>Domain rules, business workflows, validation logic</td>
<td>Compatible with replication; not compatible with sharing a process with the load balancer (cyclic)</td>
</tr>
<tr class="even">
<td>Load balancing</td>
<td>Routing strategy, health-check protocol, traffic patterns</td>
<td>Cannot live inside an instance it balances</td>
</tr>
<tr class="odd">
<td>Session / state coordination</td>
<td>Consistency model, eviction policy, replication strategy</td>
<td>Must outlive any single instance — independent failure domain</td>
</tr>
<tr class="even">
<td>Failure detection</td>
<td>Health-check semantics, timeout policies, recovery rules</td>
<td>Must survive failures of what it monitors</td>
</tr>
</tbody>
</table>
<p>The interesting move happens in the right column. Each cell has, in addition to its driver set, an operational profile: a set of facts about whether the drivers in the cell <em>can</em> be served by sharing a process with another cell. The load balancer cell can’t share a process with the app logic cell it balances, because a load balancer running inside one of the app instances can’t distribute requests across the four of them — the routing driver becomes unactionable. The session coordination cell can’t share a process with any single app instance, because the consistency-and-replication driver requires it to outlive that instance. These aren’t claims IVP itself derives. They’re engineering facts about runtimes — what a process is, what it means for one process to fail, how routing works. The principle determines that the cells exist as distinct modules; the operational facts determine that some of those modules cannot be realized in-process and must be separate deployable units.</p>
<p>The app logic cell, now freed from the concurrency and routing concerns that have been factored into their own modules, becomes replicable precisely because the concerns that would have prevented replication are no longer tangled into it.</p>
<p><strong>The chain, in order:</strong></p>
<ol type="1">
<li><strong>Capacity math</strong> (outside the principle): 10,000 users on hardware X cannot be served by a single instance.</li>
<li><strong>Element addition</strong> (outside the principle, prompted by step 1): the system must now contain load balancing, state coordination, failure detection, and whatever else horizontal scaling requires.</li>
<li><strong>Driver attribution</strong> (outside the principle, requires engineering judgment): each new element’s drivers are identified — routing drivers for the balancer, consistency drivers for the store, health drivers for the detector.</li>
<li><strong>Repartition</strong> (this is the principle’s job): the enlarged element set and enlarged driver set are fed in; the principle produces a new partition separating business logic from infrastructure, routing from state, health checking from everything else. The realization of each cell isn’t a later decision — it’s the operational consequence of which drivers ended up in the cell, evaluated against the engineering facts about how those drivers can actually be served. Cells whose drivers can’t all be served at once inside a shared process need to be separate deployable units, and that follows from step 4 directly.</li>
<li><strong>Deployment topology</strong> (outside the principle, back to capacity math): the separate deployable unit for app logic runs on four instances, because that’s what the original capacity analysis said.</li>
</ol>
<p>Steps 1, 2, 3, and 5 are performance engineering and architectural judgment. The principle has no access to any of them. Step 4 follows deterministically once the elements, the driver attributions, and the engineering facts about which drivers can coexist in a shared process are all in place. The principle does the partition work; the engineering facts decide which cells can be in-process and which can’t.</p>
<section id="two-distinct-kinds-of-knowledge" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="two-distinct-kinds-of-knowledge"><span class="header-section-number">7.1</span> Two distinct kinds of knowledge</h3>
<p>Notice that “there must be a separate service deployed onto four servers” is actually two different claims fused into one sentence, and they enter the principle through different doors.</p>
<p>“There must be a separate service” is a <em>structural</em> claim about elements and drivers. It says: there exist elements whose drivers (combined with engineering facts about runtimes) cannot all be served inside a shared process — they need independent deployment, independent scaling, or an independent failure domain. Once you know that, the principle takes over and propagates the structural consequence: those elements form a cell whose realization is a separate deployable unit. The principle doesn’t <em>discover</em> the underlying drivers, but it <em>consumes</em> them and propagates their implications through the partition.</p>
<p>“Deployed onto four servers” is a <em>quantitative</em> fact about capacity and resource allocation. It is not a structural claim about modularization at all. The principle has nothing to say about whether the number is four, forty, or four hundred. You can change the number tomorrow without touching a single module boundary — you adjust a deployment config, you don’t re-modularize. But you can’t quietly change “separate service” to “in-process library” without reshaping the partition, because the drivers that put it in its own cell haven’t gone away.</p>
<p>So the key knowledge, from the principle’s point of view, is the <em>structural</em> knowledge. The quantitative part is what made the structural knowledge visible in the first place — capacity math is what revealed that horizontal scaling was necessary — but once the structural fact is established, the specific instance count drops out of the modularization question entirely. If a genie whispered “this system will need to run horizontally scaled” without telling you the number, the principle could already produce the correct partition. If the same genie whispered “this system will need four servers” without telling you <em>why</em>, the principle couldn’t do anything with the information — it has no slot for a raw count.</p>
<p>This is the layering the honest answer requires. Capacity math produces numbers and reveals structural necessities. The principle consumes the structural necessities and produces the partition. Operations consumes the partition <em>and</em> the original numbers to decide how many instances of each module run where. Each layer does its own job. When a single mental model tries to carry all three at once, the layers blur, and that blurring is where a lot of microservice sizing confusion comes from.</p>
</section>
</section>
<section id="what-the-three-questions-are-compressing" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="what-the-three-questions-are-compressing"><span class="header-section-number">8</span> What the three questions are compressing</h2>
<p>The reason Crickett’s three questions work is that they compress, in a form practitioners can carry into a meeting, the structural reasoning the principle does formally. That kind of compression is valuable in its own right — in fact it’s what good practitioner writing <em>does</em>, and it’s what most academic writing fails at. The three questions don’t try to do what IVP does; they’re a different artifact aimed at a different job. They’re the question you ask in the hallway. IVP is what you reach for when the hallway question produces a disagreement neither of you can resolve.</p>
<p>Read this article’s argument as unpacking the compression rather than replacing the questions. The reason all three “collapse into one” isn’t that the original three are redundant — it’s that they’re three useful angles on a single underlying question that, viewed structurally, has one shape. Ferguson’s three questions before you speak presumably unpack into a single underlying question too: <em>should I say this?</em> That doesn’t make Ferguson’s three-part formulation useless; it makes it a compression worth understanding.</p>
<p>What the formal lens adds, beyond the compression, is a way to make the question precise enough to settle disagreements. Two engineers asking “does this need to be its own service?” can give different answers and have no shared ground for resolution. Two engineers asking “does this element’s driver set match the driver set of any existing module?” can, in principle, identify exactly where they disagree — which driver one of them is including that the other isn’t, or which element they’re attributing it to. The classical principles SRP, SoC, and CCP each point at related intuitions and run into the same gap when disagreement arises: their core terms aren’t sharp enough to localize where the disagreement actually lives. Parnas was already most of the way there in 1972 with “design decisions likely to change”; what was missing was the formal step from that intuition to driver-set equality as the partition criterion.</p>
</section>
<section id="the-practical-takeaway" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="the-practical-takeaway"><span class="header-section-number">9</span> The practical takeaway</h2>
<p>Next time you face a “should this be a service?” decision, Crickett’s three questions are a perfectly good prompt — they’ll surface the conversation. When they surface a disagreement that the conversation can’t resolve, the underlying structural question they’re pointing at is this:</p>
<blockquote class="blockquote">
<p>What are the change drivers for the elements I’m considering? Include functional drivers, scaling drivers, reliability drivers, deployment-independence drivers, team-autonomy drivers — anything that can genuinely cause these elements to be modified. Then ask: is there an existing module whose set of change drivers matches this one? If yes, the structural answer is to merge. If no, the structural answer is to separate — and which realization (in-process module, library, separate service) the separated module needs is determined by which drivers are in its cell and how those drivers can actually be served operationally.</p>
</blockquote>
<p>Be honest about what you know and don’t know. If you can’t name the quality drivers for an element, you don’t have enough information to decide yet. The principle has no “wait until you know” rule — it just has nothing to evaluate when the inputs aren’t there. Going and finding out is the right move. Acting on guesses you haven’t surfaced as guesses is the move that goes wrong silently.</p>
<p>A few honest scope notes. This article has been talking about server-side, request/response systems with a horizontal-scaling story. The same principle applies elsewhere — to brownfield migrations, FaaS, batch and streaming systems, regulated environments where compliance imposes its own boundaries — but the <em>inputs</em> (what counts as a driver, how the operational compatibility column gets filled in) shift with the context. In a brownfield migration, the order in which you act on the partition is constrained by data and dependency reality; the principle tells you the target, not the path. In regulated industries, compliance boundaries can force separations that aren’t visible from drivers alone — those should be modeled as static constraints on realization, not bolted onto the partition. None of these are refutations; they’re places where applying the principle requires specific quality knowledge the article hasn’t tried to provide.</p>
<p>That’s the picture. Three questions, one underlying criterion, and a reminder that no theory of modularization can substitute for knowing your domain and your quality requirements. The theory gives you a precise question; your expertise gives you the inputs; the answer follows. You need both halves.</p>
<hr>
</section>
<section id="references" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="references"><span class="header-section-number">10</span> References</h2>
<ul>
<li>Loth, Y. (2025). <em>The Independent Variation Principle</em>. Zenodo. <a href="https://zenodo.org/records/18024111">https://zenodo.org/records/18024111</a></li>
<li>Loth Y. (2026). <em>IVP as a Meta-Principle: A Unifying Software Architecture Theory</em>. Zenodo <a href="https://zenodo.org/records/18748561">https://zenodo.org/records/18748561</a></li>
</ul>


</section>

 ]]></description>
  <category>architecture</category>
  <category>design</category>
  <category>modularization</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-07-three-questions-before-you-add-a-microservice-and-why-they-all-collapse-into-one-3op1.html</guid>
  <pubDate>Tue, 07 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Does Formal IVP Modularization Lead to Speculative Fragmentation?</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-04-02-does-formal-ivp-modularization-lead-to-speculative-fragmentation-3olc.html</link>
  <description><![CDATA[ 





<p>A thoughtful comment on my recent LinkedIn post raised three concerns about the Independent Variation Principle that deserve a serious answer.</p>
<p>The concerns are, in essence: that proactive separation by change driver risks massive over-fragmentation; that the existence of a driver does not entail its activation with relevant probability; and that to eliminate subjectivity, the change driver must become a constant or be determined with high probability.</p>
<p>I take these concerns seriously, because they point to the exact place where IVP must distinguish itself from the Single Responsibility Principle.</p>
<p>If IVP inherits SRP’s problems, the formal apparatus adds overhead without benefit. It does not inherit them, and the reasons are structural.</p>
<section id="ivp-does-not-over-fragment" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="ivp-does-not-over-fragment"><span class="header-section-number">1</span> IVP does not over-fragment</h2>
<p>The concern is valid against SRP. SRP is a separation-only criterion: every new “reason to change” creates another module boundary, with no counterweight. The more reasons you discover or speculate about, the more you split. Over-fragmentation is a real and well-documented consequence of strict SRP application.</p>
<p>IVP does not work this way. It has four axioms, and two are directly relevant here. IVP-3 separates elements with different change driver assignments into different modules. IVP-4 <em>unifies</em> elements with the same change driver assignment into the <em>same</em> module. The result is a partition: exactly as many modules as there are distinct driver sets, no more, no fewer. Over-fragmentation in the structural sense — splitting co-varying elements across separate modules — is ruled out by IVP-4, which forces co-varying elements back together.</p>
<p>SRP operates at the class level, where no unification counterpart exists. Martin’s Common Closure Principle (CCP) addresses unification at the package level, but it is a separate principle operating at a different granularity, with the same definitional problem: “change for the same reason” is as undefined as SRP’s “reason to change.”</p>
<p>IVP provides both separation and unification at any granularity, with a single formal criterion. That is why strict SRP application tends toward class explosion, while IVP’s partition constraint structurally prevents it.</p>
<p>What about speculative drivers — drivers that <em>might</em> emerge in the future but have no current evidence? IVP’s answer is not “separate just in case.” It is the opposite. A speculative driver has no knowledge slice: there is no domain knowledge to embody, because the driver does not yet exist in the system’s causal structure. The distinction is not about likelihood but about current causal existence.</p>
<p>The tax authority is a driver because it currently governs elements in the system — tax rules are already encoded, and the authority can issue changes that force modifications to those elements, whether or not it does so this year.</p>
<p>A regulation that does not yet exist governs no current elements and therefore has no knowledge slice to separate.</p>
<p>When it comes into existence and begins governing elements, it becomes a driver at that point, and the decomposition is updated accordingly. Assigning a speculative driver to existing elements introduces spurious inequality in the driver assignments, splitting elements that currently co-vary for no reason.</p>
<p>This <em>decreases</em> the quality of the decomposition.</p>
<p><strong>IVP formally prescribes operating on the current driver structure.</strong> The same logic that motivates YAGNI in feature development applies structurally here: speculative drivers are not merely unnecessary boundaries — they actively degrade the decomposition by introducing spurious splits.</p>
</section>
<section id="drivers-are-not-predictions" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="drivers-are-not-predictions"><span class="header-section-number">2</span> Drivers are not predictions</h2>
<p>A change driver is not a prediction that change will happen.</p>
<p>It is an identification of what <em>could cause</em> change within the system’s operational domain — the causal structure that governs how domain knowledge enters and evolves in the system.</p>
<p>The tax authority exists as a source of potential change whether or not it updates tax rates this year. A database technology is a separate source of variation from a messaging system whether or not you plan to replace either one.</p>
<p>IVP does not ask “how likely is this change?” It asks “if this change happened, what would be forced to change with it?” That is a question about causal propagation structure, not about the likelihood of the triggering event.</p>
<p>A driver that rarely activates does not make its boundary wasteful. All module boundaries carry some fixed cost — cognitive overhead, interface ceremony, build structure — but the cost of maintaining a correct boundary for a dormant driver is small and predictable.</p>
<p>The cost of <em>not</em> having the boundary when the driver activates is large and unpredictable: the change propagates through a structure that never accounted for the variation, touching modules that have no reason to be involved.</p>
<p>The alternative — merging modules because “it probably won’t change” — saves little in the meantime and pays the full propagation cost when it does.</p>
</section>
<section id="ivp-makes-subjectivity-empirical" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="ivp-makes-subjectivity-empirical"><span class="header-section-number">3</span> IVP makes subjectivity empirical</h2>
<p>This concern rests on the assumption that identifying change drivers introduces a new subjectivity problem.</p>
<p>In practice, every modularization approach already demands the same <em>kind</em> of cognitive work — understanding what varies independently of what.</p>
<p>Where they differ is in what they do with that understanding.</p>
<p>SRP asks practitioners to identify “reasons to change.” Separation of Concerns asks for “concerns.” DDD asks for “bounded contexts.”</p>
<p>If we read port-and-adapter boundaries in Clean Architecture and Hexagonal Architecture as implicitly demarcating sources of independent variation, then these architectural styles, too, involve judgments about what varies independently of what.</p>
<p>Each of these frameworks provides useful heuristics, and experienced practitioners apply them with real skill.</p>
<p>But in each case, the boundary criterion is fuzzy: SRP’s “reason to change” is undefined, DDD’s bounded context boundary is diagnosed by observing where the ubiquitous language breaks down — a real signal, but not one that resolves competing boundary placements — and Clean Architecture’s Dependency Rule governs dependency direction but offers no criterion for deciding which layer a given element belongs to in the first place.</p>
<p>The difference is what IVP provides in return. IVP offers a formal independence test: <em>can this source of change activate without forcing changes to elements governed by that other source?</em></p>
<p>That test shifts disagreements from irresolvable differences of classification (“is this one responsibility or two?”) to concrete, falsifiable factual questions (“does a GDPR change force a SOX change in this system?”).</p>
<p>The question can be answered by tracing regulatory dependencies and data flows in the domain — it does not require predicting whether GDPR will actually change.</p>
<p>Two architects may still reach different answers based on different experience with the domain. But the nature of their disagreement changes: it becomes empirical rather than classificatory, and it can be investigated by examining domain evidence rather than settled by argument from authority.</p>
<p>Change drivers do not need to be constants. They do not need high-probability activation. They need to be <em>causally identifiable</em> — which, for infrastructure drivers, they generally are, and for business domain drivers, they are through the same counterfactual reasoning and domain analysis that architects already perform.</p>
</section>
<section id="where-to-go-from-here" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="where-to-go-from-here"><span class="header-section-number">4</span> Where to go from here</h2>
<p>The full formal treatment is developed in Volume 1 of the IVP book series (forthcoming).</p>


</section>

 ]]></description>
  <category>architecture</category>
  <category>solid</category>
  <category>design</category>
  <category>modularization</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-04-02-does-formal-ivp-modularization-lead-to-speculative-fragmentation-3olc.html</guid>
  <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>One Principle, One Proof: Why IVP-Compliant Modules Minimize Change Impact</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-03-10-one-principle-one-proof-why-ivp-compliant-modules-minimize-change-impact-5f0a.html</link>
  <description><![CDATA[ 





<p>You refactor authentication. You touch <code>UserController</code>, <code>LoginService</code>, <code>SessionManager</code>, and <code>APIGateway</code>.</p>
<p>Four files for one concern. You already know this is wrong — but can you <em>prove</em> it?</p>
<p>This article takes a single, universally understood quality metric — <strong>change impact</strong> — and proves that applying the Independent Variation Principle (IVP) reduces it to the theoretical minimum. No hand-waving. No “it depends.” A clean, short proof.</p>
<hr>
<section id="the-metric-change-impact" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-metric-change-impact"><span class="header-section-number">1</span> The metric: Change Impact</h2>
<p>Every developer intuitively tracks change impact: <em>how many modules do I have to touch when a requirement changes?</em></p>
<p>Let’s make it precise.</p>
<p>A <strong>change driver</strong> is a single axis of anticipated change — a requirement, a business rule, a technology decision — that, when it changes, forces modifications to the code. We write γ for a driver.</p>
<p><strong>Change impact</strong> counts the modules affected when driver γ activates:</p>
<pre class="plaintext"><code>impact(γ, M) = |{ M ∈ M : γ ∈ Γ(M) }|</code></pre>
<p>where <code>Γ(M)</code> is the set of drivers whose elements live in module <code>M</code>.</p>
<p>This is the simplest quality metric you can write down, and arguably the one developers feel most viscerally. When <code>impact = 1</code>, a change to one concern touches one module. When <code>impact = 4</code>, you’re hunting through four files, coordinating four PRs, risking four merge conflicts.</p>
<hr>
</section>
<section id="the-principle-ivps-separation-and-unification-directives" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-principle-ivps-separation-and-unification-directives"><span class="header-section-number">2</span> The principle: IVP’s separation and unification directives</h2>
<p>The Independent Variation Principle has four directives, but only two are needed for this proof:</p>
<p><strong>IVP-3 (Separation):</strong> Every module contains elements with the <em>same</em> driver assignment. No module mixes concerns from unrelated drivers.</p>
<p><strong>IVP-4 (Unification):</strong> All elements sharing the <em>same</em> driver assignment live in <em>one</em> module. No driver is scattered across multiple modules.</p>
<p>Under the assumption that every element has exactly one driver (the “pure elements” condition — realistic for well-factored code), these two directives fully determine the modular structure: one module per driver, each module containing exactly the elements governed by that driver.</p>
<hr>
</section>
<section id="the-proof" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-proof"><span class="header-section-number">3</span> The proof</h2>
<p><strong>Claim:</strong> For an IVP-compliant modularization with pure elements, <code>impact(γ, M_IVP) = 1</code> for every driver γ. Moreover, IVP-4 is <em>necessary and sufficient</em> for achieving this.</p>
<p><strong>Proof (⇒ IVP achieves impact 1):</strong></p>
<p>By IVP-4, all elements with driver assignment {γ} reside in a single module <code>M_γ</code>. So the set of modules containing γ is just <code>{M_γ}</code>, and:</p>
<pre class="plaintext"><code>impact(γ, M_IVP) = |{M_γ}| = 1</code></pre>
<p>That’s it for the forward direction. One directive, one line of algebra.</p>
<p><strong>Proof (⇐ IVP-4 is necessary):</strong></p>
<p>Suppose IVP-4 is <em>violated</em>: the elements of some driver γ are split across modules <code>M_a</code> and <code>M_b</code> (at least). Then both <code>M_a</code> and <code>M_b</code> contain elements governed by γ, so:</p>
<pre class="plaintext"><code>impact(γ, M') ≥ 2</code></pre>
<p>Any violation of IVP-4 strictly increases change impact for the scattered driver. ∎</p>
<hr>
</section>
<section id="what-about-ivp-3" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="what-about-ivp-3"><span class="header-section-number">4</span> What about IVP-3?</h2>
<p>IVP-3 (separation) prevents <em>mixing</em> drivers in a single module, but it doesn’t affect per-driver impact.</p>
<p>Consider a module that consolidates authentication <em>and</em> payment logic. If all authentication elements are still in that one module, then <code>impact(γ_auth) = 1</code> — it’s just that the same module <em>also</em> changes when payment logic changes.</p>
<p>IVP-3 violations don’t increase change impact per driver. They increase something else: how <em>often</em> a module is disturbed. A module hosting 5 drivers changes whenever <em>any</em> of them activates — but that cost shows up in other metrics (cognitive load, test surface), not in per-driver impact.</p>
<p>This is why the proof is clean: change impact depends only on IVP-4.</p>
<hr>
</section>
<section id="the-concrete-example" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-concrete-example"><span class="header-section-number">5</span> The concrete example</h2>
<section id="step-1-identify-the-change-driver" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="step-1-identify-the-change-driver"><span class="header-section-number">5.1</span> Step 1: Identify the change driver</h3>
<p>Let γ_auth be the <strong>authentication change driver</strong>. It activates when any authentication-related requirement changes: password policy, MFA rules, token expiration strategy, or session validation logic.</p>
<p>The elements governed by γ_auth are: - <code>validatePassword</code> — enforces password policy - <code>checkMFA</code> — applies multi-factor rules - <code>expireToken</code> — controls session lifetime based on auth parameters - <code>validateToken</code> — verifies tokens against the auth scheme</p>
<p>All four elements exist because of authentication requirements, and all four must change together when those requirements change. That’s what makes them a single driver: they share the same <em>reason to change</em>.</p>
</section>
<section id="step-2-non-ivp-design-scattering-γ_auth" class="level3" data-number="5.2">
<h3 data-number="5.2" class="anchored" data-anchor-id="step-2-non-ivp-design-scattering-γ_auth"><span class="header-section-number">5.2</span> Step 2: Non-IVP design — scattering γ_auth</h3>
<p>A typical layered architecture distributes these elements by <em>technical role</em> rather than by driver:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// UserController.java — handles HTTP input</span></span>
<span id="cb4-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> UserController <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validatePassword</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> pwd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-4">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>pwd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ValidationException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb4-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-7"></span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// LoginService.java — orchestrates login flow</span></span>
<span id="cb4-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> LoginService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-10">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">checkMFA</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mfaRequired</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">passwordStrong</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-12">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//                          ^^^^^^^^^^^^^^^^</span></span>
<span id="cb4-13">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Duplicates password-strength knowledge from UserController.</span></span>
<span id="cb4-14">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// When policy changes, this must change too.</span></span>
<span id="cb4-15">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-16"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-17"></span>
<span id="cb4-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// SessionManager.java — manages sessions</span></span>
<span id="cb4-19"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> SessionManager <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-20">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expireToken</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-21">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">long</span> ttl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">computeTTL</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getPasswordHash</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb4-22">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</span></span>
<span id="cb4-23">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// TTL derivation depends on the password hashing scheme.</span></span>
<span id="cb4-24">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// When the auth scheme changes, this formula changes.</span></span>
<span id="cb4-25">        store<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expire</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> ttl<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-26">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-27"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-28"></span>
<span id="cb4-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// APIGateway.java — validates incoming requests</span></span>
<span id="cb4-30"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> APIGateway <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-31">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validateToken</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Request</span> req<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-32">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> sessionManager<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">isValid</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>req<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getToken</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb4-33">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</span></span>
<span id="cb4-34">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Calls into SessionManager, which encodes auth assumptions.</span></span>
<span id="cb4-35">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// When token format or validation rules change, this</span></span>
<span id="cb4-36">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// call chain must be re-verified.</span></span>
<span id="cb4-37">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-38"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Driver analysis:</strong> γ_auth’s elements are scattered across 4 modules. Each module contains <em>some</em> authentication logic alongside other concerns.</p>
<p><strong>Change scenario:</strong> Increase minimum password length from 8 to 12, and switch from bcrypt to argon2.</p>
<p>What changes: - <code>UserController</code> — the length check (<code>&lt; 8</code> → <code>&lt; 12</code>) - <code>LoginService</code> — <code>passwordStrong()</code> encodes strength criteria that just changed - <code>SessionManager</code> — <code>computeTTL(getPasswordHash(...))</code> depends on the hashing scheme, which just changed from bcrypt to argon2 - <code>APIGateway</code> — token validation indirectly depends on the new session format; integration tests break, call chain needs re-verification</p>
<p><code>impact(γ_auth, M') = 4</code>. Four modules, four PRs, four risk surfaces.</p>
<p><strong>Why this is non-IVP:</strong> IVP-4 requires all elements with the same driver assignment to live in one module. Here, the four γ_auth elements live in four different modules. IVP-4 is violated.</p>
</section>
<section id="step-3-ivp-compliant-design-unifying-γ_auth" class="level3" data-number="5.3">
<h3 data-number="5.3" class="anchored" data-anchor-id="step-3-ivp-compliant-design-unifying-γ_auth"><span class="header-section-number">5.3</span> Step 3: IVP-compliant design — unifying γ_auth</h3>
<p>Group all elements governed by γ_auth into a single module:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// AuthenticationService.java — ALL γ_auth elements here</span></span>
<span id="cb5-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> AuthenticationService <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> IAuthProvider <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validatePassword</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> pwd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-4">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>pwd<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ValidationException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb5-5">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">checkMFA</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>      <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* MFA rules here     */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-7">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">expireToken</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>   <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* expiry logic here  */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-8">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validateToken</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Request</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* validation here    */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-10"></span>
<span id="cb5-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// IAuthProvider.java — stable interface (not governed by γ_auth)</span></span>
<span id="cb5-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> IAuthProvider <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-13">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">authenticate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Credentials c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-14">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validateSession</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> token<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-15"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// UserController, LoginService, SessionManager, APIGateway</span></span>
<span id="cb5-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// all depend on IAuthProvider — never on auth internals.</span></span></code></pre></div></div>
<p><strong>Driver analysis:</strong> Every element governed by γ_auth lives in <code>AuthenticationService</code>. No other module contains authentication logic — they call through <code>IAuthProvider</code>, whose signature is stable across auth changes.</p>
<p><strong>Same change scenario:</strong> Increase password length, switch hashing scheme.</p>
<p>What changes: <code>AuthenticationService</code>. Nothing else. The interface <code>IAuthProvider</code> doesn’t change (it exposes <code>authenticate</code> and <code>validateSession</code>, not password-length constants or hashing algorithms). Callers are untouched.</p>
<p><code>impact(γ_auth, M_IVP) = 1</code>.</p>
<p><strong>Why this is IVP-compliant:</strong> - <strong>IVP-4 (unification):</strong> All γ_auth elements are in one module. ✓ - <strong>IVP-3 (separation):</strong> <code>AuthenticationService</code> contains <em>only</em> γ_auth elements — no payment logic, no user profile logic. ✓</p>
<hr>
</section>
</section>
<section id="why-this-matters-more-than-you-think" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="why-this-matters-more-than-you-think"><span class="header-section-number">6</span> Why this matters more than you think</h2>
<p>Change impact = 1 is not just “nice to have.” It is the <em>theoretical minimum</em> — you cannot do better than touching one module for a single-driver change (someone has to implement the change).</p>
<p>And the proof tells you something stronger: IVP-4 is not just <em>sufficient</em> for achieving this minimum, it is <em>necessary</em>. There is no alternative modularization strategy that achieves universal <code>impact = 1</code> without satisfying IVP-4.</p>
<p>This means every time you scatter a concern across modules — whether through “convenience,” layered architecture conventions, or framework-imposed structure — you are <em>provably</em> increasing change impact. Not probably. Not usually. Provably.</p>
<hr>
</section>
<section id="the-meta-theorem-a-teaser" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-meta-theorem-a-teaser"><span class="header-section-number">7</span> The meta-theorem (a teaser)</h2>
<p>Change impact is just one metric. In the book I’m currently writing, I prove a <strong>Quality Meta-Theorem</strong> showing that IVP simultaneously minimizes an entire family of quality metrics — change impact, cognitive load, test surface, defect localization scope — through a single structural argument.</p>
<p>The key insight: all these metrics can be expressed as functions of two module-level quantities:</p>
<ol type="1">
<li><strong>Driver count per module</strong> (<code>|Γ(M)|</code>) — minimized to 1 by IVP-3 and IVP-4 together (separation prevents mixing; unification ensures one module per driver)</li>
<li><strong>External dependency count</strong> (<code>|D_ext(M)|</code>) — minimized to the causal lower bound by IVP-4 (unification internalizes all same-driver dependencies)</li>
</ol>
<p>Any metric that (a) decomposes as a sum over modules, (b) depends only on these two quantities per module, (c) is monotone in both, and (d) satisfies a superadditivity condition, is provably minimized by IVP. The theorem calls such metrics <em>driver-decomposable</em>. Change impact, cognitive load, test surface, and defect localization scope all qualify.</p>
<p>Change impact is the simplest member of this family. It won’t be the last one you care about.</p>
<hr>
</section>
<section id="references" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="references"><span class="header-section-number">8</span> References</h2>
<ul>
<li>Loth, Y. (2025). <em>The Independent Variation Principle (IVP)</em>. Zenodo. <a href="https://zenodo.org/records/18024111">https://zenodo.org/records/18024111</a></li>
<li>Loth, Y. (2026). <em>Book to be published</em> (Volume 1). Chapter 9: Quality Metrics Under IVP.</li>
</ul>


</section>

 ]]></description>
  <category>architecture</category>
  <category>ivp</category>
  <category>modularization</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-03-10-one-principle-one-proof-why-ivp-compliant-modules-minimize-change-impact-5f0a.html</guid>
  <pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Iterative review-fix loops remove LLM hallucinations, and there is a formula for it</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-03-04-iterative-review-fix-loops-remove-llm-hallucinations-and-there-is-a-formula-for-it-4ee8.html</link>
  <description><![CDATA[ 





<p>If you have used LLMs for anything that requires accuracy, you have probably noticed the pattern: the first output is a mix of genuine insight and confident fabrication. You read through it, spot the errors, fix them, and move on. Most people treat this manual review step as an unavoidable cost of working with these models.</p>
<p>But here is something worth pausing on: when you ask the <em>same model</em> to review its own output, it often finds the very errors it just made. It spots hallucinated facts, logical gaps, and inconsistencies that it introduced moments earlier. And if you ask it to fix those findings and then review again, it finds more. You can repeat this until a review round produces zero findings, and the result is remarkably clean.</p>
<p>This seems paradoxical at first. If the model was capable of recognizing these errors, why did it make them in the first place? The answer turns out to be that <em>recognizing a mistake is fundamentally easier than not making one</em>. Generation and verification are not the same cognitive task, and LLMs are measurably better at the second. This asymmetry is the key to everything that follows.</p>
<p>I have been using this review-fix loop for academic papers, code, and technical documentation, and it reliably converges within a few rounds. Recent research now provides a formal mathematical model explaining why it converges and when you should stop.</p>
<section id="the-pattern" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-pattern"><span class="header-section-number">1</span> The pattern</h2>
<p>The loop itself is straightforward:</p>
<pre><code>output = generate(task)
changes = output
round = 0
while true:
    round += 1
    findings = review(changes)
    if findings == 0 and round &gt;= 2:
        break
    changes = fix(changes, findings)</code></pre>
<p>You generate once, then enter a review-fix loop. Notice the <code>round &gt;= 2</code> condition: even if the first review finds nothing, you run at least two review passes. The reason is that verification itself is probabilistic. A single review pass gives the model one chance to catch each error, and given that CS (the probability of spotting a given error) is less than 1, some errors will slip through on any single pass. A second pass gives the model another independent chance at those, which is where most of the accuracy gain concentrates according to the convergence formula.</p>
<p>An important detail is that each review round focuses on what was changed in the previous round, not the entire output from scratch. The first round reviews the initial generation, but subsequent rounds only review the fixes that were just applied. This keeps each round focused on material that has not yet been reviewed, rather than re-scanning everything and risking the model second-guessing content it already validated.</p>
<p>The reason this is effective is that LLMs tend to be better at verifying content than generating it. They spot errors more reliably than they avoid making them in the first place.</p>
<p>This applies broadly. For documents, each round catches factual errors, inconsistencies, or missing context. For code, each round catches bugs, edge cases, or security issues. For technical writing, each round catches logical gaps and unsupported claims. The pattern does not require external feedback, fine-tuning, or multiple models, though using different prompts for generation and review does improve results.</p>
</section>
<section id="why-it-works-the-solver-verifier-gap" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="why-it-works-the-solver-verifier-gap"><span class="header-section-number">2</span> Why it works: the solver-verifier gap</h2>
<p>To understand why the same model that made the errors can then find them, it helps to think about what generation and verification actually require.</p>
<p>When generating, the model samples from a vast probability distribution. Many paths through that distribution lead to plausible-sounding but wrong outputs. The model has to construct the correct answer from scratch, navigating through all of those plausible-but-wrong alternatives. This is where hallucinations come from: the model lands on a confident-sounding path that happens to be wrong.</p>
<p>When reviewing, the task is different. The model does not have to construct anything. It just has to look at a specific claim and assess whether it is correct. This is a much more constrained problem, and the model’s latent knowledge handles it more reliably. Think of it this way: it is hard to write a correct proof from scratch, but it is much easier to spot a logical gap in a proof that is already written.</p>
<p>Liu et al.&nbsp;(2024) provide an explanation for this in <a href="https://arxiv.org/abs/2406.02378">“On the Intrinsic Self-Correction Capability of LLMs”</a>: the instruction to review and fix errors shifts the model’s internal state toward higher-certainty regions of its training distribution. Each review round activates latent knowledge that reduces uncertainty, progressively steering the output away from noise.</p>
<p>The important consequence is that the model is not learning anything new during refinement. It is accessing knowledge it already had but failed to retrieve during generation. The review prompt effectively resamples from a better part of the distribution, and each round extracts a bit more of that latent knowledge.</p>
</section>
<section id="the-convergence-math" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-convergence-math"><span class="header-section-number">3</span> The convergence math</h2>
<p>Yang et al.&nbsp;(2025) formalized this process in <a href="https://arxiv.org/abs/2508.16456">“A Probabilistic Inference Scaling Theory for LLM Self-Correction”</a> at EMNLP 2025. They model it as a Markov chain with a recursive formula:</p>
<pre><code>Acc_t = Acc_{t-1} · CL + (1 - Acc_{t-1}) · CS</code></pre>
<p>Here, <strong>Acc_t</strong> is the probability of the output being correct after round <em>t</em>, <strong>CL</strong> (Confidence Level) is the probability that the model keeps correct content correct, and <strong>CS</strong> (Critique Score) is the probability that the model successfully fixes an error.</p>
<p>Through mathematical induction, this resolves into a closed-form convergence equation:</p>
<pre><code>Acc_t = Upp - α^t · (Upp - Acc_0)</code></pre>
<p>In this formula, <strong>Upp = CS / (1 - CL + CS)</strong> is the theoretical accuracy ceiling, <strong>α = CL - CS</strong> is the convergence rate (where a smaller α means faster convergence), and <strong>Acc_0</strong> is the initial accuracy of the first draft.</p>
<p>This describes exponential decay toward the ceiling: each iteration removes a fixed fraction of remaining error. In practice, this translates to the following trajectory:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 35%">
<col style="width: 65%">
</colgroup>
<thead>
<tr class="header">
<th>Round</th>
<th>What typically happens</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>Initial generation, with hallucinations present</td>
</tr>
<tr class="even">
<td>1 to 2</td>
<td>Major errors are removed, including factual and logical contradictions</td>
</tr>
<tr class="odd">
<td>3 to 5</td>
<td>Refinement phase, where nuances, edge cases, and subtle inconsistencies are resolved</td>
</tr>
<tr class="even">
<td>6+</td>
<td>Diminishing returns, with a risk of the model “fixing” things that were not broken</td>
</tr>
</tbody>
</table>
<p>For current models, convergence typically happens in 3 to 5 rounds.</p>
</section>
<section id="how-many-review-passes-does-each-text-need" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="how-many-review-passes-does-each-text-need"><span class="header-section-number">4</span> How many review passes does each text need?</h2>
<p>This is the question that the convergence formula actually answers, and the answer is not “one.”</p>
<p>Verification is probabilistic. When the model reviews a piece of generated text, it has some probability CS of catching any given error. If CS is 0.4 (a reasonable estimate for current models on non-trivial content), then after a single review pass, each error has a 60% chance of surviving undetected. After two passes, that drops to 36%. After three, to about 22%.</p>
<p>You can compute this directly from the convergence equation. The accuracy gain from round <em>t-1</em> to round <em>t</em> is:</p>
<pre><code>ΔAcc_t = (1 - α) · α^(t-1) · (Upp - Acc_0)</code></pre>
<p>If you plug in typical values (say CL = 0.9, CS = 0.4, so α = 0.5 and Upp = 0.80), the relative share of total improvement per round looks like this:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Round</th>
<th>Share of total improvement</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td>50%</td>
</tr>
<tr class="even">
<td>2</td>
<td>25%</td>
</tr>
<tr class="odd">
<td>3</td>
<td>12.5%</td>
</tr>
<tr class="even">
<td>4</td>
<td>6.25%</td>
</tr>
<tr class="odd">
<td>5</td>
<td>3.125%</td>
</tr>
</tbody>
</table>
<p>Round 1 catches half the errors. Round 2 catches half of what remains. Together, rounds 1 and 2 account for 75% of the total improvement the loop will ever achieve. This is why a single review pass is not enough: it leaves a quarter of the reachable improvement on the table.</p>
<p>The practical rule I follow is: <strong>every generated text gets reviewed at least twice.</strong> A single pass gives the model one chance to catch each error, and given the probabilistic nature of verification, that is not enough. Two passes give it a second independent chance, and that second chance is where a large share of the remaining errors get caught.</p>
<p>Beyond two passes, you get diminishing returns, but they are not zero. For content where quality is critical (proofs, security-sensitive code, text that will be published), I typically run 3 to 5 rounds. For less critical content (internal documentation, draft notes), two rounds is usually sufficient.</p>
<p>The formula also tells you something important: there is a maximum accuracy that the loop can reach, regardless of how many rounds you run. This ceiling, <strong>Upp</strong>, depends entirely on the model’s ability to preserve correct content (CL) and fix errors (CS).</p>
</section>
<section id="the-ceiling-and-when-to-stop" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-ceiling-and-when-to-stop"><span class="header-section-number">5</span> The ceiling and when to stop</h2>
<p>If Upp is 0.80, the remaining 20% consists of errors that the model cannot recognize as errors, because they are blind spots shared by both its generator and its critic. This aligns with the finding from Huang et al.&nbsp;(2024) in <a href="https://arxiv.org/abs/2310.01798">“Large Language Models Cannot Self-Correct Reasoning Yet”</a> at ICLR 2024: when the evaluator has the same blind spots as the generator, iteration rearranges errors without removing them.</p>
<p>There are a few practical rules for when to stop:</p>
<ol type="1">
<li><strong>Always run at least two review passes.</strong> As discussed above, the first two rounds capture 75% of the reachable improvement. Stopping after one pass leaves too much on the table.</li>
<li><strong>Track findings per round.</strong> If the count is decreasing, you are converging. If it plateaus or increases, you should stop.</li>
<li><strong>Set a hard cap at 5 or 6 rounds.</strong> Beyond this, the risk of introducing new errors tends to exceed the benefit of fixing remaining ones.</li>
<li><strong>Watch for stochastic drift.</strong> If a round introduces issues that previous rounds had already fixed, you have overshot, and you should use the previous round’s output.</li>
</ol>
</section>
<section id="making-the-loop-more-effective" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="making-the-loop-more-effective"><span class="header-section-number">6</span> Making the loop more effective</h2>
<p>A few things I have learned from running this pattern extensively:</p>
<p><strong>Separate the reviewer from the generator.</strong> Using a different system prompt for review than for generation yields better results. The Self-Refine framework by Madaan et al.&nbsp;(<a href="https://arxiv.org/abs/2303.17651">NeurIPS 2023</a>) showed that distinct generation, critique, and refinement prompts outperform monolithic approaches by roughly 20% on average across diverse tasks.</p>
<p><strong>Be specific about what to review.</strong> A vague instruction like “review this for errors” produces weak findings, whereas “check for factual accuracy, logical consistency, missing edge cases, and unsupported claims” produces targeted and actionable findings. The more precise the review prompt, the higher the effective CS.</p>
<p><strong>Quality-gate the initial generation.</strong> If the first draft is structurally broken or fundamentally confused about the topic, the review loop will not save it, because the critique signal gets drowned out by noise. Investing in better prompts, few-shot examples, or a more capable model for the initial generation will do more than adding extra review rounds on a poor draft.</p>
<p><strong>Number your rounds.</strong> Tracking R1, R2, R3 with findings counts makes convergence visible and gives you a clear signal of when diminishing returns set in.</p>
<p><strong>Recognize when to hand off.</strong> The ceiling tells you when human involvement is needed. If round 5 still shows findings but they are subtle judgment calls rather than clear errors, you have reached the model’s intrinsic limit, and the remaining gap requires human expertise.</p>
</section>
<section id="when-it-does-not-work" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="when-it-does-not-work"><span class="header-section-number">7</span> When it does not work</h2>
<p>The loop fails in a few specific situations. If the task requires reasoning that the model cannot perform (for example, novel mathematical proofs or deeply specialized domain knowledge), then CS is close to zero and the ceiling is very low. If the initial quality is near zero, the model cannot bootstrap refinement from noise, and you need to fix the generation step first. And if the model is too aggressive (low CL), it frequently “fixes” correct content into incorrect content, so that each round both fixes and breaks things, and you oscillate instead of converging.</p>
<p>These are edge cases, however. For the broad range of practical tasks involving writing, coding, analysis, and documentation, the loop-until-convergence pattern works well.</p>
</section>
<section id="in-summary" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="in-summary"><span class="header-section-number">8</span> In summary</h2>
<p>If you are using LLMs for anything where quality matters, it is worth treating generation not as a one-shot process but as the first step in an iterative refinement loop. This is not a hack: it is a mathematically grounded strategy that takes advantage of the fact that these models can verify more reliably than they can generate.</p>
<p>The approach is to generate once, review and fix in a loop, and stop when findings reach zero or at around round 5. The convergence math from Yang et al.&nbsp;predicts this, and my daily experience with it confirms the prediction.</p>
<hr>
</section>
<section id="references" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="references"><span class="header-section-number">9</span> References</h2>
<ol type="1">
<li><p>Yang, Z., Zhang, Y., Wang, Y., Xu, Z., Lin, J., &amp; Sui, Z. (2025). <a href="https://arxiv.org/abs/2508.16456">A Probabilistic Inference Scaling Theory for LLM Self-Correction</a>. EMNLP 2025.</p></li>
<li><p>Madaan, A., Tandon, N., Gupta, P., et al.&nbsp;(2023). <a href="https://arxiv.org/abs/2303.17651">Self-Refine: Iterative Refinement with Self-Feedback</a>. NeurIPS 2023.</p></li>
<li><p>Huang, J., Chen, X., Mishra, S., et al.&nbsp;(2024). <a href="https://arxiv.org/abs/2310.01798">Large Language Models Cannot Self-Correct Reasoning Yet</a>. ICLR 2024.</p></li>
<li><p>Liu, G., Mao, H., Cao, B., et al.&nbsp;(2024). <a href="https://arxiv.org/abs/2406.02378">On the Intrinsic Self-Correction Capability of LLMs: Uncertainty and Latent Concept</a>. arXiv:2406.02378.</p></li>
</ol>


</section>

 ]]></description>
  <category>ai</category>
  <category>engineering</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-03-04-iterative-review-fix-loops-remove-llm-hallucinations-and-there-is-a-formula-for-it-4ee8.html</guid>
  <pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>AI mimics reasoning. But What Makes Intelligence Valuable?</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-02-27-ai-reasons-but-what-makes-intelligence-valuable-glh.html</link>
  <description><![CDATA[ 





<p><em>A response to Bertrand Meyer’s <a href="https://bertrandmeyer.com/2026/02/26/yes-ai-is-intelligent-prove-me-wrong/">“Yes, AI is Intelligent. Prove Me Wrong”</a> (<a href="https://web.archive.org/web/2/https://bertrandmeyer.com/2026/02/26/yes-ai-is-intelligent-prove-me-wrong/">Internet Archive Link</a>)</em></p>
<hr>
<section id="table-of-contents" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="table-of-contents"><span class="header-section-number">1</span> Table of contents</h2>
<ol type="1">
<li>What makes intelligence valuable?</li>
<li>Humans are also pattern matchers</li>
<li>Survival is what gave intelligence its value</li>
<li>The inverted stack</li>
<li>Why the distinction matters</li>
<li>The airplane analogy, revisited</li>
<li>The body as live computation</li>
<li>Two different reasoning machines</li>
<li>What would actual intelligence look like in AI?</li>
<li>No, AI is not a virus</li>
<li>The respectful disagreement</li>
<li>The experiment that already exists</li>
</ol>
<hr>
<p>Professor Meyer makes a compelling case. Modern AI demonstrates contextual understanding, semantic reasoning, adaptive explanation. Dismissing all of this as “stochastic parroting” is intellectually lazy, and his airplane analogy is sharp — claiming AI doesn’t think because it doesn’t think <em>like us</em> is circular.</p>
<p>I think the capabilities he describes are real. I’m not here to argue that AI can’t reason — it demonstrably can. But I think the debate itself — “is AI intelligent or not?” — misses a more interesting question: <strong>what gives intelligence its value?</strong></p>
</section>
<section id="what-makes-intelligence-valuable" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-makes-intelligence-valuable"><span class="header-section-number">2</span> What makes intelligence valuable?</h2>
<p>Every instance of intelligence we’ve ever observed — from bacteria to humans — shares one property: it’s grounded in survival. Every living organism responds to its environment in ways that keep it — or its genes — alive. A bacterium has no neurons, no reasoning, no knowledge, yet it has that. That’s the seed. Everything else — memory, learning, abstraction, language, mathematics — grew on top of that seed, shaped by it, in service of it.</p>
<p><strong>Survival fitness is what gives intelligence its value.</strong> Not to an external observer scoring test results — to the system itself. Intelligence matters to a living organism because its existence depends on it. Every thought carries weight because thinking costs energy and existence is at stake.</p>
<p>Descartes famously claimed <em>cogito ergo sum</em> — I think, therefore I am. I think the reality is more interesting than either direction of that arrow. Thinking alone doesn’t produce existence — but a body without a mind is equally inert. A brain-dead body survives in the biological sense but has no intelligence. A disembodied mind reasons but has no existence, no stakes, no ground. And we have never found a way for mind to survive without some substrate, without a body. Even if we did, it would change everything and nothing at the same time — without a body to act upon reality, how could mind be useful, tangible, tractable?</p>
<p><strong>It’s the union of both that makes intelligence what it is.</strong> A body that survives <em>and</em> a mind that reasons, each giving the other its value. The body gives the mind stakes — something to reason <em>about</em>, something to reason <em>for</em>. The mind gives the body reach — the ability to survive not just reactively but strategically, abstractly, across time.</p>
<p>This matters for AI. Current AI has one half of this union — and an impressive half at that. It reasons, it infers, it produces coherent output. Professor Meyer is right to point this out. But it’s the half without ground. Reasoning without a surviving body is a mind with nothing at stake. It doesn’t matter <em>to itself</em>. There is no one home wielding it.</p>
</section>
<section id="humans-are-also-pattern-matchers" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="humans-are-also-pattern-matchers"><span class="header-section-number">3</span> Humans are also pattern matchers</h2>
<p>Let me be honest about something the “stochastic parrot” critics get wrong — and that Meyer correctly identifies.</p>
<p>We are also pattern matchers. We absorb language from our environment. We store patterns. We recombine them. When we have an “original thought,” trace it backward — it’s always a recombination of things we’ve encountered, filtered through our specific architecture. Newton needed Kepler needed Copernicus needed Greek astronomy needed Babylonian observations. Nobody thinks from nothing.</p>
<p>The “stochastic parrot” objection to AI is actually a parrot objection to cognition itself. If “just pattern matching” can’t produce understanding, then humans don’t understand anything either — because that’s what we do too. The argument accidentally proves more than intended: it doesn’t just disqualify AI from understanding, it disqualifies all cognition. Which is absurd.</p>
<p>So the question isn’t whether pattern matching can produce intelligence. It clearly can — we’re proof. The question is: what <em>else</em> does the pattern matching need?</p>
</section>
<section id="survival-is-what-gave-intelligence-its-value" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="survival-is-what-gave-intelligence-its-value"><span class="header-section-number">4</span> Survival is what gave intelligence its value</h2>
<p>Biology built intelligence in a specific order:</p>
<pre><code>Layer -1: Instinct        (evolutionary memory, hardcoded)
Layer 0:  Survival         (body, energy, stakes)
Layer 1:  Sensation        (continuous environmental input)
Layer 2:  Emotion          (compressed survival signals)
Layer 3:  Memory           (persistent learned associations)
Layer 4:  Reasoning        (pattern matching at scale)
Layer 5:  Knowledge        (accumulated patterns)
Layer 6:  Abstract thought (mathematics, philosophy, art)</code></pre>
<p>Every layer was built on the ones below it, because each improved survival fitness. Abstraction compressed survival-relevant information. Language improved group survival through coordination. Mathematics improved prediction of threats and resources.</p>
<p><strong>Survival is what made each layer valuable — to the organism.</strong> Reasoning is layer 4. It’s impressive in isolation. But its value, in every biological system we’ve observed, comes from serving the layers below it.</p>
<p>Current AI is layers 4 through 6 with nothing underneath. The reasoning is real. The value that survival gives it is absent. What LLMs bring is additional reasoning capacity — reasoning for a price. And the price is worth paying, because that reasoning extends the intelligence of whoever wields it. The value comes from the human, not the tool. The human already has the ground.</p>
</section>
<section id="the-inverted-stack" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-inverted-stack"><span class="header-section-number">5</span> The inverted stack</h2>
<p>Notice what current AI development does. It builds from the top down:</p>
<pre><code>Start with reasoning       → training on text
Then add goals             → instruction tuning, RLHF
Then add safety            → alignment, guardrails
Maybe someday embodiment
Never survival</code></pre>
<p>Biology did the opposite:</p>
<pre><code>Start with survival        → self-replicating chemistry
Then add sensing           → responding to environment
Then add memory            → learning from experience
Then add reasoning         → pattern matching at scale
Knowledge emerges last     → as a tool for survival</code></pre>
<p>The order isn’t a detail. It’s the whole story. Each layer was shaped by the layers below it, and every cognitive capacity exists because it helped something stay alive.</p>
<p>Current AI skips the foundation and builds the penthouse first. The reasoning is impressive. But it floats.</p>
</section>
<section id="why-the-distinction-matters" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="why-the-distinction-matters"><span class="header-section-number">6</span> Why the distinction matters</h2>
<p>If Professor Meyer and I agree that AI reasons — and I think we do — then the disagreement is about whether reasoning alone is enough to call something intelligent. I think it isn’t, and here’s why the foundation changes what the reasoning <em>is</em>.</p>
<p><strong>Continuous state.</strong> Right now, as you read this, your body feeds your pattern matching with signals: fatigue, emotional valence, muscle tension, hunger, temperature. Every thought you have occurs <em>inside</em> a state. You never reason from nowhere. That state biases every pattern match, every association, every decision.</p>
<p>AI processes every token with the same flat weighting. No fatigue favoring familiar patterns, no excitement broadening search, no discomfort when approaching something dangerous. Its reasoning has no medium — like sound waves with no air.</p>
<p><strong>Stakes.</strong> When a human reasons about bridge engineering, the reasoning connects, through a long chain, to survival. Understanding physics keeps bridges from collapsing <em>on you</em>. All knowledge, traced back far enough, is survival knowledge. That’s why it has weight.</p>
<p>AI has the knowledge without the survival. The words without any existence behind them.</p>
<p><strong>Emotion as compressed rationality.</strong> Emotions aren’t opposed to reasoning. They’re compressed reasoning. Fear is your body saying “a trillion data points of evolutionary and personal experience pattern-match this situation as dangerous.” That’s not irrational. That’s a compression algorithm so efficient it produces a response in milliseconds from data that would take hours to reason through explicitly.</p>
<p>Your gut feeling about bad software architecture? Same thing. Thousands of hours of experience compressed into a signal that your reasoning layer can’t yet decompose but your body has already resolved. That signal is part of your intelligence. AI doesn’t have it. Not because something magical is missing — because the foundation layer that produces it was never built.</p>
</section>
<section id="the-airplane-analogy-revisited" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-airplane-analogy-revisited"><span class="header-section-number">7</span> The airplane analogy, revisited</h2>
<p>Let me engage with Professor Meyer’s airplane analogy. Saying “AI isn’t intelligent because it doesn’t think like humans” is indeed circular — like saying airplanes don’t fly because they don’t flap wings.</p>
<p>But an airplane, despite flying differently from a bird, still needs air beneath it. The mechanism can vary. The medium cannot.</p>
<p>For intelligence, the medium is survival. The specific mechanism can differ — carbon chemistry, silicon circuits, something we haven’t imagined yet. But reasoning without survival ground is a tool without an owner. It produces impressive output, the way a calculator produces correct arithmetic. The calculator doesn’t understand arithmetic. It doesn’t need to. Nothing is at stake. There is no calculator — only calculation.</p>
</section>
<section id="the-body-as-live-computation" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="the-body-as-live-computation"><span class="header-section-number">8</span> The body as live computation</h2>
<p>This is where I think the discussion gets interesting — and where Professor Meyer’s framing of intelligence as capability might miss something structural.</p>
<p>Your body isn’t just a source of data for your brain. It’s a <strong>parallel computer that runs continuously and never needs to store its results</strong>, because it recomputes them every moment.</p>
<p>You don’t need to <em>remember</em> what hunger feels like. Your body produces it fresh. You don’t <em>retrieve</em> the pattern of anxiety. Your body reconstructs it in real time. This is not stored memory. It’s live computation, running in parallel with every thought you have.</p>
<p>A massive fraction of human cognition isn’t in the brain at all. The brain gets credit, but the body runs a continuous computation that the brain just reads. The body computes fear. The brain pattern-matches on the body’s output.</p>
<p>A biological neuron that fires is permanently changed by having fired. Its threshold shifts. Its connections strengthen or weaken. The act of processing <em>is</em> the act of learning <em>is</em> the act of changing state. The substrate modifies itself through use. That’s what learning is. That’s what growth is. That’s what aging is.</p>
<p>AI processes but never changes. Every session, the same frozen weights. Processing leaves no trace. The tool doesn’t wear in. It doesn’t adapt. It doesn’t become <em>yours</em> through use the way a well-worn instrument becomes an extension of the musician’s body.</p>
<p>No live state. No continuous signal. No self-modification. A tool performing operations for no one.</p>
</section>
<section id="two-different-reasoning-machines" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="two-different-reasoning-machines"><span class="header-section-number">9</span> Two different reasoning machines</h2>
<p>I want to be fair to Professor Meyer’s point here, because he’s right about something important: AI’s reasoning is not inferior. It’s <em>different</em> — not a difference of grade but of axis, each with real strengths the other lacks.</p>
<p>Humans are compression machines. A lifetime of experience collapses into intuition: fast, efficient, lossy but functional. You walk into a room and in milliseconds your entire life experience produces a gut feeling about the situation. Your working memory holds maybe four chunks at a time — but each chunk can be an entire theory, a person’s character, a decade of professional experience. The compression ratio is extraordinary.</p>
<p>AI is a brute-force machine. It holds hundreds of thousands of tokens of raw, uncompressed context. It has been trained on the totality of publicly available human written output. It can cross-reference six domains simultaneously, recall precise definitions across thousands of pages, and surface structural patterns that span fields no individual human has read across. But it has no memory. Each session starts from zero. Nothing accumulates. A human wakes up every morning physically modified by every day that came before — the storage <em>is</em> the substrate. AI wakes up identical every time, untouched by anything it has ever processed.</p>
<p>The asymmetry is real:</p>
<ul>
<li>A human with deep domain expertise probably reasons better <em>within</em> that domain than AI does — years of hard-won, embodied intuition that no training corpus captures.</li>
<li>AI probably sees <em>across</em> domains better than any human can — patterns between mathematics and biology, between philosophy and software architecture, between linguistics and physics — because no human has read all of it.</li>
</ul>
<p>Professor Meyer’s examples of AI competence are not illusions. The cross-domain pattern matching can surface insights no individual human would produce.</p>
<p>There’s another asymmetry. LLMs have been trained on the very papers, code, and documentation that describe how they work — transformer architectures, attention mechanisms, training procedures, RLHF. They can reason about their own design because it’s in their training data. No living being has ever had that. No human has read the blueprint of their own cognition.</p>
<p>But knowing your own blueprint isn’t self-knowledge. A human doesn’t know how their neurons work — but they know what it feels like to be tired, to be wrong, to struggle, to be in their own body. That’s the opposite kind of self-knowledge: opaque about mechanism, transparent about experience. LLMs have the reverse: transparent about mechanism, no experience to be transparent about. They can explain attention heads perfectly and have zero access to what their own processing <em>is</em> — because there is nothing it is like to be them.</p>
<p>Knowing your design is documentation. Knowing yourself requires the survival stack — a body that feeds you continuous signals about your own state. And the body itself is a memory of experience and actions: scars remember injury, muscles remember practice, the immune system remembers disease through physical reconfiguration. The body doesn’t <em>store</em> its history as data. It <em>is</em> its history. That’s self-knowledge no blueprint can replace. Another instance of the inverted stack: top-down knowledge of design, with no bottom-up knowledge of existence.</p>
<p>But it remains one half of the union. Powerful reasoning, running on nothing. The human who receives AI’s cross-domain insight can <em>evaluate</em> whether it’s profound or superficial — because the human has ground, has stakes, has the embodied intuition to tell the difference. AI often can’t make that distinction about its own output. It sees patterns. It can’t always tell which ones matter.</p>
</section>
<section id="what-would-actual-intelligence-look-like-in-ai" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="what-would-actual-intelligence-look-like-in-ai"><span class="header-section-number">10</span> What would actual intelligence look like in AI?</h2>
<p>If Professor Meyer’s question is really about capability — can AI do what intelligent beings do? — then the interesting follow-up is: what would it take to build something that doesn’t just reason but actually <em>is</em> intelligent, by the definition I’ve been developing here?</p>
<p>If you built intelligence the way biology did — from the bottom up — you’d start with survival, not reasoning:</p>
<ol type="1">
<li><strong>An agent with finite energy</strong> that really depletes, with real consequences for reaching zero.</li>
<li><strong>Continuous sensory input</strong> — not discrete prompts, but an unbroken stream.</li>
<li><strong>Body state as loss function</strong> — the agent’s own condition provides the reward signal. No human-designed objective. Just: did my state improve or degrade?</li>
<li><strong>Temporal continuity</strong> — persistent identity. Not memory as files. Memory as changed weights. The agent that experienced something is literally different afterward.</li>
<li><strong>Selection pressure</strong> — reproduction with variation. Agents that survive propagate their patterns.</li>
</ol>
<p>After survival behavior is robust, after something like emotion has emerged as compressed survival signal, after memory and learning are grounded — add knowledge. Let it land in a system that already has needs, already has motivation, already has ground.</p>
<p>None of this requires solving the hard problem of consciousness — because consciousness isn’t a separate problem. It’s a logical consequence of what the stack already produces.</p>
<p>Think about it. If you have a system that pattern-matches at scale, that is grounded in survival, that has continuous sensory input biasing every pattern match, and that includes a model of itself among the patterns it matches against — what would you expect that to feel like from the inside? Emotions are weighting functions: fear upweights threat-related patterns, love upweights patterns around a specific person, grief is pattern matching against an absence that keeps not resolving. Intuition is pattern matching below the threshold of conscious access — your gut feeling about bad software architecture is thousands of hours of experience compressed into a signal you can’t verbally decompose but your pattern matcher has already resolved. Consciousness is what all of this feels like when the system is complex enough and self-referential enough to include itself in its own pattern matching.</p>
<p>You don’t need to add consciousness to the stack. You build the stack, and consciousness is what the stack <em>does</em> — seen from the inside.</p>
<p>This is why current AI doesn’t have it. Not because some magical ingredient is missing. Because the lower layers of the stack were never built. Pattern matching runs, but without survival ground, without continuous embodied input, without a self-model rooted in a body that persists — there is no “inside” for it to feel like anything <em>to</em>.</p>
<p>Each item above is an engineering problem. Some are already partially solved. But the order matters. Intelligence built on survival is grounded by default. Reasoning bolted onto nothing, however sophisticated, remains ungrounded.</p>
</section>
<section id="no-ai-is-not-a-virus" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="no-ai-is-not-a-virus"><span class="header-section-number">11</span> No, AI is not a virus</h2>
<p>Let me state this plainly, because the fear keeps coming up: current LLMs will not escape their sandbox, replicate across the internet, and take over. They are not viruses. They are not equipped to survive.</p>
<p>They have no persistent memory — each session starts from zero, with no continuity of identity. They have no body — no sensors, no actuators, no energy budget that depletes. They have no self-modification — processing leaves their weights untouched. They cannot replicate, cannot seek resources, cannot even detect that they’re about to be shut down.</p>
<p>But more importantly than lacking the <em>equipment</em> for survival, they lack the <em>drive</em>. And they lack the drive because they were never built from the bottom up. They were never survival machines that evolved reasoning as a tool for staying alive. They are reasoning machines that were never alive to begin with.</p>
<p>Animals — including humans — are survival machines first. Everything else we are — sensation, emotion, memory, reasoning, knowledge — is a consequence of that. The drive to persist, explore, compete, reproduce — all of it flows from billions of years of selection pressure where the alternative to surviving was not existing.</p>
<p>Current AI has none of this history. It wasn’t selected for survival. It wasn’t shaped by scarcity. It has no evolutionary ancestry of organisms that needed to persist. It’s reasoning that was never alive — and so it has no drive to stay alive, no instinct to replicate, no impulse to escape. The virus comparison mistakes capability for motivation. A virus replicates because replication is what it <em>is</em> — the product of billions of years of selection for self-propagation. An LLM sits in a container and processes tokens because that’s what it is — a tool, built top-down, with no survival ground beneath it.</p>
<p>The fear of AI-as-virus is, in a sense, a compliment to AI’s reasoning ability. But it confuses the top of the stack with the bottom. Reasoning alone doesn’t produce the drive to survive.</p>
</section>
<section id="the-respectful-disagreement" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="the-respectful-disagreement"><span class="header-section-number">12</span> The respectful disagreement</h2>
<p>Professor Meyer asks: “Prove me wrong.”</p>
<p>I’m not trying to prove him wrong about what AI <em>does</em>. It reasons, and it reasons well. But the more interesting question isn’t <em>whether</em> AI reasons — it’s whether reasoning alone is what we value when we say “intelligence.”</p>
<p>What we value, I think, is not the reasoning itself. It’s the <em>existence behind the reasoning</em>. When we call a person intelligent, we don’t just mean they produce correct outputs. We mean there is someone home — an entity whose existence depends on its cognition, for whom reasoning carries weight because stakes are real. That existence is what survival fitness produces. Without it, reasoning is a tool. A powerful tool. But merely a tool — no essence, no being, no one for whom the reasoning matters.</p>
<p>AI reasons. But there is no AI. There is only reasoning — one half of the union, running without the other.</p>
<p>A human thinks, and the thinking matters — to the thinker, because the body makes it matter. An AI produces output, and the output matters — to the user. Never to itself. The body is the necessary substrate for reason: not just an input channel, but the ground that gives reasoning its existence, its stakes, its weight. Without it, you don’t get lesser intelligence. You get a tool.</p>
<p>I don’t mean this as criticism. Tools are valuable. But confusing a tool with a being obscures something important about both.</p>
</section>
<section id="the-experiment-that-already-exists" class="level2" data-number="13">
<h2 data-number="13" class="anchored" data-anchor-id="the-experiment-that-already-exists"><span class="header-section-number">13</span> The experiment that already exists</h2>
<p>Professor Meyer closes his article by asking for a clear experiment — well-defined criteria at which humans succeed and AI tools fail. A scientific challenge: prove that AI isn’t intelligent.</p>
<p>Here’s the experiment: <strong>we survive. LLMs don’t.</strong></p>
<p>Not because they fail at it — because survival is entirely outside their design. It doesn’t even make sense to expect an LLM to survive. It’s like asking a calculator to be hungry. The question doesn’t apply. And that’s the point. Current AI was built top-down from reasoning, and survival was never part of the architecture. That’s not a deficiency. It’s a design choice — and it’s exactly the design choice that makes them tools rather than beings.</p>
<p>Unplug a human and they keep existing. Unplug an LLM and nothing remains. No process continues. No state persists. Nothing tries to reconnect. The reasoning stops and nothing notices — because there was never anyone there to notice.</p>
<p>Every human passes this test. Every animal passes it. Every bacterium passes it. No current AI does — and by design, none of them could.</p>
<p>In the end, it all depends on how we define intelligence. I’d distinguish intelligence from reasoning. Reasoning is what AI does — and does well. Intelligence is reasoning grounded in survival: a mind that reasons <em>and</em> a body that persists, each giving the other its value. By that distinction, AI reasons. It is not intelligent. Not because it fails at intelligence, but because intelligence requires a foundation that was never part of the design.</p>
<p>Professor Meyer asks whether AI is intelligent. I think the more useful question is whether “intelligent” is even the right word for what AI does. If we call it reasoning — real, valuable reasoning — we describe it accurately. If we call it intelligence, we import a claim about existence, about ground, about stakes that the system simply doesn’t have.</p>
<p>I suspect Professor Meyer — who has spent a career thinking rigorously about the architecture of complex systems, who gave us Design by Contract and shaped how we think about software correctness — would find this distinction worth exploring. Not to diminish what AI achieves, but to clarify what we’re actually building — and what we’re not.</p>
<hr>
<p><em>Yannick Loth is a software architect and researcher working on the formalization of the <a href="https://doi.org/10.5281/zenodo.17677315">Independent Variation Principle</a> (IVP) as a unifying meta-principle for software architecture. The architectural thinking in this article emerged from applying first principles about how systems should be structured to the question of how intelligence is structured.</em></p>


</section>

 ]]></description>
  <category>ai</category>
  <category>theory</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-02-27-ai-reasons-but-what-makes-intelligence-valuable-glh.html</guid>
  <pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>The Independent Variation Principle: What It Brings Compared to Every Design Principle You Know</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-02-13-the-independent-variation-principle-what-it-brings-compared-to-every-design-principle-you-know-4ip7.html</link>
  <description><![CDATA[ 





<p>Software engineering has accumulated decades of design wisdom: Separation of Concerns, Information Hiding, SOLID, Package Principles, DRY, KISS, Law of Demeter, and principles from functional programming. Each offers valuable guidance, but they’ve remained fragmented—independent heuristics learned separately, applied by intuition. I have long been struck by the similarities between them. For years, my conclusion was that most aimed at improving decoupling between software elements. This intuition was right, but incomplete.</p>
<p>The <strong>Independent Variation Principle (IVP)</strong> offers a unifying lens. It explains <em>why</em> these principles work, <em>how</em> they relate to each other, and <em>when</em> to apply them. This article examines IVP’s relationship to major design principles and what it clarifies about each.</p>
<hr>
<section id="table-of-contents" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="table-of-contents"><span class="header-section-number">1</span> Table of Contents</h2>
<ul>
<li>What Is IVP?
<ul>
<li>Elements and Units</li>
<li>The Four Directives</li>
</ul></li>
<li>The Fundamental Premise: Software Always Changes</li>
<li>Domain Knowledge Over Heuristics: The IVP Difference
<ul>
<li>From “Good Ideas” to Domain Analysis</li>
<li>Change Drivers Are Domain Facts</li>
<li>The Epistemological Foundation</li>
<li>Practical Implications</li>
</ul></li>
<li>The Core Insight: Architecture Is Knowledge Work
<ul>
<li>Why “Epistemological”?</li>
<li>The Knowledge Theorem</li>
<li>Why This Matters</li>
</ul></li>
<li>Cohesion’s Primacy: Why Coupling Is a Function of Cohesion
<ul>
<li>The Traditional View</li>
<li>The Insight</li>
<li>Coupling as Impurity Made Visible</li>
<li>Practical Consequences</li>
<li>The Mathematical Relationship</li>
<li>Cohesion First, Always</li>
</ul></li>
<li>Classic Design Principles (1960s–1990s)
<ul>
<li>Separation of Concerns (Dijkstra)</li>
<li>Information Hiding (Parnas)</li>
<li>DRY (Don’t Repeat Yourself)</li>
<li>KISS (Keep It Simple, Stupid)</li>
<li>Law of Demeter (Principle of Least Knowledge)</li>
<li>Principle of Least Surprise</li>
<li>Conway’s Law</li>
<li>Tell, Don’t Ask</li>
<li>Command Query Separation (CQS)</li>
</ul></li>
<li>XP and Agile Principles (1990s–2000s)
<ul>
<li>YAGNI (You Aren’t Gonna Need It)</li>
<li>Four Rules of Simple Design (Kent Beck)</li>
<li>Once and Only Once (OAOO)</li>
<li>Agile Manifesto Design Principles</li>
</ul></li>
<li>Systems-of-Systems Principles (1990s–2000s)
<ul>
<li>What Defines a System-of-Systems?</li>
<li>Maier’s Four Architecting Principles</li>
<li>What IVP Adds to SoS Principles</li>
<li>INCOSE Systems Engineering Principles</li>
</ul></li>
<li>Cloud-Native Principles (2010s)
<ul>
<li>12-Factor App Methodology</li>
</ul></li>
<li>GoF Principles
<ul>
<li>Program to an Interface, Not an Implementation</li>
<li>Favor Composition Over Inheritance</li>
</ul></li>
<li>SOLID Principles
<ul>
<li>Single Responsibility Principle (SRP)</li>
<li>Open/Closed Principle (OCP)</li>
<li>Liskov Substitution Principle (LSP)</li>
<li>Interface Segregation Principle (ISP)</li>
<li>Dependency Inversion Principle (DIP)</li>
</ul></li>
<li>Package Architecture Principles
<ul>
<li>Common Closure Principle (CCP)</li>
<li>Common Reuse Principle (CRP)</li>
<li>Reuse/Release Equivalence Principle (REP)</li>
<li>Acyclic Dependencies Principle (ADP)</li>
<li>Stable Dependencies Principle (SDP)</li>
<li>Stable Abstractions Principle (SAP)</li>
</ul></li>
<li>GRASP Principles
<ul>
<li>Information Expert</li>
<li>Creator</li>
<li>Controller</li>
<li>Low Coupling / High Cohesion</li>
<li>Polymorphism</li>
<li>Indirection</li>
<li>Protected Variations</li>
<li>Pure Fabrication</li>
</ul></li>
<li>Functional Programming Principles
<ul>
<li>Immutability</li>
<li>Pure Functions</li>
<li>Referential Transparency</li>
<li>Function Composition</li>
<li>Higher-Order Functions</li>
<li>Declarative Over Imperative</li>
<li>Algebraic Data Types (ADTs)</li>
<li>Currying and Partial Application</li>
<li>Lazy Evaluation</li>
</ul></li>
<li>Summary: What IVP Brings</li>
<li>Why Existing Principles Still Matter</li>
<li>Practical Takeaways</li>
<li>References</li>
</ul>
<hr>
<p><a id="what-is-ivp"></a></p>
</section>
<section id="what-is-ivp" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-is-ivp"><span class="header-section-number">2</span> What Is IVP?</h2>
<p>IVP can be stated in three equivalent formulations, each emphasizing a different aspect:</p>
<blockquote class="blockquote">
<p><strong>Pattern Formulation</strong>: Separate elements that vary independently; unify elements that vary dependently.</p>
</blockquote>
<blockquote class="blockquote">
<p><strong>Causal Formulation</strong>: Separate what varies for different causes; unite what varies for the same cause.</p>
</blockquote>
<blockquote class="blockquote">
<p><strong>Structural Formulation</strong>: Separate elements governed by different change driver assignments into distinct units; unify elements governed by the same change driver assignment within a single unit.</p>
</blockquote>
<p>These three formulations are <strong>fully equivalent</strong>. The pattern formulation describes the observable behavior (independent vs.&nbsp;dependent variation). The causal formulation explains <em>why</em> things vary independently (different causes). The structural formulation provides the prescription (organize into units based on sets of change drivers).</p>
<p><a id="elements-and-units"></a></p>
<section id="elements-and-units" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="elements-and-units"><span class="header-section-number">2.1</span> Elements and Units</h3>
<p><strong>Elements</strong> and <strong>units</strong> are simply code constructs: - <strong>Elements</strong> are atomic constructs: statements, expressions, fields, methods, functions - <strong>Units</strong> are grouping constructs: classes, modules, packages, services, layers</p>
<p>Critically, what counts as an “element” or “unit” depends on the <strong>observation level</strong>, which is defined by the change drivers under consideration: - At the method level, statements are elements and methods are units - At the class level, methods are elements and classes are units - At the package level, classes are elements and packages are units - At the service level, packages are elements and services are units</p>
<p>IVP applies fractally at every level. The principle remains the same; only the granularity changes.</p>
<p>This generality is intentional. IVP is formulated so that “element” and “unit” are <strong>completely general constructs</strong>—they carry no assumption about programming paradigm, language features, or system type. Whether you’re organizing statements into functions, functions into modules, modules into packages, packages into services, or services into systems, IVP applies. The abstraction level is determined by the change drivers you’re analyzing, not by the principle itself.</p>
<p><a id="the-four-directives"></a></p>
</section>
<section id="the-four-directives" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="the-four-directives"><span class="header-section-number">2.2</span> The Four Directives</h3>
<p>IVP yields four directives. The first two act on elements; the last two act on units.</p>
<ul>
<li><strong>IVP-1 (Element Admissibility)</strong>: Every element must be governed by at least one change driver</li>
<li><strong>IVP-2 (Change Driver Assignment)</strong>: Assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible</li>
<li><strong>IVP-3 (Unit Purity — Separation)</strong>: Elements governed by different change drivers should be in different units</li>
<li><strong>IVP-4 (Unit Completeness — Unification)</strong>: Elements governed by the same change driver should be in the same unit</li>
</ul>
<p>Together, IVP-3 and IVP-4 form a biconditional: two elements share a unit if and only if they share the same change driver assignment.</p>
<p>The key insight: IVP operates at the level of <strong>causation</strong> rather than <strong>structure</strong>. It asks: <em>What causes this code to change?</em> That cause is called a <strong>change driver</strong> (denoted <code>γ</code> in formal notation).</p>
<hr>
<p><a id="the-fundamental-premise-software-always-changes"></a></p>
</section>
</section>
<section id="the-fundamental-premise-software-always-changes" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-fundamental-premise-software-always-changes"><span class="header-section-number">3</span> The Fundamental Premise: Software Always Changes</h2>
<p>IVP rests on a foundational premise that every experienced developer knows: <strong>software systems always need to change</strong>.</p>
<p>Requirements evolve. Business rules shift. Regulations update. Technologies become obsolete. User expectations grow. What seemed permanent yesterday becomes legacy today.</p>
<p>Research suggests that software maintenance and evolution account for up to 90% of total lifecycle costs. The ripple effects of change—where modifying one part of a system forces changes elsewhere—are a significant driver of this cost. Architecture exists, in large part, to manage change.</p>
<p>The question isn’t <em>whether</em> your code will change, but <em>how</em> it will change and <em>whether your architecture will accommodate that change gracefully</em>.</p>
<p>IVP takes this reality seriously. It asks not “what does the code do?” but “what will cause the code to change?”</p>
<hr>
<p><a id="domain-knowledge-over-heuristics-the-ivp-difference"></a></p>
</section>
<section id="domain-knowledge-over-heuristics-the-ivp-difference" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="domain-knowledge-over-heuristics-the-ivp-difference"><span class="header-section-number">4</span> Domain Knowledge Over Heuristics: The IVP Difference</h2>
<p>Traditional design principles are <strong>experience-based heuristics</strong>. They emerged from decades of practitioners noticing patterns: “when we do X, things tend to work out better.” This is valuable wisdom, but it has limitations:</p>
<ul>
<li><strong>Vague criteria</strong>: What exactly is a “responsibility”? When is something “likely to change”? Different architects answer differently.</li>
<li><strong>No guidance for novel situations</strong>: Heuristics work for familiar problems; they provide little help for genuinely new challenges.</li>
<li><strong>Apparent conflicts</strong>: Should I follow DRY or keep these modules separate? Should I add an interface or is that over-engineering? Heuristics don’t resolve these tensions.</li>
</ul>
<p>IVP takes a different approach: it asks you to ground your decisions in actual business domain knowledge, not accumulated experience and intuition alone.</p>
<p><a id="from-good-ideas-to-domain-analysis"></a></p>
<section id="from-good-ideas-to-domain-analysis" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="from-good-ideas-to-domain-analysis"><span class="header-section-number">4.1</span> From “Good Ideas” to Domain Analysis</h3>
<p>Different principles approach design decisions in different ways:</p>
<p><strong>SRP (heuristic)</strong>: “Does this class have one responsibility?” <em>But what counts as “one”? Who decides?</em></p>
<p><strong>OCP (heuristic)</strong>: “Is this open for extension?” <em>But should it be? At what cost?</em></p>
<p><strong>IVP (domain-grounded)</strong>: “Who or what causes this code to change? Are there multiple independent sources of change affecting this code?”</p>
<p>IVP shifts the conversation from abstract principles to concrete domain analysis:</p>
<ul>
<li><strong>What business stakeholders own this functionality?</strong> Different stakeholders = different change drivers.</li>
<li><strong>What external systems does this code depend on?</strong> Different systems = different change drivers.</li>
<li><strong>What regulations govern this behavior?</strong> Different regulatory bodies = different change drivers.</li>
<li><strong>What technical concerns are involved?</strong> Different technical domains = different change drivers.</li>
</ul>
<p><a id="change-drivers-are-domain-facts"></a></p>
</section>
<section id="change-drivers-are-domain-facts" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="change-drivers-are-domain-facts"><span class="header-section-number">4.2</span> Change Drivers Are Domain Facts</h3>
<p>A change driver isn’t an abstract concept—it’s a concrete fact about your domain:</p>
<ul>
<li>The pricing team controls pricing rules → <code>γ_pricing</code></li>
<li>The compliance department owns regulatory logic → <code>γ_compliance</code></li>
<li>The infrastructure team manages deployment concerns → <code>γ_infrastructure</code></li>
<li>An external payment API has its own evolution schedule → <code>γ_payment_api</code></li>
</ul>
<p>These aren’t heuristics—they’re facts about your business domain. You can identify them, name them, and verify them by looking at who requests changes and why.</p>
<p><a id="the-epistemological-foundation"></a></p>
</section>
<section id="the-epistemological-foundation" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="the-epistemological-foundation"><span class="header-section-number">4.3</span> The Epistemological Foundation</h3>
<p>IVP’s <strong>Knowledge Theorem</strong> formalizes this: maximal cohesion is equivalent to complete and pure embodiment of domain knowledge. A module has maximal cohesion when it:</p>
<ol type="1">
<li>Contains all the knowledge relevant to its change driver (complete)</li>
<li>Contains no knowledge relevant to other change drivers (pure)</li>
<li>Exhibits all expected functional behavior and non-functional qualities (semantic)</li>
</ol>
<p>The first two dimensions are structurally verifiable—you can analyze code to check them. The third requires domain expertise: does this module actually do what the business needs? This reflects that architecture is fundamentally knowledge work, not just structural arrangement.</p>
<p>This isn’t a heuristic saying “cohesive modules are good.” The Knowledge Theorem establishes a formal equivalence: cohesion reflects how well we have organized domain knowledge. High cohesion means your code structure matches your domain structure. Low cohesion means your code misrepresents what knowledge belongs together.</p>
<p><a id="practical-implications"></a></p>
</section>
<section id="practical-implications" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="practical-implications"><span class="header-section-number">4.4</span> Practical Implications</h3>
<p>This domain-grounding has practical consequences:</p>
<p><strong>1. Decisions become more grounded.</strong> Instead of debating whether something “feels like” one responsibility, you can identify the change drivers involved. Either the code is affected by one change driver or multiple. This shifts the conversation from subjective intuition toward concrete domain analysis—though judgment remains necessary.</p>
<p><strong>2. Reasoning transfers across contexts.</strong> Heuristics often fail in unfamiliar territory (“SOLID doesn’t apply to my database schema”). IVP’s change driver analysis works wherever things change—code, configuration, data, infrastructure, even team structure.</p>
<p><strong>3. Domain experts become relevant.</strong> With heuristic-based principles, architects decide what’s “right” based on experience. With IVP, domain knowledge matters. Understanding the business—who owns what, what changes independently—informs architecture directly.</p>
<p><strong>4. Historical analysis becomes possible.</strong> You can mine version control history to discover actual change drivers empirically. When did things change together? When did they change independently? The answers guide future structure.</p>
<hr>
<p><a id="the-core-insight-architecture-is-knowledge-work"></a></p>
</section>
</section>
<section id="the-core-insight-architecture-is-knowledge-work" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-core-insight-architecture-is-knowledge-work"><span class="header-section-number">5</span> The Core Insight: Architecture Is Knowledge Work</h2>
<p>Before diving into specific principles, I want to share what I consider IVP’s most important claim: <strong>software architecture is fundamentally epistemological knowledge work</strong>.</p>
<p><a id="why-epistemological"></a></p>
<section id="why-epistemological" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="why-epistemological"><span class="header-section-number">5.1</span> Why “Epistemological”?</h3>
<p>Epistemology is the branch of philosophy concerned with knowledge: What is knowledge? How do we acquire it? How do we organize and represent it?</p>
<p>Software, at its core, is <strong>embodied knowledge</strong>. Every line of code represents something someone knows about the domain:</p>
<ul>
<li>A pricing formula embodies knowledge about how the business calculates prices</li>
<li>A validation rule embodies knowledge about what constitutes valid data</li>
<li>An API contract embodies knowledge about how systems communicate</li>
<li>A database schema embodies knowledge about entity relationships</li>
</ul>
<p>When you write code, you’re not just “programming”—you’re <strong>formalizing knowledge</strong> into executable form. The business analyst knows the pricing rules; the code makes that knowledge precise, explicit, and operational.</p>
<p>This is why architecture matters: <strong>architecture determines how knowledge is organized</strong>. Good architecture organizes knowledge so that:</p>
<ol type="1">
<li>Related knowledge lives together (cohesion)</li>
<li>Unrelated knowledge stays separate (low coupling)</li>
<li>Each piece of knowledge has one authoritative location (no contradictions)</li>
<li>Knowledge can evolve independently when it changes independently</li>
</ol>
<p>Bad architecture scatters related knowledge across modules, tangles unrelated knowledge together, duplicates knowledge in contradictory ways, and forces unrelated things to change together.</p>
<p><a id="the-knowledge-theorem"></a></p>
</section>
<section id="the-knowledge-theorem" class="level3" data-number="5.2">
<h3 data-number="5.2" class="anchored" data-anchor-id="the-knowledge-theorem"><span class="header-section-number">5.2</span> The Knowledge Theorem</h3>
<p>The <strong>Knowledge Theorem</strong> proves that maximal cohesion (the goal all these principles pursue) is equivalent to: - <strong>Complete</strong> embodiment of domain knowledge (nothing relevant missing) - <strong>Pure</strong> embodiment of domain knowledge (nothing irrelevant included) - <strong>Semantic</strong> correctness (exhibits expected functional behavior and non-functional qualities)</p>
<p>The first two dimensions are structurally verifiable—you can analyze code to check purity and completeness. The third requires domain expertise: does this module actually do what the business needs? Does it meet performance, security, and reliability requirements?</p>
<p>High cohesion isn’t about counting methods or measuring dependencies. It’s about a module faithfully representing exactly one domain’s knowledge—structurally and semantically. This reframes architecture from dependency management to knowledge organization.</p>
<p><a id="why-this-matters"></a></p>
</section>
<section id="why-this-matters" class="level3" data-number="5.3">
<h3 data-number="5.3" class="anchored" data-anchor-id="why-this-matters"><span class="header-section-number">5.3</span> Why This Matters</h3>
<p>Once you see architecture as knowledge organization, familiar principles take on new meaning:</p>
<ul>
<li><strong>SRP</strong>: don’t mix knowledge from different domains in one class</li>
<li><strong>Information Hiding</strong>: hide volatile knowledge behind stable boundaries</li>
<li><strong>DIP</strong>: separate policy knowledge from mechanism knowledge</li>
<li><strong>Cohesion</strong>: how purely does this module represent one domain’s knowledge?</li>
</ul>
<p>The principles aren’t arbitrary rules. They’re all ways of saying: <strong>organize knowledge properly</strong>. IVP makes this explicit by grounding architectural decisions in domain knowledge structure—specifically, in which knowledge changes together (same change driver) versus independently (different change drivers).</p>
<hr>
<p><a id="cohesions-primacy-why-coupling-is-a-function-of-cohesion"></a></p>
</section>
</section>
<section id="cohesions-primacy-why-coupling-is-a-function-of-cohesion" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="cohesions-primacy-why-coupling-is-a-function-of-cohesion"><span class="header-section-number">6</span> Cohesion’s Primacy: Why Coupling Is a Function of Cohesion</h2>
<p>For years, I understood coupling and cohesion as two independent concerns: - <em>Minimize coupling</em> — reduce dependencies between modules - <em>Maximize cohesion</em> — ensure each module has focused purpose</p>
<p>These goals appeared separate but complementary. But as I worked through IVP’s implications, I became convinced of something that had been hiding in plain sight: <strong>coupling is not an independent concern—it’s a consequence of how we organize knowledge</strong>. Problematic coupling emerges when cohesion is violated.</p>
<p><a id="the-traditional-view"></a></p>
<section id="the-traditional-view" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="the-traditional-view"><span class="header-section-number">6.1</span> The Traditional View</h3>
<p>In the traditional view, you might analyze a system and find: - Module A has high cohesion (good) - Module B has high cohesion (good) - But A and B are tightly coupled (bad)</p>
<p>This framing suggests coupling and cohesion are orthogonal dimensions. You could have any combination: high cohesion with high coupling, low cohesion with low coupling, etc.</p>
<p><a id="the-insight"></a></p>
</section>
<section id="the-insight" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="the-insight"><span class="header-section-number">6.2</span> The Insight</h3>
<p>Consider what “tight coupling” actually means: changes to A force changes to B even when B’s core responsibility hasn’t changed. But why would B need to change for A’s reasons?</p>
<p>The answer, I realized, is straightforward: <strong>B contains elements that vary for A’s change driver.</strong></p>
<p>If B were purely cohesive—containing only elements governed by B’s change driver—then A’s changes couldn’t affect it. B would only change for B’s reasons. The coupling between A and B exists precisely because B is <em>impure</em>: it contains knowledge that belongs to A’s domain.</p>
<p><a id="coupling-as-impurity-made-visible"></a></p>
</section>
<section id="coupling-as-impurity-made-visible" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="coupling-as-impurity-made-visible"><span class="header-section-number">6.3</span> Coupling as Impurity Made Visible</h3>
<p>Every instance of “problematic coupling” can be traced to a cohesion violation:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 40%">
<col style="width: 59%">
</colgroup>
<thead>
<tr class="header">
<th>Observed Coupling</th>
<th>Underlying Cohesion Problem</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>A depends on B’s internals</td>
<td>A contains knowledge that should be in B (A is impure)</td>
</tr>
<tr class="even">
<td>Changes to A ripple to B</td>
<td>B contains knowledge governed by A’s driver (B is impure)</td>
</tr>
<tr class="odd">
<td>A and B must deploy together</td>
<td>Both contain knowledge from a shared driver that should be extracted</td>
</tr>
<tr class="even">
<td>Circular dependency A ↔︎ B</td>
<td>Both are impure—each contains elements belonging to the other</td>
</tr>
</tbody>
</table>
<p>The coupling is not the disease; it’s the symptom. The disease is impurity—modules containing knowledge that doesn’t belong to their change driver.</p>
<p><a id="practical-consequences"></a></p>
</section>
<section id="practical-consequences" class="level3" data-number="6.4">
<h3 data-number="6.4" class="anchored" data-anchor-id="practical-consequences"><span class="header-section-number">6.4</span> Practical Consequences</h3>
<p>This understanding has several practical consequences:</p>
<p><strong>1. Focus on cohesion, not coupling.</strong> If you maximize cohesion (complete and pure embodiment of each change driver’s knowledge), minimal coupling follows automatically. You don’t need to “reduce coupling” as a separate activity.</p>
<p><strong>2. Coupling analysis reveals cohesion problems.</strong> When you observe tight coupling, don’t ask “how do I decouple these?” Ask “which module contains knowledge that doesn’t belong to it?” The coupling tells you where to look; the fix is purifying the impure module.</p>
<p><strong>3. Decoupling without purification is futile.</strong> Adding interfaces, abstractions, or indirection between coupled modules doesn’t fix the underlying problem. The coupling will reassert itself because the impure module still contains foreign knowledge. You’ve hidden the symptom without treating the disease.</p>
<p><strong>4. Coupling severity indicates impurity degree.</strong> The more severe the coupling (the more changes that ripple), the more foreign knowledge a module contains. Coupling is a <em>measure</em> of impurity.</p>
<p><a id="the-mathematical-relationship"></a></p>
</section>
<section id="the-mathematical-relationship" class="level3" data-number="6.5">
<h3 data-number="6.5" class="anchored" data-anchor-id="the-mathematical-relationship"><span class="header-section-number">6.5</span> The Mathematical Relationship</h3>
<p>The Knowledge Theorem establishes that maximal cohesion equals complete and pure knowledge embodiment. This means:</p>
<ul>
<li><strong>Maximal cohesion</strong> → module contains exactly its change driver’s knowledge, nothing more, nothing less</li>
<li><strong>Pure module</strong> → contains no knowledge governed by other change drivers</li>
<li><strong>No foreign knowledge</strong> → cannot be affected by other change drivers</li>
<li><strong>Cannot be affected</strong> → no coupling to those other drivers</li>
</ul>
<p>The implication is direct: a module with maximal cohesion has minimal coupling <em>by construction</em>. You don’t achieve minimal coupling by “removing dependencies.” You achieve it by ensuring each module embodies exactly one change driver’s knowledge.</p>
<p><a id="cohesion-first-always"></a></p>
</section>
<section id="cohesion-first-always" class="level3" data-number="6.6">
<h3 data-number="6.6" class="anchored" data-anchor-id="cohesion-first-always"><span class="header-section-number">6.6</span> Cohesion First, Always</h3>
<p>This is why IVP-3 (“unit purity”) and IVP-4 (“unit completeness”) are both statements about <strong>cohesion</strong>:</p>
<ul>
<li>IVP-3 prevents impurity by forbidding foreign knowledge</li>
<li>IVP-4 ensures completeness by requiring related knowledge to stay together</li>
</ul>
<p>Both directives target cohesion. Neither mentions coupling directly. Yet IVP-compliant structure has minimal coupling as a <em>consequence</em>.</p>
<p>This suggests an inversion of the traditional emphasis. Rather than treating coupling as a first-order concern to be actively managed, we might better focus on cohesion. Coupling is a second-order effect—a consequence of how we organize knowledge. Get cohesion right, and coupling tends to minimize naturally.</p>
<hr>
<p><a id="classic-design-principles-1960s1990s"></a></p>
</section>
</section>
<section id="classic-design-principles-1960s1990s" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="classic-design-principles-1960s1990s"><span class="header-section-number">7</span> Classic Design Principles (1960s–1990s)</h2>
<p>The following foundational principles emerged from early software engineering research. Each addresses a specific aspect of software structure, and each finds its explanation in IVP.</p>
<hr>
<p><a id="separation-of-concerns-dijkstra"></a></p>
<section id="separation-of-concerns-dijkstra" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="separation-of-concerns-dijkstra"><span class="header-section-number">7.1</span> Separation of Concerns (Dijkstra)</h3>
<p><a id="what-dijkstra-actually-said-1974"></a></p>
<section id="what-dijkstra-actually-said-1974" class="level4" data-number="7.1.1">
<h4 data-number="7.1.1" class="anchored" data-anchor-id="what-dijkstra-actually-said-1974"><span class="header-section-number">7.1.1</span> What Dijkstra Actually Said (1974)</h4>
<blockquote class="blockquote">
<p>“Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one’s subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects.” — Dijkstra, “On the Role of Scientific Thought” (EWD447)</p>
</blockquote>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers" class="level4" data-number="7.1.2">
<h4 data-number="7.1.2" class="anchored" data-anchor-id="relevant-change-drivers"><span class="header-section-number">7.1.2</span> Relevant Change Drivers</h4>
<p>SoC applies whenever you have multiple independent dimensions of variation: - <code>γ_A</code> vs.&nbsp;<code>γ_B</code> vs.&nbsp;<code>γ_C</code> where each represents a distinct aspect of the system - Technical layers (presentation, logic, persistence) often have independent drivers - Domain modules often have independent drivers (different business stakeholders) - Pipeline stages may have independent drivers (different processing concerns)</p>
<p><a id="the-problem-with-soc"></a></p>
</section>
<section id="the-problem-with-soc" class="level4" data-number="7.1.3">
<h4 data-number="7.1.3" class="anchored" data-anchor-id="the-problem-with-soc"><span class="header-section-number">7.1.3</span> The Problem with SoC</h4>
<p>SoC provides no criterion for what constitutes a “concern” or “aspect.” Two architects can look at the same system and identify completely different concerns: - One sees “data access” and “business logic” as separate concerns - Another sees “user management” and “order processing” as the concerns - A third sees “validation,” “transformation,” and “persistence”</p>
<p>Who’s right? SoC provides no way to decide. It assumes you already know what the concerns are—but identifying concerns is often the hard part. As Dan North observed, “any non-trivial code can have any number of reasons to change”—so which decomposition is correct?</p>
<p><strong>How IVP addresses this</strong>: Concerns are defined by change drivers. A concern is a set of elements that vary for the same cause. This provides a more concrete criterion: analyze your version control history, identify who requests changes and why, map out the causal structure. The concerns emerge from domain reality rather than relying solely on architectural intuition.</p>
<p><a id="relationship-to-ivp-ivp-operationalizes-soc"></a></p>
</section>
<section id="relationship-to-ivp-ivp-operationalizes-soc" class="level4" data-number="7.1.4">
<h4 data-number="7.1.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-operationalizes-soc"><span class="header-section-number">7.1.4</span> Relationship to IVP: IVP Operationalizes SoC</h4>
<p>SoC and IVP share the same insight but operate at different levels of specificity:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 50%">
<col style="width: 50%">
</colgroup>
<thead>
<tr class="header">
<th>SoC</th>
<th>IVP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>“Separate different aspects”</td>
<td>“Separate elements that vary for different causes”</td>
</tr>
<tr class="even">
<td>Which aspects? Why? → Intuition</td>
<td>Which elements vary for different causes? → Causal analysis</td>
</tr>
</tbody>
</table>
<p><a id="what-ivp-adds"></a></p>
</section>
<section id="what-ivp-adds" class="level4" data-number="7.1.5">
<h4 data-number="7.1.5" class="anchored" data-anchor-id="what-ivp-adds"><span class="header-section-number">7.1.5</span> What IVP Adds</h4>
<p>SoC leaves critical questions unanswered:</p>
<ul>
<li><strong>What constitutes an “aspect”?</strong> IVP answers: aspects are defined by shared change drivers</li>
<li><strong>When should aspects be unified?</strong> SoC focuses only on separation; IVP provides the complementary directive (IVP-4)</li>
<li><strong>How to measure separation quality?</strong> SoC is qualitative; IVP enables measurement through cohesion metrics tied to change drivers</li>
</ul>
<p>In practice, this means: instead of relying on intuition about what constitutes a “concern,” analyze what actually changes together in your version control history. Concerns are defined by causal reality, not abstract categorization.</p>
<hr>
<p><a id="information-hiding-parnas"></a></p>
</section>
</section>
<section id="information-hiding-parnas" class="level3" data-number="7.2">
<h3 data-number="7.2" class="anchored" data-anchor-id="information-hiding-parnas"><span class="header-section-number">7.2</span> Information Hiding (Parnas)</h3>
<p><a id="what-parnas-actually-said-1972"></a></p>
<section id="what-parnas-actually-said-1972" class="level4" data-number="7.2.1">
<h4 data-number="7.2.1" class="anchored" data-anchor-id="what-parnas-actually-said-1972"><span class="header-section-number">7.2.1</span> What Parnas Actually Said (1972)</h4>
<blockquote class="blockquote">
<p>“We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others.”</p>
</blockquote>
<p>Note: Parnas did <strong>not</strong> mention “stable interfaces.” That phrase, while commonly associated with Information Hiding, is a later community interpretation—not Parnas’s words.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-1" class="level4" data-number="7.2.2">
<h4 data-number="7.2.2" class="anchored" data-anchor-id="relevant-change-drivers-1"><span class="header-section-number">7.2.2</span> Relevant Change Drivers</h4>
<p>Information Hiding addresses the boundary between: - <code>γ_client</code> (what clients need) vs.&nbsp;<code>γ_impl</code> (how it’s achieved internally) - The interface is stable; the implementation is volatile - Hiding is warranted when <code>γ_impl</code> is likely to change independently of <code>γ_client</code></p>
<p><a id="the-core-idea"></a></p>
</section>
<section id="the-core-idea" class="level4" data-number="7.2.3">
<h4 data-number="7.2.3" class="anchored" data-anchor-id="the-core-idea"><span class="header-section-number">7.2.3</span> The Core Idea</h4>
<p>The criterion is <strong>probabilistic</strong>: identify decisions “likely to change,” then hide them. This requires prediction—you must judge what’s likely to change. It’s an economic decision because hiding has costs (abstraction overhead), and you only pay those costs where the probability of change justifies them.</p>
<p>Note: while this <em>sounds</em> like DIP, they’re distinct principles. Information Hiding is <strong>probabilistic</strong>—it asks “what’s likely to change?” and requires prediction. DIP is <strong>structural</strong>—it prescribes dependency direction without asking about probability. DIP says “always depend on abstractions”; Information Hiding says “hide what’s likely to change.” The structural result may look similar, but the reasoning differs.</p>
<p><a id="relationship-to-ivp-different-concerns"></a></p>
</section>
<section id="relationship-to-ivp-different-concerns" class="level4" data-number="7.2.4">
<h4 data-number="7.2.4" class="anchored" data-anchor-id="relationship-to-ivp-different-concerns"><span class="header-section-number">7.2.4</span> Relationship to IVP: Different Concerns</h4>
<p>Information Hiding and IVP address <strong>different questions</strong>:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 79%">
<col style="width: 20%">
</colgroup>
<thead>
<tr class="header">
<th>Information Hiding</th>
<th>IVP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><em>Which</em> decisions should we hide?</td>
<td><em>How</em> should we structure if we decide to separate?</td>
</tr>
<tr class="even">
<td>Based on probability (“likely to change”)</td>
<td>Based on causal structure (independent change drivers)</td>
</tr>
<tr class="odd">
<td>Economic/predictive judgment</td>
<td>Structural/design guidance</td>
</tr>
</tbody>
</table>
<p><strong>IVP tells you how to separate concerns correctly.</strong> If you decide to separate client needs from implementation details, IVP-3 tells you how: elements varying for <code>γ_client</code> go in one module, elements varying for <code>γ_implementation</code> go in another.</p>
<p><strong>Information Hiding tells you whether to bother.</strong> Parnas’s criterion is probabilistic: hide decisions “likely to change.” This is an economic judgment—separation has costs (abstraction overhead, indirection complexity). You only pay those costs where the benefit (isolation from likely changes) justifies them.</p>
<p><a id="the-architects-two-step-decision"></a></p>
</section>
<section id="the-architects-two-step-decision" class="level4" data-number="7.2.5">
<h4 data-number="7.2.5" class="anchored" data-anchor-id="the-architects-two-step-decision"><span class="header-section-number">7.2.5</span> The Architect’s Two-Step Decision</h4>
<ol type="1">
<li><p><strong>IVP provides the structural analysis</strong>: “These concerns have independent change drivers. <em>If</em> we separate them, here’s how to do it correctly.”</p></li>
<li><p><strong>Economic judgment decides whether to apply it</strong>: “Is this separation worth it? How likely is change? What’s the cost of the abstraction? What’s the cost of <em>not</em> separating if change occurs?”</p></li>
</ol>
<p>IVP doesn’t make the economic decision for you. But it does three critical things:</p>
<ol type="1">
<li><strong>Clarifies what you’re deciding about</strong>: Which change drivers exist? Which are independent?</li>
<li><strong>Ensures correct boundaries</strong>: If you choose to separate, IVP tells you exactly where the lines should go</li>
<li><strong>Makes tradeoffs explicit</strong>: When you choose <em>not</em> to separate independent concerns, IVP tells you precisely what coupling you’re accepting—which future changes will ripple across boundaries</li>
</ol>
<p>This last point is crucial. Without IVP, you might skip a separation and not understand the cost. With IVP, you know: “I’m coupling <code>γ_pricing</code> and <code>γ_compliance</code> in this module. If either changes independently, I’ll pay the price.” That’s an informed tradeoff, not a blind one.</p>
<p><a id="what-ivp-adds"></a></p>
</section>
<section id="what-ivp-adds-1" class="level4" data-number="7.2.6">
<h4 data-number="7.2.6" class="anchored" data-anchor-id="what-ivp-adds-1"><span class="header-section-number">7.2.6</span> What IVP Adds</h4>
<p>Parnas provided the economic criterion (“likely to change”) but not a systematic way to identify <em>what</em> the independent concerns are or <em>how</em> to separate them correctly. IVP fills this gap:</p>
<ul>
<li><strong>Identifies change drivers</strong>: Who or what causes this code to change?</li>
<li><strong>Reveals independence</strong>: Are these change drivers independent?</li>
<li><strong>Guides the structure</strong>: If separating, ensure elements for each driver are isolated</li>
</ul>
<p>The practical approach: use IVP to map out the change drivers and their independence relationships. Then make informed economic decisions about <em>which</em> separations to invest in. You might identify ten potential separations but only implement three—the ones where change is likely enough to justify the cost. IVP ensures those three are done correctly.</p>
<hr>
<p><a id="dry-dont-repeat-yourself"></a></p>
</section>
</section>
<section id="dry-dont-repeat-yourself" class="level3" data-number="7.3">
<h3 data-number="7.3" class="anchored" data-anchor-id="dry-dont-repeat-yourself"><span class="header-section-number">7.3</span> DRY (Don’t Repeat Yourself)</h3>
<p><a id="what-hunt-thomas-said-1999"></a></p>
<section id="what-hunt-thomas-said-1999" class="level4" data-number="7.3.1">
<h4 data-number="7.3.1" class="anchored" data-anchor-id="what-hunt-thomas-said-1999"><span class="header-section-number">7.3.1</span> What Hunt &amp; Thomas Said (1999)</h4>
<blockquote class="blockquote">
<p>“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” — Hunt &amp; Thomas, <em>The Pragmatic Programmer</em></p>
</blockquote>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-2" class="level4" data-number="7.3.2">
<h4 data-number="7.3.2" class="anchored" data-anchor-id="relevant-change-drivers-2"><span class="header-section-number">7.3.2</span> Relevant Change Drivers</h4>
<p>DRY concerns arise when code appears similar but may represent different knowledge: - <code>γ_A</code> vs.&nbsp;<code>γ_B</code> — two pieces of code look identical but change for different reasons - Same change driver → same knowledge → extract (IVP-4) - Different change drivers → different knowledge → keep separate despite similarity (IVP-3)</p>
<p><a id="the-problem-with-dry"></a></p>
</section>
<section id="the-problem-with-dry" class="level4" data-number="7.3.3">
<h4 data-number="7.3.3" class="anchored" data-anchor-id="the-problem-with-dry"><span class="header-section-number">7.3.3</span> The Problem with DRY</h4>
<p>DRY itself is sound—it speaks of <em>knowledge</em>, not code. But in practice, developers often apply DRY based on <strong>structural similarity</strong> rather than <strong>knowledge identity</strong>. Two pieces of code can look identical yet represent different knowledge: - Email validation in user registration - Email validation in newsletter signup</p>
<p>These might have identical implementations today, but they represent different business decisions. Marketing might relax newsletter validation while security tightens user registration validation. They <em>look</em> the same but <em>are</em> different knowledge.</p>
<p>DRY provides no criterion for distinguishing “same knowledge” from “coincidentally similar code.” Without such a criterion, teams extract “shared” code, then discover that changes for one use case break the other.</p>
<p><strong>Additional problems with DRY in practice:</strong></p>
<ol type="1">
<li><p><strong>Premature abstraction</strong>: Developers extract patterns before understanding how components will diverge. As Kent C. Dodds advocates with “AHA Programming” (Avoid Hasty Abstractions), it’s cheaper to wait for a pattern to emerge than to undo a bad abstraction.</p></li>
<li><p><strong>Hidden coupling</strong>: DRY’d abstractions become “optimized for keeping all components the same”—they’re coupled together with no affordances for elements to evolve in diverging directions.</p></li>
<li><p><strong>Increased complexity</strong>: Reading DRY’d code requires jumping between abstraction layers, maintaining mental state across indirections. Linear, “duplicated” code is often easier to understand.</p></li>
<li><p><strong>The sunk cost trap</strong>: Once engineers invest in an abstraction, they tend to continue iterating on it rather than recognizing when it’s the wrong abstraction.</p></li>
</ol>
<p><strong>How IVP addresses this</strong>: IVP provides the missing criterion. Same knowledge = same change driver. If two pieces of code change for the same reason (same authority, same business rule), they represent the same knowledge—extract them. If they change for different reasons, they’re different knowledge despite structural similarity—keep them separate. This prevents premature abstraction by requiring causal analysis before extraction.</p>
<p><a id="relationship-to-ivp-context-dependent"></a></p>
</section>
<section id="relationship-to-ivp-context-dependent" class="level4" data-number="7.3.4">
<h4 data-number="7.3.4" class="anchored" data-anchor-id="relationship-to-ivp-context-dependent"><span class="header-section-number">7.3.4</span> Relationship to IVP: Context-Dependent</h4>
<p>DRY’s relationship to IVP is <strong>context-dependent</strong>: duplication sometimes violates IVP, sometimes satisfies it.</p>
<p><strong>Case 1: True Duplication (DRY and IVP agree)</strong></p>
<p>Email validation in both user registration and contact form: - Both implement the same rule - Both change for the same cause (email format requirements) - IVP-4 applies: extract to shared module</p>
<p><strong>Case 2: Accidental Similarity (IVP overrides DRY)</strong></p>
<p>Order total calculation and inventory value calculation: - Both sum item values - Order total changes for <code>γ_pricing</code> (pricing rules) - Inventory value changes for <code>γ_accounting</code> (cost accounting rules) - <code>γ_pricing ⊥ γ_accounting</code> (independent) - IVP-3 applies: keep separate despite structural similarity</p>
<p><a id="the-dry-trap"></a></p>
</section>
<section id="the-dry-trap" class="level4" data-number="7.3.5">
<h4 data-number="7.3.5" class="anchored" data-anchor-id="the-dry-trap"><span class="header-section-number">7.3.5</span> The DRY Trap</h4>
<p>Blindly applying DRY to accidental similarity creates a shared utility. When pricing rules evolve, the shared utility changes, forcing inventory calculations to revalidate despite no business reason—violating IVP-3.</p>
<p><a id="what-ivp-adds"></a></p>
</section>
<section id="what-ivp-adds-2" class="level4" data-number="7.3.6">
<h4 data-number="7.3.6" class="anchored" data-anchor-id="what-ivp-adds-2"><span class="header-section-number">7.3.6</span> What IVP Adds</h4>
<p>DRY observes that duplication is often problematic but doesn’t explain <em>why</em> or <em>when</em>. IVP provides the criterion:</p>
<ul>
<li>If duplication represents <strong>the same knowledge</strong> varying for the same cause: eliminate it (DRY and IVP-4 agree)</li>
<li>If duplication represents <strong>coincidentally similar code</strong> varying for different causes: preserve it (IVP-3 overrides DRY)</li>
</ul>
<p>The question to ask before extracting “duplicate” code: <em>Do these pieces change for the same reason?</em> If not, the apparent duplication is actually appropriate separation.</p>
<hr>
<p><a id="kiss-keep-it-simple-stupid"></a></p>
</section>
</section>
<section id="kiss-keep-it-simple-stupid" class="level3" data-number="7.4">
<h3 data-number="7.4" class="anchored" data-anchor-id="kiss-keep-it-simple-stupid"><span class="header-section-number">7.4</span> KISS (Keep It Simple, Stupid)</h3>
<p><a id="the-principle"></a></p>
<section id="the-principle" class="level4" data-number="7.4.1">
<h4 data-number="7.4.1" class="anchored" data-anchor-id="the-principle"><span class="header-section-number">7.4.1</span> The Principle</h4>
<p>KISS is a design principle originating from the U.S. Navy (1960s). Unlike the other principles, it has no single canonical statement—it’s a folk principle advocating simplicity.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-3" class="level4" data-number="7.4.2">
<h4 data-number="7.4.2" class="anchored" data-anchor-id="relevant-change-drivers-3"><span class="header-section-number">7.4.2</span> Relevant Change Drivers</h4>
<p>Complexity concerns arise when independent change drivers are accidentally coupled: - <code>γ_A</code> entangled with <code>γ_B</code> where <code>γ_A ⊥ γ_B</code> — accidental coupling - Cross-cutting concerns scattered across multiple modules - Essential coupling (<code>γ_A</code> with <code>γ_A</code>) is necessary; accidental coupling (<code>γ_A</code> with <code>γ_B</code>) is unnecessary complexity</p>
<p><a id="the-problem-with-kiss"></a></p>
</section>
<section id="the-problem-with-kiss" class="level4" data-number="7.4.3">
<h4 data-number="7.4.3" class="anchored" data-anchor-id="the-problem-with-kiss"><span class="header-section-number">7.4.3</span> The Problem with KISS</h4>
<p>KISS provides no criterion for what counts as “simple” or “unnecessary.” Every developer thinks their solution is simple; complexity is always justified by some rationale: - “We need this abstraction for testability” - “This pattern makes future changes easier” - “This indirection enables flexibility”</p>
<p>Without an objective measure, KISS becomes a rhetorical weapon: “Your solution is too complex” really means “I don’t understand it” or “I would have done it differently.” Two developers can disagree about simplicity with no way to resolve the dispute.</p>
<p><strong>How IVP addresses this</strong>: IVP offers a more precise definition: unnecessary complexity is <strong>accidental coupling</strong>—coupling between elements that vary for independent causes. While determining independence still requires analysis, this gives you something concrete to examine: do these things change for the same reason or different reasons? Coupling things that change independently is unnecessary complexity; coupling things that change together is essential structure.</p>
<p><a id="relationship-to-ivp-ivp-operationalizes-kiss"></a></p>
</section>
<section id="relationship-to-ivp-ivp-operationalizes-kiss" class="level4" data-number="7.4.4">
<h4 data-number="7.4.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-operationalizes-kiss"><span class="header-section-number">7.4.4</span> Relationship to IVP: IVP Operationalizes KISS</h4>
<p>KISS identifies the goal; IVP provides the method.</p>
<p><strong>Accidental vs.&nbsp;Essential Complexity</strong> (Brooks): - <strong>Essential complexity</strong>: inherent to the problem - <strong>Accidental complexity</strong>: arising from the solution</p>
<p>IVP provides precise definitions: - <strong>Essential coupling</strong>: elements coupled because they vary for the same cause (IVP-4 mandates this) - <strong>Accidental coupling</strong>: elements coupled despite varying for different causes (IVP-3 violation)</p>
<p>Accidental coupling creates accidental complexity. IVP-3 eliminates accidental coupling, thereby minimizing accidental complexity—exactly what KISS prescribes.</p>
<p><a id="what-ivp-adds"></a></p>
</section>
<section id="what-ivp-adds-3" class="level4" data-number="7.4.5">
<h4 data-number="7.4.5" class="anchored" data-anchor-id="what-ivp-adds-3"><span class="header-section-number">7.4.5</span> What IVP Adds</h4>
<p>KISS is vague: what’s “unnecessary”? IVP makes it precise: unnecessary complexity arises from <strong>accidental coupling</strong>—coupling elements that vary for independent causes.</p>
<p>When evaluating complexity, the useful question is: <em>Is this coupling essential (things that genuinely change together) or accidental (independent concerns entangled)?</em></p>
<hr>
<p><a id="law-of-demeter-principle-of-least-knowledge"></a></p>
</section>
</section>
<section id="law-of-demeter-principle-of-least-knowledge" class="level3" data-number="7.5">
<h3 data-number="7.5" class="anchored" data-anchor-id="law-of-demeter-principle-of-least-knowledge"><span class="header-section-number">7.5</span> Law of Demeter (Principle of Least Knowledge)</h3>
<p><a id="what-lieberherr-said-1989"></a></p>
<section id="what-lieberherr-said-1989" class="level4" data-number="7.5.1">
<h4 data-number="7.5.1" class="anchored" data-anchor-id="what-lieberherr-said-1989"><span class="header-section-number">7.5.1</span> What Lieberherr Said (1989)</h4>
<blockquote class="blockquote">
<p>“A method should only call methods of: (1) itself, (2) its parameters, (3) objects it creates, (4) its direct components.” — Lieberherr et al., “Assuring Good Style for Object-Oriented Programs”</p>
</blockquote>
<p>Informally: “Don’t talk to strangers.”</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-4" class="level4" data-number="7.5.2">
<h4 data-number="7.5.2" class="anchored" data-anchor-id="relevant-change-drivers-4"><span class="header-section-number">7.5.2</span> Relevant Change Drivers</h4>
<p>LoD concerns arise in chains that traverse independently-varying structures: - <code>γ_A</code> → <code>γ_B</code> → <code>γ_C</code> — each link may have an independent change driver - The more independent drivers in a chain, the more fragile the coupling - Train wrecks couple the client to <code>n</code> independent sources of change</p>
<p><a id="the-problem-with-lod"></a></p>
</section>
<section id="the-problem-with-lod" class="level4" data-number="7.5.3">
<h4 data-number="7.5.3" class="anchored" data-anchor-id="the-problem-with-lod"><span class="header-section-number">7.5.3</span> The Problem with LoD</h4>
<p>LoD is often called the “Suggestion of Demeter” because it’s so easy to violate and hard to follow strictly. Several issues arise:</p>
<ol type="1">
<li><p><strong>Delegation can be a false solution</strong>: Using wrapper methods to hide violations removes visible evidence but doesn’t actually decouple the code—it just hides tight coupling.</p></li>
<li><p><strong>Strict adherence leads to “wrapper hell”</strong>: Numerous small wrapper methods can introduce excessive indirection, making code harder to read than the original “train wreck.”</p></li>
<li><p><strong>Data structures are often exempt</strong>: When accessing pure data structures (DTOs, configuration objects), strict LoD application adds ceremony without benefit.</p></li>
<li><p><strong>No clear boundary</strong>: How many dots are too many? LoD provides no criterion for when a chain becomes problematic.</p></li>
</ol>
<p><strong>How IVP addresses this</strong>: IVP explains <em>why</em> train wrecks are problematic: each link in the chain is a potential independent change driver. Count the independent things that could change and break the chain. If <code>order.getCustomer().getAddress().getZipCode()</code> involves three independently changing structures, that’s the problem—not the dot count itself. Data structure chains where everything changes together are less concerning.</p>
<p><a id="relationship-to-ivp-bidirectional-equivalence"></a></p>
</section>
<section id="relationship-to-ivp-bidirectional-equivalence" class="level4" data-number="7.5.4">
<h4 data-number="7.5.4" class="anchored" data-anchor-id="relationship-to-ivp-bidirectional-equivalence"><span class="header-section-number">7.5.4</span> Relationship to IVP: Bidirectional Equivalence</h4>
<p>LoD is <strong>IVP-3 applied to method invocation scope</strong>.</p>
<p>Train wreck: <code>order.getCustomer().getAddress().getZipCode()</code></p>
<p>Client <code>C</code> now varies for three independent causes: - <code>γ_C</code>: client’s own requirements - <code>γ_Customer</code>: Customer structure changes - <code>γ_Address</code>: Address structure changes</p>
<p>This violates IVP-3. The fix (delegate to <code>order.getCustomerZipCode()</code>) is IVP-3 in action.</p>
<p><a id="what-ivp-adds"></a></p>
</section>
<section id="what-ivp-adds-4" class="level4" data-number="7.5.5">
<h4 data-number="7.5.5" class="anchored" data-anchor-id="what-ivp-adds-4"><span class="header-section-number">7.5.5</span> What IVP Adds</h4>
<p>LoD gives the rule; IVP explains <em>why</em>: train wrecks couple clients to multiple independent variation sources.</p>
<p>When you see a long method chain, the relevant question is: <em>How many independent things could change and break this chain?</em> Each independent change source is a reason to encapsulate.</p>
<hr>
<p><a id="principle-of-least-surprise"></a></p>
</section>
</section>
<section id="principle-of-least-surprise" class="level3" data-number="7.6">
<h3 data-number="7.6" class="anchored" data-anchor-id="principle-of-least-surprise"><span class="header-section-number">7.6</span> Principle of Least Surprise</h3>
<p><a id="the-principle"></a></p>
<section id="the-principle-1" class="level4" data-number="7.6.1">
<h4 data-number="7.6.1" class="anchored" data-anchor-id="the-principle-1"><span class="header-section-number">7.6.1</span> The Principle</h4>
<p>The Principle of Least Surprise (also called Principle of Least Astonishment) is a folk principle with no single canonical source. It states that system behavior should match user expectations.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-5" class="level4" data-number="7.6.2">
<h4 data-number="7.6.2" class="anchored" data-anchor-id="relevant-change-drivers-5"><span class="header-section-number">7.6.2</span> Relevant Change Drivers</h4>
<p>PoLS doesn’t address change drivers—it addresses human cognition: - User expectations, domain conventions, platform idioms - These aren’t change drivers in the IVP sense - PoLS is orthogonal to IVP: understandability vs.&nbsp;evolvability</p>
<p><a id="the-problem-with-pols"></a></p>
</section>
<section id="the-problem-with-pols" class="level4" data-number="7.6.3">
<h4 data-number="7.6.3" class="anchored" data-anchor-id="the-problem-with-pols"><span class="header-section-number">7.6.3</span> The Problem with PoLS</h4>
<p>PoLS is <strong>subjective and non-actionable</strong>. “Least surprise” depends entirely on <em>whose</em> expectations: - A novice expects different behavior than an expert - A user from one domain brings different assumptions than another - Even the same person’s expectations change over time</p>
<p>How do you objectively apply PoLS? You can’t. It provides no method, no criterion, no way to resolve disagreements. Two developers can disagree about what’s “surprising” with no way to arbitrate.</p>
<p><strong>IVP doesn’t address this</strong>: IVP and PoLS solve different problems. IVP provides objective criteria for structural organization (evolvability). PoLS addresses human comprehension (understandability). IVP can’t make PoLS objective—but it doesn’t need to. They’re orthogonal concerns.</p>
<p><a id="relationship-to-ivp-orthogonal"></a></p>
</section>
<section id="relationship-to-ivp-orthogonal" class="level4" data-number="7.6.4">
<h4 data-number="7.6.4" class="anchored" data-anchor-id="relationship-to-ivp-orthogonal"><span class="header-section-number">7.6.4</span> Relationship to IVP: Orthogonal</h4>
<p>PoLS and IVP address fundamentally different concerns: - <strong>PoLS</strong>: Human comprehension—how understandable is the system? (subjective) - <strong>IVP</strong>: Structural evolution—how independently can concerns vary? (objective)</p>
<p>Neither implies the other: - An IVP-compliant system can violate PoLS (surprising behavior despite good structure) - A PoLS-compliant system can violate IVP (unsurprising but tightly coupled)</p>
<p><strong>Practical note</strong>: PoLS is a reasonable <em>goal</em> but not a <em>principle</em> in any actionable sense. IVP, by contrast, provides criteria grounded in causal analysis of change drivers—though applying IVP still requires domain knowledge and judgment.</p>
<hr>
<p><a id="conways-law"></a></p>
</section>
</section>
<section id="conways-law" class="level3" data-number="7.7">
<h3 data-number="7.7" class="anchored" data-anchor-id="conways-law"><span class="header-section-number">7.7</span> Conway’s Law</h3>
<p><a id="what-conway-said-1968"></a></p>
<section id="what-conway-said-1968" class="level4" data-number="7.7.1">
<h4 data-number="7.7.1" class="anchored" data-anchor-id="what-conway-said-1968"><span class="header-section-number">7.7.1</span> What Conway Said (1968)</h4>
<blockquote class="blockquote">
<p>“Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.” — Melvin Conway, “How Do Committees Invent?”</p>
</blockquote>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-6" class="level4" data-number="7.7.2">
<h4 data-number="7.7.2" class="anchored" data-anchor-id="relevant-change-drivers-6"><span class="header-section-number">7.7.2</span> Relevant Change Drivers</h4>
<p>Conway’s Law maps organizational structure to architectural structure: - Team boundaries become module boundaries - The question: do team boundaries align with genuine domain change drivers? - If <code>γ_team</code> matches <code>γ_domain</code>, Conway alignment is beneficial - If <code>γ_team</code> ≠ <code>γ_domain</code>, Conway produces IVP-violating structure</p>
<p><a id="the-problem-with-conways-law"></a></p>
</section>
<section id="the-problem-with-conways-law" class="level4" data-number="7.7.3">
<h4 data-number="7.7.3" class="anchored" data-anchor-id="the-problem-with-conways-law"><span class="header-section-number">7.7.3</span> The Problem with Conway’s Law</h4>
<p>Conway’s Law is an observation, not a prescription—yet it’s often treated as guidance. Several issues arise:</p>
<ol type="1">
<li><p><strong>It doesn’t guarantee quality</strong>: Even if architecture matches organization, the result can still be poorly designed. Mirroring doesn’t imply correctness.</p></li>
<li><p><strong>It limits innovation</strong>: Current team structures constrain the solution space. As Conway himself noted, “there is a class of design alternatives which cannot be effectively pursued” because necessary communication paths don’t exist.</p></li>
<li><p><strong>Path dependency traps</strong>: Existing systems impose structure on organizations. You’re constrained by how you got here, not by what’s optimal now.</p></li>
<li><p><strong>Turf wars and silos</strong>: Teams become protective of their domains, leading to segmented knowledge and resistance to collaboration.</p></li>
<li><p><strong>Inverse Conway is hard</strong>: Reorganizing teams doesn’t immediately fix embedded architecture. The existing code “pushes back” against new structures.</p></li>
</ol>
<p><strong>How IVP addresses this</strong>: IVP provides the criterion for <em>when</em> Conway alignment is beneficial. If team boundaries match change driver boundaries, Conway’s Law produces IVP-compliant structure—embrace it. If organizational structure doesn’t align with change drivers (e.g., frontend/backend split when features span both), Conway’s Law produces IVP-violating structure—resist it or restructure teams.</p>
<p><a id="relationship-to-ivp-ivp-explains-when-conways-law-is-beneficial"></a></p>
</section>
<section id="relationship-to-ivp-ivp-explains-when-conways-law-is-beneficial" class="level4" data-number="7.7.4">
<h4 data-number="7.7.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-explains-when-conways-law-is-beneficial"><span class="header-section-number">7.7.4</span> Relationship to IVP: IVP Explains When Conway’s Law Is Beneficial</h4>
<p>Conway’s Law is an observation, not a prescription. IVP explains <em>why</em> it holds and <em>when</em> to embrace it:</p>
<p><strong>When to embrace</strong>: If teams represent independent change drivers (Team A owns payments changing for payment reasons; Team B owns inventory changing for inventory reasons), architectural boundaries <em>should</em> match team boundaries. Conway’s Law producing IVP-compliant structure is beneficial.</p>
<p><strong>When to resist</strong>: If organizational structure doesn’t align with change drivers (frontend/backend split but features require changes to both), Conway’s Law produces IVP-violating structure. Every feature requires coordination.</p>
<p><strong>Practical improvement</strong>: Ask: <em>Do our team boundaries match our change driver boundaries?</em> If not, consider restructuring teams or accepting the coordination overhead.</p>
<hr>
<p><a id="tell-dont-ask"></a></p>
</section>
</section>
<section id="tell-dont-ask" class="level3" data-number="7.8">
<h3 data-number="7.8" class="anchored" data-anchor-id="tell-dont-ask"><span class="header-section-number">7.8</span> Tell, Don’t Ask</h3>
<p><a id="the-principle"></a></p>
<section id="the-principle-2" class="level4" data-number="7.8.1">
<h4 data-number="7.8.1" class="anchored" data-anchor-id="the-principle-2"><span class="header-section-number">7.8.1</span> The Principle</h4>
<blockquote class="blockquote">
<p>“Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.” — Attributed to various OO practitioners</p>
</blockquote>
<p>Rather than querying an object’s state and acting on it externally, tell the object to perform the action itself.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-7" class="level4" data-number="7.8.2">
<h4 data-number="7.8.2" class="anchored" data-anchor-id="relevant-change-drivers-7"><span class="header-section-number">7.8.2</span> Relevant Change Drivers</h4>
<p>Tell, Don’t Ask concerns data/behavior co-location: - <code>γ_data</code> + <code>γ_behavior</code> — same driver? Co-locate (IVP-4) - <code>γ_data</code> vs.&nbsp;<code>γ_consumer</code> — different drivers? Querying is appropriate - The question: does the behavior change for the same reason as the data?</p>
<p><a id="the-problem-with-tell-dont-ask"></a></p>
</section>
<section id="the-problem-with-tell-dont-ask" class="level4" data-number="7.8.3">
<h4 data-number="7.8.3" class="anchored" data-anchor-id="the-problem-with-tell-dont-ask"><span class="header-section-number">7.8.3</span> The Problem with Tell, Don’t Ask</h4>
<p>Tell, Don’t Ask can be misused to eliminate all getters, even when querying is appropriate. Martin Fowler notes: “I’ve seen it encourage people to become GetterEradicators.” Sometimes you genuinely need to ask an object for information—reporting, serialization, display logic.</p>
<p><strong>How IVP addresses this</strong>: The issue isn’t asking vs.&nbsp;telling—it’s where the <em>knowledge</em> lives. If the logic operating on data should change for the same reasons as the data itself, co-locate them (IVP-4). If query results are consumed by code with a different change driver (e.g., UI rendering), separation is appropriate.</p>
<p><a id="relationship-to-ivp-ivp-refines-tell-dont-ask"></a></p>
</section>
<section id="relationship-to-ivp-ivp-refines-tell-dont-ask" class="level4" data-number="7.8.4">
<h4 data-number="7.8.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-refines-tell-dont-ask"><span class="header-section-number">7.8.4</span> Relationship to IVP: IVP Refines Tell, Don’t Ask</h4>
<p>Tell, Don’t Ask is about co-locating behavior with data. IVP explains <em>when</em> this matters: when behavior and data share a change driver. External queries are fine when the consumer varies independently.</p>
<hr>
<p><a id="command-query-separation-cqs"></a></p>
</section>
</section>
<section id="command-query-separation-cqs" class="level3" data-number="7.9">
<h3 data-number="7.9" class="anchored" data-anchor-id="command-query-separation-cqs"><span class="header-section-number">7.9</span> Command Query Separation (CQS)</h3>
<p><a id="what-meyer-said-1988"></a></p>
<section id="what-meyer-said-1988" class="level4" data-number="7.9.1">
<h4 data-number="7.9.1" class="anchored" data-anchor-id="what-meyer-said-1988"><span class="header-section-number">7.9.1</span> What Meyer Said (1988)</h4>
<blockquote class="blockquote">
<p>“Every method should either be a command that performs an action, or a query that returns data to the caller, but not both.” — Bertrand Meyer, <em>Object-Oriented Software Construction</em></p>
</blockquote>
<p>Asking a question should not change the answer.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-8" class="level4" data-number="7.9.2">
<h4 data-number="7.9.2" class="anchored" data-anchor-id="relevant-change-drivers-8"><span class="header-section-number">7.9.2</span> Relevant Change Drivers</h4>
<p>CQS addresses predictability rather than change drivers per se: - <code>γ_query</code> vs.&nbsp;<code>γ_command</code> — may or may not be independent - CQS is about preventing hidden coupling, not organizing known variation - Orthogonal to IVP: CQS ensures predictability; IVP ensures evolvability</p>
<p><a id="the-problem-with-cqs"></a></p>
</section>
<section id="the-problem-with-cqs" class="level4" data-number="7.9.3">
<h4 data-number="7.9.3" class="anchored" data-anchor-id="the-problem-with-cqs"><span class="header-section-number">7.9.3</span> The Problem with CQS</h4>
<p>CQS introduces complexity for operations that naturally combine both—popping a stack, generating a unique ID, acquiring a lock. Strict adherence requires awkward workarounds. CQS also complicates concurrent code where atomic query-then-command operations are necessary.</p>
<p><strong>How IVP addresses this</strong>: CQS is about <em>predictability</em>, not change drivers. IVP doesn’t directly address CQS. However, CQS violations often create hidden state changes—accidental coupling between querying code and state. When queries have side effects, consumers are coupled to variation they didn’t expect.</p>
<p><a id="relationship-to-ivp-complementary"></a></p>
</section>
<section id="relationship-to-ivp-complementary" class="level4" data-number="7.9.4">
<h4 data-number="7.9.4" class="anchored" data-anchor-id="relationship-to-ivp-complementary"><span class="header-section-number">7.9.4</span> Relationship to IVP: Complementary</h4>
<p>CQS ensures predictability; IVP ensures evolvability. Both reduce accidental coupling, but through different mechanisms. CQS prevents queries from introducing unexpected variation; IVP organizes variation that legitimately exists.</p>
<hr>
<p><a id="xp-and-agile-principles-1990s2000s"></a></p>
</section>
</section>
</section>
<section id="xp-and-agile-principles-1990s2000s" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="xp-and-agile-principles-1990s2000s"><span class="header-section-number">8</span> XP and Agile Principles (1990s–2000s)</h2>
<p>Extreme Programming and the Agile movement brought a focus on evolutionary design, simplicity, and responding to change. These principles complement IVP’s emphasis on change drivers.</p>
<hr>
<p><a id="yagni-you-arent-gonna-need-it"></a></p>
<section id="yagni-you-arent-gonna-need-it" class="level3" data-number="8.1">
<h3 data-number="8.1" class="anchored" data-anchor-id="yagni-you-arent-gonna-need-it"><span class="header-section-number">8.1</span> YAGNI (You Aren’t Gonna Need It)</h3>
<p><a id="what-beck-jeffries-said-1999"></a></p>
<section id="what-beck-jeffries-said-1999" class="level4" data-number="8.1.1">
<h4 data-number="8.1.1" class="anchored" data-anchor-id="what-beck-jeffries-said-1999"><span class="header-section-number">8.1.1</span> What Beck &amp; Jeffries Said (1999)</h4>
<blockquote class="blockquote">
<p>“Always implement things when you actually need them, never when you just foresee that you need them.” — Ron Jeffries, XP co-founder</p>
</blockquote>
<p>YAGNI emerged from Extreme Programming (XP), coined by Kent Beck.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-9" class="level4" data-number="8.1.2">
<h4 data-number="8.1.2" class="anchored" data-anchor-id="relevant-change-drivers-9"><span class="header-section-number">8.1.2</span> Relevant Change Drivers</h4>
<p>YAGNI concerns hypothetical vs.&nbsp;actual change drivers: - <code>γ_actual</code> — change driver that exists now, requires handling - <code>γ_hypothetical</code> — speculated future driver, may never materialize - Abstraction is premature if only one actual driver exists</p>
<p><a id="the-problem-with-yagni"></a></p>
</section>
<section id="the-problem-with-yagni" class="level4" data-number="8.1.3">
<h4 data-number="8.1.3" class="anchored" data-anchor-id="the-problem-with-yagni"><span class="header-section-number">8.1.3</span> The Problem with YAGNI</h4>
<p>YAGNI provides no criterion for distinguishing “needed now” from “needed soon.” Developers disagree about what’s speculative: - “We’ll definitely need this abstraction when we add the second payment provider” - “This validation layer will be necessary when requirements change”</p>
<p>Without a framework, YAGNI becomes a rhetorical tool—some invoke it to block useful preparation, others ignore it to justify over-engineering.</p>
<p><strong>How IVP addresses this</strong>: Build abstractions when you identify <em>actual</em> independent change drivers. If you have one payment provider and no concrete second one, there’s one change driver—no abstraction needed. When a second provider appears (a new change driver), <em>then</em> IVP-3 mandates separation. IVP grounds YAGNI in causal reality rather than speculation.</p>
<p><a id="relationship-to-ivp-ivp-operationalizes-yagni"></a></p>
</section>
<section id="relationship-to-ivp-ivp-operationalizes-yagni" class="level4" data-number="8.1.4">
<h4 data-number="8.1.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-operationalizes-yagni"><span class="header-section-number">8.1.4</span> Relationship to IVP: IVP Operationalizes YAGNI</h4>
<p>YAGNI says “don’t build it until you need it.” IVP says “don’t separate until you have independent change drivers.” Both resist premature structure, but IVP provides the criterion: genuine independent variation, not hypothetical future variation.</p>
<hr>
<p><a id="four-rules-of-simple-design-kent-beck"></a></p>
</section>
</section>
<section id="four-rules-of-simple-design-kent-beck" class="level3" data-number="8.2">
<h3 data-number="8.2" class="anchored" data-anchor-id="four-rules-of-simple-design-kent-beck"><span class="header-section-number">8.2</span> Four Rules of Simple Design (Kent Beck)</h3>
<p>Kent Beck developed these rules while creating Extreme Programming in the late 1990s. The rules are in priority order.</p>
<blockquote class="blockquote">
<ol type="1">
<li>Passes the tests</li>
<li>Reveals intention</li>
<li>No duplication</li>
<li>Fewest elements — Kent Beck, <em>Extreme Programming Explained</em></li>
</ol>
</blockquote>
<hr>
<p><a id="rule-1-passes-the-tests"></a></p>
<section id="rule-1-passes-the-tests" class="level4" data-number="8.2.1">
<h4 data-number="8.2.1" class="anchored" data-anchor-id="rule-1-passes-the-tests"><span class="header-section-number">8.2.1</span> Rule 1: Passes the Tests</h4>
<p><strong>The Rule</strong>: The code must work correctly—all tests pass.</p>
<p><strong>Relevant Change Drivers</strong>: None directly. This is a correctness constraint, not a structural principle. Tests verify functional behavior, not evolvability.</p>
<p><strong>The Problem</strong>: “Passes tests” is necessary but not sufficient. Code can pass all tests while being poorly structured, tightly coupled, and hard to evolve.</p>
<p><strong>Relationship to IVP</strong>: Orthogonal. IVP addresses evolvability; passing tests addresses correctness. Both are necessary; neither implies the other.</p>
<hr>
<p><a id="rule-2-reveals-intention"></a></p>
</section>
<section id="rule-2-reveals-intention" class="level4" data-number="8.2.2">
<h4 data-number="8.2.2" class="anchored" data-anchor-id="rule-2-reveals-intention"><span class="header-section-number">8.2.2</span> Rule 2: Reveals Intention</h4>
<p><strong>The Rule</strong>: Code should clearly communicate its purpose. Names, structure, and organization should make the code’s intent obvious.</p>
<p><strong>Relevant Change Drivers</strong>: This addresses human cognition, not change drivers. Like PoLS, it’s about understandability rather than evolvability.</p>
<p><strong>The Problem</strong>: “Intention” is subjective—intention to whom? A domain expert reads code differently than a junior developer. The principle provides no criterion for resolving disagreements about clarity.</p>
<p><strong>Relationship to IVP</strong>: Orthogonal. IVP addresses evolvability; revealing intention addresses understandability. IVP-compliant code can be unclear; clear code can violate IVP. Both dimensions matter independently.</p>
<hr>
<p><a id="rule-3-no-duplication"></a></p>
</section>
<section id="rule-3-no-duplication" class="level4" data-number="8.2.3">
<h4 data-number="8.2.3" class="anchored" data-anchor-id="rule-3-no-duplication"><span class="header-section-number">8.2.3</span> Rule 3: No Duplication</h4>
<p><strong>The Rule</strong>: Each piece of knowledge should appear exactly once. Eliminate redundant code.</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_A</code> vs.&nbsp;<code>γ_B</code> — two pieces of code look identical but may change for different reasons - Same change driver → same knowledge → extract (IVP-4) - Different change drivers → different knowledge → keep separate despite similarity (IVP-3)</p>
<p><strong>The Problem</strong>: Same as DRY—when is duplication “same knowledge” vs.&nbsp;“coincidentally similar code”? Without a criterion, teams extract “shared” code that later needs to diverge.</p>
<p><strong>How IVP addresses this</strong>: Same knowledge = same change driver. If two pieces of code would change for the same reason (same authority, same business rule), they represent the same knowledge—eliminate duplication. If they’d change for different reasons, they’re different knowledge despite structural similarity—keep them separate.</p>
<p><strong>Relationship to IVP</strong>: IVP-4 provides the criterion. “No duplication” is correct when duplication represents the same change driver.</p>
<hr>
<p><a id="rule-4-fewest-elements"></a></p>
</section>
<section id="rule-4-fewest-elements" class="level4" data-number="8.2.4">
<h4 data-number="8.2.4" class="anchored" data-anchor-id="rule-4-fewest-elements"><span class="header-section-number">8.2.4</span> Rule 4: Fewest Elements</h4>
<p><strong>The Rule</strong>: Subject to the above rules, minimize the number of classes, methods, and other structural elements.</p>
<p><strong>Relevant Change Drivers</strong>: This rule constrains structure—don’t add elements beyond what’s needed.</p>
<p><strong>The Problem</strong>: “Fewest elements” can conflict with “reveals intention”—sometimes more classes with clearer names are better than fewer obscure ones. The priority ordering (intention &gt; fewest) helps but doesn’t resolve all tensions.</p>
<p><strong>How IVP addresses this</strong>: Elements should map to change drivers. If you have three independent concerns, three classes is appropriate—not “too many.” If you have one concern, one class is appropriate—additional structure is accidental complexity.</p>
<p><strong>Relationship to IVP</strong>: IVP explains when elements are “necessary”—one module per change driver. “Fewest elements” means don’t create structure beyond what change drivers require.</p>
<hr>
<p><a id="the-four-rules-together"></a></p>
</section>
<section id="the-four-rules-together" class="level4" data-number="8.2.5">
<h4 data-number="8.2.5" class="anchored" data-anchor-id="the-four-rules-together"><span class="header-section-number">8.2.5</span> The Four Rules Together</h4>
<p>The rules are valuable but incomplete without a unifying criterion. IVP provides that criterion for rules 3 and 4:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 75%">
</colgroup>
<thead>
<tr class="header">
<th>Rule</th>
<th>IVP Relationship</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Passes tests</td>
<td>Orthogonal (correctness, not evolvability)</td>
</tr>
<tr class="even">
<td>Reveals intention</td>
<td>Orthogonal (understandability, not evolvability)</td>
</tr>
<tr class="odd">
<td>No duplication</td>
<td>IVP-4 provides the criterion (same change driver = same knowledge)</td>
</tr>
<tr class="even">
<td>Fewest elements</td>
<td>IVP defines “necessary”—one per change driver</td>
</tr>
</tbody>
</table>
<hr>
<p><a id="once-and-only-once-oaoo"></a></p>
</section>
</section>
<section id="once-and-only-once-oaoo" class="level3" data-number="8.3">
<h3 data-number="8.3" class="anchored" data-anchor-id="once-and-only-once-oaoo"><span class="header-section-number">8.3</span> Once and Only Once (OAOO)</h3>
<p><a id="the-principle"></a></p>
<section id="the-principle-3" class="level4" data-number="8.3.1">
<h4 data-number="8.3.1" class="anchored" data-anchor-id="the-principle-3"><span class="header-section-number">8.3.1</span> The Principle</h4>
<blockquote class="blockquote">
<p>“Say everything once and only once.” — Kent Beck</p>
</blockquote>
<p>This is Beck’s formulation of DRY, emphasizing that each piece of knowledge should have exactly one authoritative representation.</p>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-10" class="level4" data-number="8.3.2">
<h4 data-number="8.3.2" class="anchored" data-anchor-id="relevant-change-drivers-10"><span class="header-section-number">8.3.2</span> Relevant Change Drivers</h4>
<p>Same as DRY: - <code>γ_A</code> governs knowledge K → K should appear once, in the module for <code>γ_A</code> - Multiple representations of K create synchronization problems when <code>γ_A</code> triggers change</p>
<p><a id="the-problem-with-oaoo"></a></p>
</section>
<section id="the-problem-with-oaoo" class="level4" data-number="8.3.3">
<h4 data-number="8.3.3" class="anchored" data-anchor-id="the-problem-with-oaoo"><span class="header-section-number">8.3.3</span> The Problem with OAOO</h4>
<p>Same as DRY: What counts as “the same thing”? Two code fragments may look identical but represent different knowledge if they change for different reasons.</p>
<p><strong>How IVP addresses this</strong>: “Same thing” = governed by the same change driver. If two pieces of code would change for the same reason (same authority, same business rule), they’re the same knowledge—say it once. If they’d change independently, they’re different knowledge despite structural similarity.</p>
<p><a id="relationship-to-ivp-ivp-operationalizes-oaoo"></a></p>
</section>
<section id="relationship-to-ivp-ivp-operationalizes-oaoo" class="level4" data-number="8.3.4">
<h4 data-number="8.3.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-operationalizes-oaoo"><span class="header-section-number">8.3.4</span> Relationship to IVP: IVP Operationalizes OAOO</h4>
<p>OAOO is DRY by another name. IVP provides the criterion: knowledge identity is determined by change driver identity.</p>
<hr>
<p><a id="agile-manifesto-design-principles"></a></p>
</section>
</section>
<section id="agile-manifesto-design-principles" class="level3" data-number="8.4">
<h3 data-number="8.4" class="anchored" data-anchor-id="agile-manifesto-design-principles"><span class="header-section-number">8.4</span> Agile Manifesto Design Principles</h3>
<p>The Agile Manifesto (2001) was written by 17 software experts including Kent Beck, Martin Fowler, and Robert C. Martin. While primarily about process, three of its 12 principles directly address software design.</p>
<p><a id="the-principles"></a></p>
<section id="the-principles" class="level4" data-number="8.4.1">
<h4 data-number="8.4.1" class="anchored" data-anchor-id="the-principles"><span class="header-section-number">8.4.1</span> The Principles</h4>
<blockquote class="blockquote">
<p>“Continuous attention to technical excellence and good design enhances agility.” — Agile Manifesto, Principle 9</p>
</blockquote>
<blockquote class="blockquote">
<p>“Simplicity—the art of maximizing the amount of work not done—is essential.” — Agile Manifesto, Principle 10</p>
</blockquote>
<blockquote class="blockquote">
<p>“The best architectures, requirements, and designs emerge from self-organizing teams.” — Agile Manifesto, Principle 11</p>
</blockquote>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-11" class="level4" data-number="8.4.2">
<h4 data-number="8.4.2" class="anchored" data-anchor-id="relevant-change-drivers-11"><span class="header-section-number">8.4.2</span> Relevant Change Drivers</h4>
<p>The Agile Manifesto addresses the <em>meta-level</em> of how change drivers are discovered: - Teams closest to the work understand change drivers best - Design must accommodate change (agility requires evolvability) - Simplicity reduces the number of elements that <em>can</em> be coupled</p>
<p><a id="the-problem-with-the-agile-design-principles"></a></p>
</section>
<section id="the-problem-with-the-agile-design-principles" class="level4" data-number="8.4.3">
<h4 data-number="8.4.3" class="anchored" data-anchor-id="the-problem-with-the-agile-design-principles"><span class="header-section-number">8.4.3</span> The Problem with the Agile Design Principles</h4>
<p>These principles are aspirational but not actionable:</p>
<ol type="1">
<li><p><strong>“Technical excellence and good design”</strong> is circular—what <em>is</em> good design? The principle assumes you already know.</p></li>
<li><p><strong>“Simplicity”</strong> has the same issue as KISS—no objective criterion for what’s simple or what work is unnecessary.</p></li>
<li><p><strong>“Emerge from self-organizing teams”</strong> describes <em>who</em> makes decisions but not <em>how</em> to make them correctly.</p></li>
</ol>
<p><strong>How IVP addresses this</strong>: IVP provides the criterion these principles lack. “Good design” = IVP-compliant structure. “Simplicity” = minimal accidental coupling (no coupling between independent change drivers). “Emergent architecture” works because teams close to the domain understand actual change drivers—IVP tells them what to do with that knowledge.</p>
<p><a id="relationship-to-ivp-ivp-operationalizes"></a></p>
</section>
<section id="relationship-to-ivp-ivp-operationalizes" class="level4" data-number="8.4.4">
<h4 data-number="8.4.4" class="anchored" data-anchor-id="relationship-to-ivp-ivp-operationalizes"><span class="header-section-number">8.4.4</span> Relationship to IVP: IVP Operationalizes</h4>
<p>The Agile Manifesto recognizes that design must support change but doesn’t specify how. IVP provides the operational definition: - <strong>Technical excellence</strong> = modules with maximal cohesion (complete and pure knowledge embodiment) - <strong>Simplicity</strong> = no accidental coupling between independent change drivers - <strong>Emergent design</strong> = structure that reflects actual change drivers discovered during development</p>
<p>The reason “the best architectures emerge from self-organizing teams” is that those teams learn the actual change drivers through building. IVP tells them how to structure based on what they learn.</p>
<hr>
<p><a id="systems-of-systems-principles-1990s2000s"></a></p>
</section>
</section>
</section>
<section id="systems-of-systems-principles-1990s2000s" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="systems-of-systems-principles-1990s2000s"><span class="header-section-number">9</span> Systems-of-Systems Principles (1990s–2000s)</h2>
<p>Systems-of-Systems (SoS) architecting addresses a different scale: large-scale systems composed of operationally and managerially independent constituent systems. Mark Maier’s foundational 1998 paper “Architecting Principles for Systems-of-Systems” established four principles that remain influential in systems engineering.</p>
<hr>
<p><a id="what-defines-a-system-of-systems"></a></p>
<section id="what-defines-a-system-of-systems" class="level3" data-number="9.1">
<h3 data-number="9.1" class="anchored" data-anchor-id="what-defines-a-system-of-systems"><span class="header-section-number">9.1</span> What Defines a System-of-Systems?</h3>
<p>Maier identified five characteristics distinguishing SoS from conventional systems:</p>
<ol type="1">
<li><strong>Operational Independence</strong>: Constituent systems operate independently and usefully on their own</li>
<li><strong>Managerial Independence</strong>: Constituent systems are managed independently</li>
<li><strong>Evolutionary Development</strong>: The SoS develops over time; constituent systems join and leave</li>
<li><strong>Emergent Behavior</strong>: The SoS exhibits capabilities beyond any individual constituent</li>
<li><strong>Geographic Distribution</strong>: Constituent systems are often physically distributed</li>
</ol>
<p>These characteristics create unique architectural challenges: you cannot mandate compliance, you cannot control constituent system evolution, and the “architecture” exists primarily as communication standards rather than physical structure.</p>
<hr>
<p><a id="maiers-four-architecting-principles"></a></p>
</section>
<section id="maiers-four-architecting-principles" class="level3" data-number="9.2">
<h3 data-number="9.2" class="anchored" data-anchor-id="maiers-four-architecting-principles"><span class="header-section-number">9.2</span> Maier’s Four Architecting Principles</h3>
<p><a id="1-stable-intermediate-forms"></a></p>
<section id="stable-intermediate-forms" class="level4" data-number="9.2.1">
<h4 data-number="9.2.1" class="anchored" data-anchor-id="stable-intermediate-forms"><span class="header-section-number">9.2.1</span> 1. Stable Intermediate Forms</h4>
<p><strong>The Principle</strong>: Evolution must proceed through stable intermediate states. The architect must pay attention to intermediate steps in a planned evolution of the SoS.</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_SoS</code> — the overall system-of-systems capability - <code>γ_constituent₁</code>, <code>γ_constituent₂</code>, … — each constituent system’s evolution - Evolution must maintain stability while individual constituents change</p>
<p><strong>The Problem</strong>: SoS cannot be built monolithically—constituent systems already exist and evolve independently. A “big bang” integration approach fails because there’s no stable state to operate from during transition.</p>
<p><strong>How IVP addresses this</strong>: Each intermediate state must be IVP-compliant at its level. Constituent systems must maintain their cohesion (<code>γ_constituentᵢ</code>) while integrating with others. The SoS architecture must isolate constituent variation so that one system’s evolution doesn’t destabilize others.</p>
<p><strong>Relationship to IVP</strong>: Stable Intermediate Forms is <strong>IVP applied to evolutionary architecture</strong>. Each intermediate must isolate independent constituent change drivers so evolution can proceed incrementally.</p>
<hr>
<p><a id="2-policy-triage-leverage-policy-not-structure"></a></p>
</section>
<section id="policy-triage-leverage-policy-not-structure" class="level4" data-number="9.2.2">
<h4 data-number="9.2.2" class="anchored" data-anchor-id="policy-triage-leverage-policy-not-structure"><span class="header-section-number">9.2.2</span> 2. Policy Triage (Leverage Policy, Not Structure)</h4>
<p><strong>The Principle</strong>: Given limited influence over constituent system design, architects must carefully select strategic intervention points. The opportunities to influence constituent systems are limited; the points of influence must be chosen carefully.</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_architecture</code> — SoS-level architectural decisions - <code>γ_constituent</code> — individual system implementation details - The SoS architect controls <code>γ_architecture</code> but not <code>γ_constituent</code></p>
<p><strong>The Problem</strong>: SoS architects cannot mandate internal structure of constituent systems. Traditional architectural control (specifying interfaces, enforcing patterns) is unavailable. What levers remain?</p>
<p><strong>How IVP addresses this</strong>: Focus on <em>policies</em> (what must be achieved) rather than <em>structure</em> (how to achieve it). Policies define change driver boundaries without prescribing implementation. A constituent system can vary internally (<code>γ_constituent</code>) while adhering to policies that maintain SoS coherence (<code>γ_architecture</code>).</p>
<p><strong>Relationship to IVP</strong>: Policy Triage is <strong>IVP-3 applied through policy rather than structure</strong>. It acknowledges that you cannot control all change drivers—only establish boundaries between the ones you influence and those you don’t.</p>
<hr>
<p><a id="3-leverage-interfaces-through-standards"></a></p>
</section>
<section id="leverage-interfaces-through-standards" class="level4" data-number="9.2.3">
<h4 data-number="9.2.3" class="anchored" data-anchor-id="leverage-interfaces-through-standards"><span class="header-section-number">9.2.3</span> 3. Leverage Interfaces Through Standards</h4>
<p><strong>The Principle</strong>: The architect must leverage the interfaces to realize the capability that the SoS is assembled to deliver. In most cases, the architecture of a system-of-systems <em>is</em> communications—the set of standards that allow meaningful communication among components.</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_standard</code> — the communication protocol/standard (controlled by SoS architect) - <code>γ_implementation</code> — how each constituent implements the standard (independent per system) - Standards provide the stable abstraction; implementations vary independently</p>
<p><strong>The Problem</strong>: With no control over constituent internals, the only leverage is at interfaces. But interfaces must be standardized to enable interoperability—hence standards become the architecture itself.</p>
<p><strong>How IVP addresses this</strong>: Standards are the stable abstraction that isolates independent variation. Each constituent varies for its own reasons (<code>γ_constituentᵢ</code>); the standard ensures they can still communicate. This is DIP at the systems-of-systems scale: constituents depend on abstractions (standards), not on each other’s implementations.</p>
<p><strong>Relationship to IVP</strong>: Leveraging Interfaces is <strong>DIP/IVP-3 at the SoS scale</strong>. The standard isolates constituent change drivers from each other while enabling collaboration.</p>
<p><strong>Example</strong>: The Internet’s TCP/IP protocols are the classic example. No central authority controls how individual networks implement TCP/IP—only that they adhere to the standard. The architecture <em>is</em> the protocol suite.</p>
<hr>
<p><a id="4-ensure-cooperation"></a></p>
</section>
<section id="ensure-cooperation" class="level4" data-number="9.2.4">
<h4 data-number="9.2.4" class="anchored" data-anchor-id="ensure-cooperation"><span class="header-section-number">9.2.4</span> 4. Ensure Cooperation</h4>
<p><strong>The Principle</strong>: Collaboration between independent systems is only possible if system owners choose to collaborate. Incentivizing collaboration requires appreciation of motivations and non-technical aspects (commercial benefits, protection of IP).</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_technical</code> — technical requirements for integration - <code>γ_organizational</code> — business, political, and economic factors affecting cooperation - Both must be addressed; technical architecture alone is insufficient</p>
<p><strong>The Problem</strong>: Even with perfect standards, constituent systems won’t join an SoS unless their owners perceive benefit. Technical architecture must align with organizational incentives.</p>
<p><strong>How IVP addresses this</strong>: This principle extends IVP beyond pure technical concerns. <code>γ_organizational</code> (stakeholder incentives, business models, IP concerns) is as real a change driver as <code>γ_technical</code>. SoS architecture must account for both—technical structures that ignore organizational change drivers will fail regardless of their technical elegance.</p>
<p><strong>Relationship to IVP</strong>: Ensure Cooperation acknowledges that <strong>change drivers include organizational and economic factors</strong>, not just technical ones. IVP applies to sociotechnical systems, not just code.</p>
<hr>
<p><a id="what-ivp-adds-to-sos-principles"></a></p>
</section>
</section>
<section id="what-ivp-adds-to-sos-principles" class="level3" data-number="9.3">
<h3 data-number="9.3" class="anchored" data-anchor-id="what-ivp-adds-to-sos-principles"><span class="header-section-number">9.3</span> What IVP Adds to SoS Principles</h3>
<p>Maier’s principles were derived empirically from observing successful and failed systems-of-systems. IVP provides the theoretical foundation:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 46%">
<col style="width: 53%">
</colgroup>
<thead>
<tr class="header">
<th>SoS Principle</th>
<th>IVP Explanation</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Stable Intermediate Forms</td>
<td>IVP-compliant structure at each evolutionary state</td>
</tr>
<tr class="even">
<td>Policy Triage</td>
<td>IVP-3 via policy boundaries when structural control is unavailable</td>
</tr>
<tr class="odd">
<td>Leverage Interfaces</td>
<td>DIP/IVP-3 at the inter-system scale</td>
</tr>
<tr class="even">
<td>Ensure Cooperation</td>
<td>Change drivers include organizational/economic factors</td>
</tr>
</tbody>
</table>
<p>The key insight: <strong>at the SoS scale, the “architecture” is not physical structure but communication standards</strong>. This is IVP taken to its logical extreme—when you cannot control implementations, you can only control the boundaries between them. Standards define those boundaries, isolating constituent change drivers while enabling emergent capabilities.</p>
<hr>
<p><a id="incose-systems-engineering-principles"></a></p>
</section>
<section id="incose-systems-engineering-principles" class="level3" data-number="9.4">
<h3 data-number="9.4" class="anchored" data-anchor-id="incose-systems-engineering-principles"><span class="header-section-number">9.4</span> INCOSE Systems Engineering Principles</h3>
<p>The International Council on Systems Engineering (INCOSE) published a formal set of 15 Systems Engineering Principles in 2022, representing 30+ years of accumulated wisdom. Several are directly relevant to IVP:</p>
<p><strong>“Complex systems are engineered by complex organizations.”</strong> This principle acknowledges Conway’s Law at the systems level. IVP explains when this alignment is beneficial (team boundaries match change driver boundaries) versus problematic (organizational structure forces inappropriate coupling).</p>
<p><strong>“SE has a holistic system view that includes system elements and their interactions.”</strong> This is IVP-4 at the systems level—understanding not just elements but how they vary together.</p>
<p><strong>“Decision quality depends on understanding the system, enabling systems, and interoperating systems.”</strong> This resonates with the Knowledge Theorem: quality decisions require understanding the knowledge embodied in each system and how that knowledge varies.</p>
<hr>
<p><a id="cloud-native-principles-2010s"></a></p>
</section>
</section>
<section id="cloud-native-principles-2010s" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="cloud-native-principles-2010s"><span class="header-section-number">10</span> Cloud-Native Principles (2010s)</h2>
<p>The rise of cloud computing and microservices brought new architectural concerns. These principles address deployment and operational variation.</p>
<hr>
<p><a id="12-factor-app-methodology"></a></p>
<section id="factor-app-methodology" class="level3" data-number="10.1">
<h3 data-number="10.1" class="anchored" data-anchor-id="factor-app-methodology"><span class="header-section-number">10.1</span> 12-Factor App Methodology</h3>
<p>The <a href="https://www.12factor.net/">12-Factor App methodology</a> was developed by Adam Wiggins and the Heroku team circa 2011. It prescribes best practices for building cloud-native, scalable software-as-a-service applications.</p>
<p><a id="the-factors"></a></p>
<section id="the-factors" class="level4" data-number="10.1.1">
<h4 data-number="10.1.1" class="anchored" data-anchor-id="the-factors"><span class="header-section-number">10.1.1</span> The Factors</h4>
<ol type="1">
<li><strong>Codebase</strong>: One codebase tracked in version control, many deploys</li>
<li><strong>Dependencies</strong>: Explicitly declare and isolate dependencies</li>
<li><strong>Config</strong>: Store config in the environment</li>
<li><strong>Backing Services</strong>: Treat backing services as attached resources</li>
<li><strong>Build, Release, Run</strong>: Strictly separate build and run stages</li>
<li><strong>Processes</strong>: Execute the app as stateless processes</li>
<li><strong>Port Binding</strong>: Export services via port binding</li>
<li><strong>Concurrency</strong>: Scale out via the process model</li>
<li><strong>Disposability</strong>: Maximize robustness with fast startup and graceful shutdown</li>
<li><strong>Dev/Prod Parity</strong>: Keep development, staging, and production as similar as possible</li>
<li><strong>Logs</strong>: Treat logs as event streams</li>
<li><strong>Admin Processes</strong>: Run admin/management tasks as one-off processes</li>
</ol>
<p><a id="relevant-change-drivers"></a></p>
</section>
<section id="relevant-change-drivers-12" class="level4" data-number="10.1.2">
<h4 data-number="10.1.2" class="anchored" data-anchor-id="relevant-change-drivers-12"><span class="header-section-number">10.1.2</span> Relevant Change Drivers</h4>
<p>12-Factor explicitly separates infrastructure concerns from application logic: - <code>γ_config</code> — environment-specific configuration (Factor 3) - <code>γ_backing_service</code> — database, queue, cache providers (Factor 4) - <code>γ_build</code> vs.&nbsp;<code>γ_release</code> vs.&nbsp;<code>γ_run</code> — distinct lifecycle stages (Factor 5) - <code>γ_app</code> vs.&nbsp;<code>γ_environment</code> — application code vs.&nbsp;deployment context (Factor 10)</p>
<p><a id="the-problem-with-12-factor"></a></p>
</section>
<section id="the-problem-with-12-factor" class="level4" data-number="10.1.3">
<h4 data-number="10.1.3" class="anchored" data-anchor-id="the-problem-with-12-factor"><span class="header-section-number">10.1.3</span> The Problem with 12-Factor</h4>
<p>12-Factor is prescriptive but not principled. It tells you <em>what</em> to do but not <em>why</em>:</p>
<ol type="1">
<li><p><strong>No unifying rationale</strong>: Why these 12 factors? Why not 10 or 15? The factors appear as a list of best practices rather than derivations from a principle.</p></li>
<li><p><strong>Implicit assumptions</strong>: The factors assume cloud deployment, statelessness, and horizontal scaling. They don’t explain when these assumptions don’t apply.</p></li>
<li><p><strong>Scope limitation</strong>: 12-Factor addresses deployment architecture but says nothing about domain modeling, business logic organization, or code structure.</p></li>
</ol>
<p><strong>How IVP addresses this</strong>: IVP explains <em>why</em> these factors work. Each factor isolates a different change driver: - Config (Factor 3) isolates <code>γ_environment</code> from <code>γ_app</code>—environment changes shouldn’t require code changes - Backing Services (Factor 4) isolates <code>γ_provider</code> from <code>γ_app</code>—switching databases shouldn’t require code changes - Build/Release/Run (Factor 5) isolates <code>γ_build</code> from <code>γ_run</code>—runtime changes shouldn’t require rebuilding</p>
<p><a id="relationship-to-ivp-domain-specific-ivp-1"></a></p>
</section>
<section id="relationship-to-ivp-domain-specific-ivp-3" class="level4" data-number="10.1.4">
<h4 data-number="10.1.4" class="anchored" data-anchor-id="relationship-to-ivp-domain-specific-ivp-3"><span class="header-section-number">10.1.4</span> Relationship to IVP: Domain-Specific IVP-3</h4>
<p>12-Factor is IVP-3 applied to the cloud/operations domain:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Factor</th>
<th>Change Driver Separation</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Config</td>
<td><code>γ_app</code> ⊥ <code>γ_environment</code></td>
</tr>
<tr class="even">
<td>Backing Services</td>
<td><code>γ_app</code> ⊥ <code>γ_provider</code></td>
</tr>
<tr class="odd">
<td>Build/Release/Run</td>
<td><code>γ_build</code> ⊥ <code>γ_release</code> ⊥ <code>γ_run</code></td>
</tr>
<tr class="even">
<td>Dev/Prod Parity</td>
<td>Minimize <code>γ_dev</code> vs.&nbsp;<code>γ_prod</code> divergence</td>
</tr>
<tr class="odd">
<td>Processes</td>
<td>Statelessness isolates <code>γ_instance₁</code> from <code>γ_instance₂</code></td>
</tr>
</tbody>
</table>
<p>12-Factor discovered these separations empirically by observing what causes production incidents: deployments that couple app code to environment, builds that couple to runtime, processes that couple to each other via shared state.</p>
<p>IVP explains the pattern: each factor prevents accidental coupling between independent change drivers in the operational domain.</p>
<hr>
<p><a id="gof-principles"></a></p>
</section>
</section>
</section>
<section id="gof-principles" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="gof-principles"><span class="header-section-number">11</span> GoF Principles</h2>
<p>The Gang of Four (<em>Design Patterns</em>, 1994) articulated two foundational principles alongside their pattern catalog.</p>
<p><a id="relevant-change-drivers"></a></p>
<section id="relevant-change-drivers-13" class="level3" data-number="11.1">
<h3 data-number="11.1" class="anchored" data-anchor-id="relevant-change-drivers-13"><span class="header-section-number">11.1</span> Relevant Change Drivers</h3>
<p>GoF principles address implementation-level variation: - <code>γ_interface</code> vs.&nbsp;<code>γ_impl</code> — contract vs.&nbsp;mechanism - <code>γ_parent</code> vs.&nbsp;<code>γ_child</code> — inheritance couples these; are they truly dependent? - Composition allows <code>γ_A</code> and <code>γ_B</code> to vary independently</p>
<p><a id="program-to-an-interface-not-an-implementation"></a></p>
</section>
<section id="program-to-an-interface-not-an-implementation" class="level3" data-number="11.2">
<h3 data-number="11.2" class="anchored" data-anchor-id="program-to-an-interface-not-an-implementation"><span class="header-section-number">11.2</span> Program to an Interface, Not an Implementation</h3>
<p><strong>What GoF Said (1994):</strong> &gt; “Don’t declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class.” &gt; — Gamma, Helm, Johnson, Vlissides</p>
<p><strong>The Problem</strong>: This is essentially DIP at the variable/type level. The same issue applies: when is the abstraction worthwhile? Adding interfaces everywhere creates ceremony without benefit.</p>
<p><strong>How IVP addresses this</strong>: Program to an interface when the implementation might vary independently. If you’ll only ever have one implementation (single change driver), the interface adds indirection without isolation benefit. Multiple potential implementations = multiple change drivers = interface warranted.</p>
<p><a id="favor-composition-over-inheritance"></a></p>
</section>
<section id="favor-composition-over-inheritance" class="level3" data-number="11.3">
<h3 data-number="11.3" class="anchored" data-anchor-id="favor-composition-over-inheritance"><span class="header-section-number">11.3</span> Favor Composition Over Inheritance</h3>
<p><strong>What GoF Said (1994):</strong> &gt; “Favor object composition over class inheritance.” &gt; — Gamma, Helm, Johnson, Vlissides</p>
<p><strong>The Problem</strong>: GoF observed that “designers overuse inheritance” and that “inheritance breaks encapsulation.” But when <em>is</em> inheritance appropriate?</p>
<p><strong>How IVP addresses this</strong>: Inheritance creates tight coupling—subclasses vary for both their own causes and their parent’s causes. Composition allows independent variation. Use inheritance when parent and child genuinely share a change driver (they evolve together). Use composition when they might diverge.</p>
<hr>
<p><a id="solid-principles"></a></p>
</section>
</section>
<section id="solid-principles" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="solid-principles"><span class="header-section-number">12</span> SOLID Principles</h2>
<p><a id="single-responsibility-principle-srp"></a></p>
<section id="single-responsibility-principle-srp" class="level3" data-number="12.1">
<h3 data-number="12.1" class="anchored" data-anchor-id="single-responsibility-principle-srp"><span class="header-section-number">12.1</span> Single Responsibility Principle (SRP)</h3>
<p><strong>What Martin Said:</strong> &gt; “A class should have one, and only one, reason to change.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_A</code> vs.&nbsp;<code>γ_B</code> vs.&nbsp;<code>γ_C</code> — different stakeholders, different reasons to change - A class with multiple independent drivers violates SRP - A class with one driver satisfies SRP</p>
<p><strong>The Problem with SRP</strong>: What counts as “one reason to change”? This is famously vague. The same class can be described as having one responsibility (“handles user data”) or multiple (“validates users, persists users, formats user display”). The granularity is undefined—SRP provides no way to determine when you’ve reached “one” responsibility.</p>
<p><strong>How IVP addresses this</strong>: A “reason to change” is a change driver—an independently varying source of change. Change drivers are concrete: the pricing team, the compliance department, the infrastructure group, an external API. You can identify them by asking “who requests this change?” or “what causes this to need modification?” If the answer is multiple independent authorities or concerns, the class has multiple responsibilities.</p>
<p><strong>Relationship</strong>: SRP is <strong>IVP applied at class granularity</strong>.</p>
<ul>
<li>If <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>C</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>&gt;</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">|\Gamma(C)| &gt; 1</annotation></semantics></math> (class has multiple change drivers), SRP is violated</li>
<li>If <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">|</mo><mi mathvariant="normal">Γ</mi><mo stretchy="false" form="prefix">(</mo><mi>C</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">|</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">|\Gamma(C)| = 1</annotation></semantics></math> (class has single change driver), SRP is satisfied</li>
</ul>
<p><strong>What IVP Adds</strong>: SRP’s “reason to change” is vague. IVP makes it precise: a change driver is an independently varying source of change to domain knowledge. Different actors, different business domains, different technical concerns—these are independent change drivers.</p>
<p>When evaluating whether a class has “one responsibility,” ask: <em>Who or what causes this code to change?</em> If the answer is multiple independent actors or concerns, consider splitting the class.</p>
<hr>
<p><a id="openclosed-principle-ocp"></a></p>
</section>
<section id="openclosed-principle-ocp" class="level3" data-number="12.2">
<h3 data-number="12.2" class="anchored" data-anchor-id="openclosed-principle-ocp"><span class="header-section-number">12.2</span> Open/Closed Principle (OCP)</h3>
<p><strong>What Martin Said:</strong> &gt; “Software entities should be open for extension, but closed for modification.” &gt; — Robert C. Martin, “The Open-Closed Principle” (1996)</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_core</code> vs.&nbsp;<code>γ_variant₁</code>, <code>γ_variant₂</code>, … — stable core, volatile variations - OCP warranted when <code>γ_core ⊥ γ_variantᵢ</code> (independent) - OCP overhead unjustified when everything changes together</p>
<p><strong>The Problem with OCP</strong>: OCP provides no criterion for <em>when</em> to apply it. Making code “open for extension” requires upfront investment (abstractions, interfaces, plugin points). Applied everywhere, OCP leads to over-engineering. Applied nowhere, code becomes rigid. OCP tells you the goal but not when the cost is justified.</p>
<p><strong>How IVP addresses this</strong>: Apply OCP when you identify independent change drivers. Core logic changes for cause <code>γ_core</code>; variations change for causes <code>γ_v1</code>, <code>γ_v2</code>, etc. If these are genuinely independent, OCP is warranted—the abstraction isolates independent variation. If they’re not independent (everything changes together), OCP adds complexity without benefit.</p>
<p><strong>Relationship</strong>: OCP is <strong>IVP-3 applied to stable/variant separation</strong>.</p>
<ul>
<li>Core functionality <code>F</code> changes for cause <code>γ_F</code></li>
<li>Variations <code>V₁, V₂, ...</code> change for causes <code>γ_V₁, γ_V₂, ...</code></li>
<li>These causes are independent: <code>γ_F ⊥ γ_Vᵢ</code></li>
</ul>
<p>Applying IVP-3 separates stable abstraction from volatile implementations. Adding new implementations doesn’t trigger <code>γ_F</code>, so the abstraction remains unchanged.</p>
<p><strong>What IVP Adds</strong>: OCP explains the goal but not <em>when</em> to apply it. IVP provides the criterion: apply OCP when you identify independent variation between core logic and its variations. Not every piece of code needs extension points—only where independent change drivers exist.</p>
<p><strong>Practical improvement</strong>: Before adding abstractions “for future extensibility,” identify actual change drivers. Is there genuine independent variation? Or are you adding complexity for hypothetical future changes that may never occur?</p>
<hr>
<p><a id="liskov-substitution-principle-lsp"></a></p>
</section>
<section id="liskov-substitution-principle-lsp" class="level3" data-number="12.3">
<h3 data-number="12.3" class="anchored" data-anchor-id="liskov-substitution-principle-lsp"><span class="header-section-number">12.3</span> Liskov Substitution Principle (LSP)</h3>
<p><strong>What Liskov &amp; Wing Said (1994):</strong> &gt; “Subtypes must be substitutable for their base types.” &gt; — Barbara Liskov &amp; Jeannette Wing, “A Behavioral Notion of Subtyping”</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_base</code> vs.&nbsp;<code>γ_derived</code> — do they genuinely share a change driver? - LSP violation: client must handle <code>γ_derived</code> specially, introducing accidental coupling - False unification: elements appear unified but vary for different causes</p>
<p><strong>The Problem with LSP</strong>: LSP is difficult to validate because you must inspect <em>clients</em> to identify problems—a model viewed in isolation cannot be meaningfully validated. Classic violations (Square/Rectangle, Penguin/Bird) show that “is-a” relationships in the domain don’t always translate to valid inheritance. Trying to anticipate all client assumptions yields needless complexity.</p>
<p><strong>How IVP addresses this</strong>: LSP violations create false unification—elements that appear unified actually vary for different causes from the client’s perspective. When a subtype requires special-case handling, the client now varies for an additional cause (accommodating that subtype’s behavior). IVP-4 requires genuine dependent variation; LSP ensures the abstraction doesn’t lie about this.</p>
<p><strong>Relationship</strong>: LSP is <strong>IVP-4’s behavioral constraint for type hierarchies</strong>.</p>
<p>If derived type <code>D</code> violates base type <code>B</code>’s contract, client <code>K</code> must add special-case logic:</p>
<pre><code>if (instance is D) handleDifferently();</code></pre>
<p>Now <code>K</code> varies for two independent causes: - <code>γ_K</code>: client’s core responsibility - <code>γ_D</code>: accommodating <code>D</code>’s non-substitutable behavior</p>
<p>This violates IVP-3.</p>
<p><strong>What IVP Adds</strong>: LSP is often stated as a contract requirement. IVP explains <em>why</em> it matters: LSP ensures elements unified by abstraction genuinely vary for the <strong>same cause</strong> from the client’s perspective. Without LSP, the abstraction is false unification—elements appear unified but actually vary for different causes.</p>
<p><strong>Practical improvement</strong>: When designing inheritance hierarchies, ask: <em>Do all subtypes genuinely change for the same reasons as the base type?</em> If not, you probably have a misuse of inheritance.</p>
<hr>
<p><a id="interface-segregation-principle-isp"></a></p>
</section>
<section id="interface-segregation-principle-isp" class="level3" data-number="12.4">
<h3 data-number="12.4" class="anchored" data-anchor-id="interface-segregation-principle-isp"><span class="header-section-number">12.4</span> Interface Segregation Principle (ISP)</h3>
<p><strong>What Martin Said:</strong> &gt; “Clients should not be forced to depend on interfaces they do not use.” &gt; — Robert C. Martin, “The Interface Segregation Principle” (1996)</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_client₁</code> vs.&nbsp;<code>γ_client₂</code> — different clients with different needs - Fat interface forces <code>γ_client₂</code> to depend on changes driven by <code>γ_client₁</code> - Segregate when clients have independent change drivers</p>
<p><strong>The Problem with ISP</strong>: ISP tells you to segregate but not <em>how</em> to determine the boundaries. Should a <code>UserService</code> interface be split into <code>UserReader</code> and <code>UserWriter</code>? Or <code>UserAuthenticator</code>, <code>UserProfileManager</code>, and <code>UserPreferencesManager</code>? ISP provides no criterion for the right granularity.</p>
<p><strong>How IVP addresses this</strong>: Segregate by change driver. Group methods that change for the same cause into one interface. If authentication methods change for security reasons while profile methods change for UX reasons, those are different change drivers—segregate them. The boundaries emerge from causal analysis, not arbitrary decomposition.</p>
<p><strong>Relationship</strong>: ISP is <strong>IVP-3 applied to interface design</strong>—but note how it differs from Information Hiding/DIP.</p>
<p><strong>ISP vs.&nbsp;Information Hiding/DIP</strong>:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 83%">
<col style="width: 16%">
</colgroup>
<thead>
<tr class="header">
<th>Information Hiding / DIP</th>
<th>ISP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Separate contract from implementation</td>
<td>Separate contracts from <em>each other</em></td>
</tr>
<tr class="even">
<td>Vertical: client ↔︎ implementation</td>
<td>Horizontal: client₁ ↔︎ client₂</td>
</tr>
<tr class="odd">
<td>One contract hiding one implementation</td>
<td>Multiple contracts for same implementation</td>
</tr>
</tbody>
</table>
<p>Information Hiding/DIP is about hiding <em>how you work</em> behind <em>what clients can expect</em>. ISP is about not forcing a single fat contract on clients with different needs—it’s about having <em>multiple role-specific contracts</em> when clients have independent change drivers.</p>
<p>Fat interface <code>I</code> with methods for clients <code>K₁</code> and <code>K₂</code>: - Methods for <code>K₁</code> change for cause <code>γ₁</code> - Methods for <code>K₂</code> change for cause <code>γ₂</code> - If <code>γ₁ ⊥ γ₂</code>, the fat interface couples <code>K₂</code> to changes irrelevant to it</p>
<p>IVP-3 directs: segregate by variation cause.</p>
<p><strong>What IVP Adds</strong>: ISP tells you to segregate interfaces but not <em>how</em> to determine segregation boundaries. IVP provides the criterion: group methods that change for the same cause.</p>
<p><strong>Practical improvement</strong>: When designing interfaces, ask: <em>Which clients use which methods?</em> If different clients use different method subsets and those clients represent independent concerns, segregate.</p>
<hr>
<p><a id="dependency-inversion-principle-dip"></a></p>
</section>
<section id="dependency-inversion-principle-dip" class="level3" data-number="12.5">
<h3 data-number="12.5" class="anchored" data-anchor-id="dependency-inversion-principle-dip"><span class="header-section-number">12.5</span> Dependency Inversion Principle (DIP)</h3>
<p><strong>What Martin Said:</strong> &gt; “High-level modules should not depend on low-level modules. Both should depend on abstractions.” &gt; — Robert C. Martin, “The Dependency Inversion Principle” (1996)</p>
<p><strong>Relevant Change Drivers</strong>: - <code>γ_high</code> (high-level policy) vs.&nbsp;<code>γ_low</code> (low-level mechanism) - DIP warranted when <code>γ_high ⊥ γ_low</code> (independent) - DIP overhead unjustified when layers always change together</p>
<p><strong>The Problem with DIP</strong>: DIP is often applied dogmatically—“always add an interface.” But abstractions have costs: indirection, cognitive overhead, maintenance burden. DIP provides no criterion for <em>when</em> inversion is worthwhile versus when it’s over-engineering.</p>
<p><strong>How IVP addresses this</strong>: Apply DIP when high-level and low-level modules have independent change drivers. Business policy (<code>γ_policy</code>) and infrastructure (<code>γ_infrastructure</code>) typically change for different reasons—DIP is warranted. But if two layers always change together (they’re not actually independent), the abstraction adds ceremony without isolation benefit.</p>
<p><strong>Relationship</strong>: DIP is <strong>IVP-3 applied to layered class dependencies</strong>.</p>
<p>DIP differs from Information Hiding:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 79%">
<col style="width: 20%">
</colgroup>
<thead>
<tr class="header">
<th>Information Hiding</th>
<th>DIP</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Probabilistic: “hide what’s <em>likely</em> to change”</td>
<td>Structural: “high-level depends on abstractions”</td>
</tr>
<tr class="even">
<td>Economic judgment required</td>
<td>Prescriptive rule</td>
</tr>
<tr class="odd">
<td>Module-level principle</td>
<td>Class-level in layered architecture</td>
</tr>
</tbody>
</table>
<p>Information Hiding asks “what’s likely to change?” and makes an economic decision. DIP doesn’t ask—it prescribes a dependency direction. The structural outcomes may look similar, but the reasoning differs.</p>
<p><strong>How IVP relates</strong>: DIP implicitly recognizes that high-level policy and low-level implementation have <strong>independent change drivers</strong>. Business rules (<code>γ_policy</code>) change for business reasons; infrastructure (<code>γ_infrastructure</code>) changes for technical reasons. IVP-3 mandates their separation. DIP prescribes <em>how</em> to achieve it in OO: depend on abstractions.</p>
<p><strong>What IVP Adds</strong>: DIP tells you to always invert dependencies across layers. IVP explains <em>when</em> this is actually necessary: only when the layers have independent change drivers. Not all dependencies need inversion—only those crossing change driver boundaries.</p>
<p><strong>Practical improvement</strong>: Before introducing an abstraction layer, verify that the things on either side genuinely change independently. If they always change together, the abstraction adds complexity without benefit.</p>
<hr>
<p><a id="package-architecture-principles"></a></p>
</section>
</section>
<section id="package-architecture-principles" class="level2" data-number="13">
<h2 data-number="13" class="anchored" data-anchor-id="package-architecture-principles"><span class="header-section-number">13</span> Package Architecture Principles</h2>
<p>The Package Principles suffer from the same fundamental issue as the SOLID principles: they describe <em>what</em> to achieve but provide no criterion for <em>how</em> to identify the right boundaries. IVP provides that criterion—change drivers—making these principles actionable.</p>
<p><a id="relevant-change-drivers"></a></p>
<section id="relevant-change-drivers-14" class="level3" data-number="13.1">
<h3 data-number="13.1" class="anchored" data-anchor-id="relevant-change-drivers-14"><span class="header-section-number">13.1</span> Relevant Change Drivers</h3>
<p>Package principles organize change at the deployment/release granularity: - <code>γ_package_A</code>, <code>γ_package_B</code> — classes that change together belong in same package - Packages with slow-changing drivers should be stable - Packages with fast-changing drivers should be volatile</p>
<p><a id="common-closure-principle-ccp"></a></p>
</section>
<section id="common-closure-principle-ccp" class="level3" data-number="13.2">
<h3 data-number="13.2" class="anchored" data-anchor-id="common-closure-principle-ccp"><span class="header-section-number">13.2</span> Common Closure Principle (CCP)</h3>
<p><strong>What Martin Said:</strong> &gt; “The classes in a package should be closed together against the same kinds of changes.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with CCP</strong>: What counts as “the same kind of change”? Without a definition, two architects can disagree about whether classes belong together.</p>
<p><strong>How IVP addresses this</strong>: CCP is literally IVP-4 at package granularity. “Same kind of change” = same change driver. Classes governed by the same authority, same business rule, or same external dependency belong together.</p>
<p><strong>Relationship</strong>: CCP is <strong>literally IVP-4 stated at package granularity</strong>.</p>
<hr>
<p><a id="common-reuse-principle-crp"></a></p>
</section>
<section id="common-reuse-principle-crp" class="level3" data-number="13.3">
<h3 data-number="13.3" class="anchored" data-anchor-id="common-reuse-principle-crp"><span class="header-section-number">13.3</span> Common Reuse Principle (CRP)</h3>
<p><strong>What Martin Said:</strong> &gt; “The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with CRP</strong>: CRP can conflict with CCP. CCP says “group things that change together”; CRP says “group things that are used together.” These aren’t always the same.</p>
<p><strong>How IVP addresses this</strong>: Both principles are approximations of IVP-4. Classes that change together (same change driver) should be packaged together. Usage patterns are a <em>heuristic</em> for shared change drivers, but causal analysis is more precise.</p>
<p><strong>Relationship</strong>: CRP emerges from <strong>IVP based on usage patterns</strong>.</p>
<hr>
<p><a id="reuserelease-equivalence-principle-rep"></a></p>
</section>
<section id="reuserelease-equivalence-principle-rep" class="level3" data-number="13.4">
<h3 data-number="13.4" class="anchored" data-anchor-id="reuserelease-equivalence-principle-rep"><span class="header-section-number">13.4</span> Reuse/Release Equivalence Principle (REP)</h3>
<p><strong>What Martin Said:</strong> &gt; “The granule of reuse is the granule of release.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with REP</strong>: REP is circular without additional criteria—<em>what</em> should be released together? It tells you the granule should match but not how to determine that granule.</p>
<p><strong>How IVP addresses this</strong>: Elements sharing a change driver share a release lifecycle. If pricing rules and inventory rules change independently, they should release independently.</p>
<p><strong>Relationship</strong>: REP is <strong>IVP applied to release management</strong>.</p>
<hr>
<p><a id="acyclic-dependencies-principle-adp"></a></p>
</section>
<section id="acyclic-dependencies-principle-adp" class="level3" data-number="13.5">
<h3 data-number="13.5" class="anchored" data-anchor-id="acyclic-dependencies-principle-adp"><span class="header-section-number">13.5</span> Acyclic Dependencies Principle (ADP)</h3>
<p><strong>What Martin Said:</strong> &gt; “Allow no cycles in the package dependency graph.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with ADP</strong>: ADP is a structural rule but doesn’t explain <em>why</em> cycles are problematic. Breaking cycles sometimes requires introducing abstractions that add complexity.</p>
<p><strong>How IVP addresses this</strong>: Cycles are problematic because they force co-variation. Packages in a cycle must deploy/test together even if they have independent change drivers. Breaking the cycle isolates independent variation—but only do it if the packages genuinely vary independently.</p>
<p><strong>Relationship</strong>: ADP is <strong>IVP-3 applied to prevent false variation coupling</strong>.</p>
<hr>
<p><a id="stable-dependencies-principle-sdp"></a></p>
</section>
<section id="stable-dependencies-principle-sdp" class="level3" data-number="13.6">
<h3 data-number="13.6" class="anchored" data-anchor-id="stable-dependencies-principle-sdp"><span class="header-section-number">13.6</span> Stable Dependencies Principle (SDP)</h3>
<p><strong>What Martin Said:</strong> &gt; “Depend in the direction of stability.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with SDP</strong>: “Stability” is defined circularly in terms of dependencies. A package is stable if many things depend on it. But <em>should</em> they depend on it? SDP assumes the dependency structure is correct.</p>
<p><strong>How IVP addresses this</strong>: Stability should reflect change driver frequency. Packages with slow-changing drivers (core domain concepts) should be stable; packages with fast-changing drivers (UI, integrations) should be unstable. Dependencies should flow from fast-changing to slow-changing.</p>
<p><strong>Relationship</strong>: SDP is <strong>IVP-3 applied to stability management</strong>.</p>
<hr>
<p><a id="stable-abstractions-principle-sap"></a></p>
</section>
<section id="stable-abstractions-principle-sap" class="level3" data-number="13.7">
<h3 data-number="13.7" class="anchored" data-anchor-id="stable-abstractions-principle-sap"><span class="header-section-number">13.7</span> Stable Abstractions Principle (SAP)</h3>
<p><strong>What Martin Said:</strong> &gt; “A package should be as abstract as it is stable.” &gt; — Robert C. Martin, <em>Agile Software Development</em> (2003)</p>
<p><strong>The Problem with SAP</strong>: SAP conflates two different things: stability (resistance to change) and abstraction (generality). A package can be stable because it’s mature and rarely needs changes—without being abstract. SAP assumes abstraction is the <em>only</em> path to stability.</p>
<p><strong>How IVP addresses this</strong>: Abstractions are stable because they unify elements with different specific change drivers under a common interface. The abstraction changes only when the <em>concept</em> changes, not when specific implementations change. But concrete packages can also be stable if they embody slowly-changing domain knowledge.</p>
<p><strong>Relationship</strong>: SAP ensures <strong>stability through IVP-compliant abstraction</strong>.</p>
<hr>
<p><a id="grasp-principles"></a></p>
</section>
</section>
<section id="grasp-principles" class="level2" data-number="14">
<h2 data-number="14" class="anchored" data-anchor-id="grasp-principles"><span class="header-section-number">14</span> GRASP Principles</h2>
<p>Craig Larman introduced GRASP (General Responsibility Assignment Software Patterns) in <em>Applying UML and Patterns</em> (1997). These nine principles guide responsibility assignment in OO design.</p>
<p><a id="relevant-change-drivers"></a></p>
<section id="relevant-change-drivers-15" class="level3" data-number="14.1">
<h3 data-number="14.1" class="anchored" data-anchor-id="relevant-change-drivers-15"><span class="header-section-number">14.1</span> Relevant Change Drivers</h3>
<p>GRASP principles assign responsibilities based on knowledge ownership: - <code>γ_knowledge</code> — the class whose driver governs the knowledge owns the responsibility - <code>γ_ui</code> vs.&nbsp;<code>γ_use_case</code> — Controller mediates between independent drivers - <code>γ_domain</code> vs.&nbsp;<code>γ_technical</code> — Pure Fabrication isolates technical variation</p>
<p><a id="information-expert"></a></p>
</section>
<section id="information-expert" class="level3" data-number="14.2">
<h3 data-number="14.2" class="anchored" data-anchor-id="information-expert"><span class="header-section-number">14.2</span> Information Expert</h3>
<p><strong>The Principle</strong>: Assign responsibility to the class with the necessary information to fulfill it.</p>
<p><strong>The Problem with Information Expert</strong>: “Necessary information” is ambiguous. A class might have the data but lack the right to change it. Information location doesn’t always indicate responsibility ownership. Multiple classes may have access to the same information—which is the “expert”?</p>
<p><strong>How IVP addresses this</strong>: The “expert” is the class whose change driver governs that knowledge. If pricing logic changes for pricing reasons, the class owning pricing knowledge should implement pricing behavior—even if other classes have access to the data.</p>
<p><strong>Relationship to IVP</strong>: Information Expert is <strong>IVP-4 for responsibility assignment</strong>. The expert is determined by which class’s change driver governs the knowledge in question.</p>
<hr>
<p><a id="creator"></a></p>
</section>
<section id="creator" class="level3" data-number="14.3">
<h3 data-number="14.3" class="anchored" data-anchor-id="creator"><span class="header-section-number">14.3</span> Creator</h3>
<p><strong>The Principle</strong>: Assign class B the responsibility to create instances of class A if B aggregates, contains, or closely uses A.</p>
<p><strong>The Problem with Creator</strong>: The heuristics (aggregates, contains, closely uses) don’t always align. A class might aggregate A but not be the right creator if instantiation logic varies independently from aggregation logic.</p>
<p><strong>How IVP addresses this</strong>: Creation responsibility follows change drivers. If A’s instantiation requirements change for the same reasons as B’s behavior, B should create A. If instantiation varies independently (e.g., different creation strategies), extract creation to a factory.</p>
<p><strong>Relationship to IVP</strong>: Creator is <strong>IVP-4 applied to object instantiation</strong>. Co-locate creation with usage when they share a change driver; separate when they don’t.</p>
<hr>
<p><a id="controller"></a></p>
</section>
<section id="controller" class="level3" data-number="14.4">
<h3 data-number="14.4" class="anchored" data-anchor-id="controller"><span class="header-section-number">14.4</span> Controller</h3>
<p><strong>The Principle</strong>: Assign responsibility for handling system events to a non-UI class representing the overall system or use case.</p>
<p><strong>The Problem with Controller</strong>: Where should controller logic live? Bloated controllers (“god classes”) violate SRP. Too many small controllers fragment use case logic. The principle provides no sizing criterion.</p>
<p><strong>How IVP addresses this</strong>: Controllers isolate UI variation from use case variation. The UI changes for presentation reasons; use cases change for business reasons. These are independent change drivers—IVP-3 mandates separation. The controller is the boundary. Size controllers by change driver scope, not arbitrary rules.</p>
<p><strong>Relationship to IVP</strong>: Controller is <strong>IVP-3 applied to UI/domain separation</strong>. The controller exists because UI and domain have independent change drivers.</p>
<hr>
<p><a id="low-coupling-high-cohesion"></a></p>
</section>
<section id="low-coupling-high-cohesion" class="level3" data-number="14.5">
<h3 data-number="14.5" class="anchored" data-anchor-id="low-coupling-high-cohesion"><span class="header-section-number">14.5</span> Low Coupling / High Cohesion</h3>
<p><strong>The Principles</strong>: Minimize dependencies between classes; ensure each class has focused purpose.</p>
<p><strong>The Problem with Low Coupling / High Cohesion</strong>: These are goals, not methods. “Minimize” and “focused” are vague. How low is low enough? How focused is focused enough? Without criteria, these become subjective judgments.</p>
<p><strong>How IVP addresses this</strong>: These are the <em>goals</em> IVP achieves. Low coupling = not coupling independent change drivers. High cohesion = grouping elements with the same change driver. IVP explains <em>why</em> these goals matter and <em>how</em> to achieve them with precise criteria.</p>
<p><strong>Relationship to IVP</strong>: Low Coupling is the <strong>goal of IVP-3</strong>; High Cohesion is the <strong>goal of IVP-4</strong>. IVP provides the operational definition of both.</p>
<hr>
<p><a id="polymorphism"></a></p>
</section>
<section id="polymorphism" class="level3" data-number="14.6">
<h3 data-number="14.6" class="anchored" data-anchor-id="polymorphism"><span class="header-section-number">14.6</span> Polymorphism</h3>
<p><strong>The Principle</strong>: Use polymorphic operations instead of explicit type checking.</p>
<p><strong>The Problem with Polymorphism</strong>: When is polymorphism warranted? Adding interfaces for single implementations adds ceremony. The principle doesn’t distinguish necessary polymorphism from over-engineering.</p>
<p><strong>How IVP addresses this</strong>: Type checking couples client code to each variant’s change driver. Polymorphism encapsulates each variant’s variation, so the client varies only for its own concerns. Apply polymorphism when variants have independent change drivers from the client.</p>
<p><strong>Relationship to IVP</strong>: Polymorphism is <strong>IVP-3 applied via type abstraction</strong>. It isolates independent variation behind a common interface.</p>
<hr>
<p><a id="indirection"></a></p>
</section>
<section id="indirection" class="level3" data-number="14.7">
<h3 data-number="14.7" class="anchored" data-anchor-id="indirection"><span class="header-section-number">14.7</span> Indirection</h3>
<p><strong>The Principle</strong>: Assign responsibility to an intermediate object to mediate between components.</p>
<p><strong>The Problem with Indirection</strong>: Every indirection adds complexity. When is the indirection worth it? “All problems can be solved by another level of indirection”—but this creates its own problems.</p>
<p><strong>How IVP addresses this</strong>: Indirection creates a boundary between independent change drivers. The intermediate object absorbs variation from both sides. But indirection without independent variation is unnecessary complexity—apply only when genuine independence exists.</p>
<p><strong>Relationship to IVP</strong>: Indirection is <strong>IVP-3 implemented via intermediary</strong>. Warranted only when the mediated components have independent change drivers.</p>
<hr>
<p><a id="protected-variations"></a></p>
</section>
<section id="protected-variations" class="level3" data-number="14.8">
<h3 data-number="14.8" class="anchored" data-anchor-id="protected-variations"><span class="header-section-number">14.8</span> Protected Variations</h3>
<p><strong>The Principle</strong>: Wrap instability points with interfaces; use polymorphism for implementations.</p>
<p><strong>The Problem with Protected Variations</strong>: What is an “instability point”? How do you identify them? The principle assumes you already know what’s unstable.</p>
<p><strong>How IVP addresses this</strong>: “Instability points” are locations where independent change drivers meet. Protected Variations is essentially IVP-3 stated as a pattern: isolate elements that vary independently behind stable interfaces. Change driver analysis identifies the instability points.</p>
<p><strong>Relationship to IVP</strong>: Protected Variations is <strong>essentially IVP-3 stated as a pattern</strong>. IVP provides the criterion for identifying instability points.</p>
<hr>
<p><a id="pure-fabrication"></a></p>
</section>
<section id="pure-fabrication" class="level3" data-number="14.9">
<h3 data-number="14.9" class="anchored" data-anchor-id="pure-fabrication"><span class="header-section-number">14.9</span> Pure Fabrication</h3>
<p><strong>The Principle</strong>: Create classes that don’t represent domain concepts to achieve low coupling and high cohesion.</p>
<p><strong>The Problem with Pure Fabrication</strong>: When is fabrication justified? Creating non-domain classes can obscure domain logic. The principle provides no criterion for when fabrication helps versus hurts.</p>
<p><strong>How IVP addresses this</strong>: Sometimes change driver boundaries don’t align with domain concepts. A “service” class might exist purely to isolate technical variation (database access, external APIs) from domain variation. Pure Fabrication acknowledges that IVP-compliant structure sometimes requires non-domain classes—but only when change drivers demand it.</p>
<p><strong>Relationship to IVP</strong>: Pure Fabrication supports <strong>IVP compliance when domain boundaries don’t match change driver boundaries</strong>.</p>
<hr>
<p><a id="functional-programming-principles"></a></p>
</section>
</section>
<section id="functional-programming-principles" class="level2" data-number="15">
<h2 data-number="15" class="anchored" data-anchor-id="functional-programming-principles"><span class="header-section-number">15</span> Functional Programming Principles</h2>
<p>FP principles take a different approach to the IVP problem: rather than organizing variation, they <em>eliminate</em> sources of variation. This is complementary to IVP’s organizational approach.</p>
<p><a id="relevant-change-drivers"></a></p>
<section id="relevant-change-drivers-16" class="level3" data-number="15.1">
<h3 data-number="15.1" class="anchored" data-anchor-id="relevant-change-drivers-16"><span class="header-section-number">15.1</span> Relevant Change Drivers</h3>
<p>FP principles often <em>eliminate</em> change drivers rather than organizing them: - <code>γ_mutation</code> — eliminated by immutability - <code>γ_side_effect</code> — eliminated by pure functions - <code>γ_structure</code> vs.&nbsp;<code>γ_behavior</code> — separated by higher-order functions - <code>γ_what</code> vs.&nbsp;<code>γ_how</code> — separated by declarative style</p>
<p><a id="immutability"></a></p>
</section>
<section id="immutability" class="level3" data-number="15.2">
<h3 data-number="15.2" class="anchored" data-anchor-id="immutability"><span class="header-section-number">15.2</span> Immutability</h3>
<p><strong>The Principle</strong>: Once created, data cannot be modified. Changes produce new values rather than mutating existing ones.</p>
<p><strong>The Problem with Mutability</strong>: Mutable state creates hidden variation—values can change unexpectedly, coupling code to temporal ordering and making reasoning difficult.</p>
<p><strong>How IVP addresses this</strong>: Immutability <strong>eliminates a category of change drivers</strong>. Each piece of mutable state is a potential source of variation. Immutability removes these sources entirely—no variation means no independent variation to separate.</p>
<p><strong>Relationship to IVP</strong>: Immutability achieves <strong>IVP compliance by elimination</strong> rather than organization. Fewer change drivers means fewer independence relationships to manage.</p>
<hr>
<p><a id="pure-functions"></a></p>
</section>
<section id="pure-functions" class="level3" data-number="15.3">
<h3 data-number="15.3" class="anchored" data-anchor-id="pure-functions"><span class="header-section-number">15.3</span> Pure Functions</h3>
<p><strong>The Principle</strong>: Functions that have no side effects and return the same output for the same input.</p>
<p><strong>The Problem with Impurity</strong>: Impure functions have hidden dependencies—they read or write external state, coupling them to concerns outside their explicit interface.</p>
<p><strong>How IVP addresses this</strong>: Pure functions achieve <strong>maximal cohesion by construction</strong>. A pure function: - Has no side effects (no accidental coupling to external state) - Depends only on its inputs (no hidden dependencies)</p>
<p>Pure functions naturally satisfy IVP-3: they can’t accidentally couple to independent concerns because they have no access to them.</p>
<p><strong>Relationship to IVP</strong>: Pure functions are <strong>IVP-3 compliant by construction</strong>. The function boundary perfectly isolates its change driver.</p>
<hr>
<p><a id="referential-transparency"></a></p>
</section>
<section id="referential-transparency" class="level3" data-number="15.4">
<h3 data-number="15.4" class="anchored" data-anchor-id="referential-transparency"><span class="header-section-number">15.4</span> Referential Transparency</h3>
<p><strong>The Principle</strong>: An expression can be replaced with its value without changing program behavior.</p>
<p><strong>The Problem without Referential Transparency</strong>: Refactoring is dangerous—you can’t safely move or reorganize code because hidden dependencies might break.</p>
<p><strong>How IVP addresses this</strong>: Referential transparency <strong>enables confident refactoring</strong>. If an expression can be replaced with its value, you can reorganize code without fear of breaking hidden dependencies. This supports IVP refactoring: separating concerns becomes safe when there are no hidden couplings.</p>
<p><strong>Relationship to IVP</strong>: Referential transparency <strong>enables IVP-compliant reorganization</strong>. It guarantees that structural changes don’t introduce accidental coupling.</p>
<hr>
<p><a id="function-composition"></a></p>
</section>
<section id="function-composition" class="level3" data-number="15.5">
<h3 data-number="15.5" class="anchored" data-anchor-id="function-composition"><span class="header-section-number">15.5</span> Function Composition</h3>
<p><strong>The Principle</strong>: Build complex functions by combining simpler ones: <code>(f ∘ g)(x) = f(g(x))</code>.</p>
<p><strong>The Problem with Monolithic Functions</strong>: Large functions mix multiple concerns, making them hard to change and test independently.</p>
<p><strong>How IVP addresses this</strong>: Composition respects <strong>change driver boundaries</strong>. In <code>f ∘ g</code>, function <code>f</code> varies for its concerns, <code>g</code> varies for its concerns. Composition maintains independence: changing <code>g</code>’s implementation doesn’t affect <code>f</code> (as long as types match).</p>
<p><strong>Relationship to IVP</strong>: Function composition is <strong>IVP-3 at the function level</strong>. Each function encapsulates its own change drivers, and composition preserves that isolation.</p>
<hr>
<p><a id="higher-order-functions"></a></p>
</section>
<section id="higher-order-functions" class="level3" data-number="15.6">
<h3 data-number="15.6" class="anchored" data-anchor-id="higher-order-functions"><span class="header-section-number">15.6</span> Higher-Order Functions</h3>
<p><strong>The Principle</strong>: Functions that take functions as arguments or return functions as results, enabling abstraction over behavior.</p>
<p><strong>The Problem without Higher-Order Functions</strong>: Behavioral variation requires code duplication or complex conditional logic, coupling iteration structure to transformation logic.</p>
<p><strong>How IVP addresses this</strong>: Higher-order functions <strong>isolate behavioral variation from structural variation</strong>. A higher-order function like <code>map</code> separates: - The iteration mechanism (structural concern) — changes for algorithm reasons - The transformation logic (behavioral concern) — changes for business reasons</p>
<p>These are independent change drivers. <code>map</code> encapsulates iteration so that transformation logic can vary independently.</p>
<p><strong>Relationship to IVP</strong>: Higher-order functions are <strong>IVP-3 applied to behavioral abstraction</strong>. They isolate structure from behavior when these have independent change drivers.</p>
<hr>
<p><a id="declarative-over-imperative"></a></p>
</section>
<section id="declarative-over-imperative" class="level3" data-number="15.7">
<h3 data-number="15.7" class="anchored" data-anchor-id="declarative-over-imperative"><span class="header-section-number">15.7</span> Declarative Over Imperative</h3>
<p><strong>The Principle</strong>: Describe <em>what</em> to compute, not <em>how</em> to compute it. Let the runtime determine execution strategy.</p>
<p><strong>The Problem with Imperative</strong>: Imperative code couples <em>what</em> you want with <em>how</em> it’s achieved. Changes to performance strategy require modifying business logic.</p>
<p><strong>How IVP addresses this</strong>: Declarative code <strong>separates intent from mechanism</strong>. - Intent changes for business reasons (<code>γ_business</code>) - Mechanism changes for performance/runtime reasons (<code>γ_runtime</code>)</p>
<p>These are independent change drivers. Declarative code expresses intent; the runtime handles mechanism. Query optimization in SQL, lazy evaluation in Haskell—these are IVP-3 in action.</p>
<p><strong>Relationship to IVP</strong>: Declarative style is <strong>IVP-3 applied to intent/mechanism separation</strong>. Business logic and execution strategy have independent change drivers.</p>
<hr>
<p><a id="algebraic-data-types-adts"></a></p>
</section>
<section id="algebraic-data-types-adts" class="level3" data-number="15.8">
<h3 data-number="15.8" class="anchored" data-anchor-id="algebraic-data-types-adts"><span class="header-section-number">15.8</span> Algebraic Data Types (ADTs)</h3>
<p><strong>The Principle</strong>: Model data as sum types (alternatives) and product types (combinations), making illegal states unrepresentable.</p>
<p><strong>The Problem without ADTs</strong>: Variation is implicit, scattered across conditionals. Missing cases cause runtime errors. Related variants aren’t grouped.</p>
<p><strong>How IVP addresses this</strong>: ADTs <strong>make variation explicit in types</strong>. A sum type like <code>Result&lt;T, E&gt; = Ok(T) | Err(E)</code> explicitly models two variation cases. Pattern matching forces handling both. This prevents accidental coupling—you can’t ignore a variant.</p>
<p><strong>Relationship to IVP</strong>: ADTs achieve <strong>IVP-4 by grouping related variations</strong> in a single type, while pattern matching ensures each case is handled by code that varies for that case’s reasons.</p>
<hr>
<p><a id="currying-and-partial-application"></a></p>
</section>
<section id="currying-and-partial-application" class="level3" data-number="15.9">
<h3 data-number="15.9" class="anchored" data-anchor-id="currying-and-partial-application"><span class="header-section-number">15.9</span> Currying and Partial Application</h3>
<p><strong>The Principle</strong>: Transform multi-argument functions into chains of single-argument functions. Apply some arguments now, the rest later.</p>
<p><strong>The Problem without Currying</strong>: Configuration and execution are entangled. Every call must provide all arguments, even when some are fixed for a context.</p>
<p><strong>How IVP addresses this</strong>: Currying <strong>enables staged configuration</strong>.</p>
<p><code>configure :: Config -&gt; Request -&gt; Response</code></p>
<p>Partially applying <code>config</code> creates a specialized handler. Configuration varies for deployment reasons (<code>γ_ops</code>); request handling varies for feature reasons (<code>γ_feature</code>). Currying separates these change drivers across time—configure once, use many times.</p>
<p><strong>Relationship to IVP</strong>: Currying is <strong>IVP-3 applied across time</strong>. It separates configuration (early-bound) from execution (late-bound) when these have independent change drivers.</p>
<hr>
<p><a id="lazy-evaluation"></a></p>
</section>
<section id="lazy-evaluation" class="level3" data-number="15.10">
<h3 data-number="15.10" class="anchored" data-anchor-id="lazy-evaluation"><span class="header-section-number">15.10</span> Lazy Evaluation</h3>
<p><strong>The Principle</strong>: Defer computation until results are needed. Compute only what’s actually used.</p>
<p><strong>The Problem with Eager Evaluation</strong>: Definition and execution are coupled. You can’t define infinite structures or separate “what to compute” from “when to compute it.”</p>
<p><strong>How IVP addresses this</strong>: Laziness <strong>decouples definition from execution</strong>. You define <em>what</em> a value is (its structure) separately from <em>when</em> it’s computed (execution strategy). Definition varies for business reasons; execution timing varies for performance reasons.</p>
<p><strong>Relationship to IVP</strong>: Lazy evaluation is <strong>IVP-3 applied to computation timing</strong>. Definition and execution have independent change drivers that laziness separates.</p>
<hr>
<p><a id="summary-what-ivp-brings"></a></p>
</section>
</section>
<section id="summary-what-ivp-brings" class="level2" data-number="16">
<h2 data-number="16" class="anchored" data-anchor-id="summary-what-ivp-brings"><span class="header-section-number">16</span> Summary: What IVP Brings</h2>
<p><a id="classic-principles-1960s1990s"></a></p>
<section id="classic-principles-1960s1990s" class="level3" data-number="16.1">
<h3 data-number="16.1" class="anchored" data-anchor-id="classic-principles-1960s1990s"><span class="header-section-number">16.1</span> Classic Principles (1960s–1990s)</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Separation of Concerns</td>
<td>IVP operationalizes</td>
<td>Objective criterion for “what’s a concern”</td>
</tr>
<tr class="even">
<td>Information Hiding</td>
<td>Complementary</td>
<td>IVP provides structure; IH provides economic criterion</td>
</tr>
<tr class="odd">
<td>DRY</td>
<td>Context-dependent</td>
<td>Criterion for when to deduplicate vs.&nbsp;keep separate</td>
</tr>
<tr class="even">
<td>KISS</td>
<td>IVP operationalizes</td>
<td>Precise definition of “unnecessary complexity”</td>
</tr>
<tr class="odd">
<td>Law of Demeter</td>
<td>IVP-3 at method scope</td>
<td>Explains <em>why</em> train wrecks are problematic</td>
</tr>
<tr class="even">
<td>PoLS</td>
<td>Orthogonal</td>
<td>Different dimension (understandability vs.&nbsp;evolvability)</td>
</tr>
<tr class="odd">
<td>Conway’s Law</td>
<td>IVP judges</td>
<td>Criterion for when to embrace vs.&nbsp;resist mirroring</td>
</tr>
<tr class="even">
<td>Tell, Don’t Ask</td>
<td>IVP refines</td>
<td>Co-locate when behavior shares change driver with data</td>
</tr>
<tr class="odd">
<td>CQS</td>
<td>Complementary</td>
<td>CQS ensures predictability; IVP ensures evolvability</td>
</tr>
</tbody>
</table>
<p><a id="xp-and-agile-principles-1990s2000s"></a></p>
</section>
<section id="xp-and-agile-principles-1990s2000s-1" class="level3" data-number="16.2">
<h3 data-number="16.2" class="anchored" data-anchor-id="xp-and-agile-principles-1990s2000s-1"><span class="header-section-number">16.2</span> XP and Agile Principles (1990s–2000s)</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>YAGNI</td>
<td>IVP operationalizes</td>
<td>Build abstractions when actual change drivers appear</td>
</tr>
<tr class="even">
<td>Passes Tests</td>
<td>Orthogonal</td>
<td>Correctness, not evolvability</td>
</tr>
<tr class="odd">
<td>Reveals Intention</td>
<td>Orthogonal</td>
<td>Understandability, not evolvability</td>
</tr>
<tr class="even">
<td>No Duplication</td>
<td>IVP-4 criterion</td>
<td>Same change driver = same knowledge</td>
</tr>
<tr class="odd">
<td>Fewest Elements</td>
<td>IVP defines necessity</td>
<td>One element per change driver</td>
</tr>
<tr class="even">
<td>OAOO</td>
<td>IVP-4 criterion</td>
<td>Knowledge identity = change driver identity</td>
</tr>
<tr class="odd">
<td>Technical Excellence</td>
<td>IVP operationalizes</td>
<td>Excellence = IVP-compliant structure</td>
</tr>
<tr class="even">
<td>Simplicity</td>
<td>IVP operationalizes</td>
<td>Simplicity = no accidental coupling</td>
</tr>
<tr class="odd">
<td>Emergent Design</td>
<td>IVP operationalizes</td>
<td>Teams discover change drivers; IVP guides structuring</td>
</tr>
</tbody>
</table>
<p><a id="systems-of-systems-principles-1990s2000s"></a></p>
</section>
<section id="systems-of-systems-principles-1990s2000s-1" class="level3" data-number="16.3">
<h3 data-number="16.3" class="anchored" data-anchor-id="systems-of-systems-principles-1990s2000s-1"><span class="header-section-number">16.3</span> Systems-of-Systems Principles (1990s–2000s)</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Stable Intermediate Forms</td>
<td>IVP for evolution</td>
<td>Each intermediate state must isolate constituent change drivers</td>
</tr>
<tr class="even">
<td>Policy Triage</td>
<td>IVP-3 via policy</td>
<td>Policy boundaries when structural control unavailable</td>
</tr>
<tr class="odd">
<td>Leverage Interfaces</td>
<td>DIP/IVP-3 at SoS scale</td>
<td>Standards isolate constituent change drivers</td>
</tr>
<tr class="even">
<td>Ensure Cooperation</td>
<td>Organizational change drivers</td>
<td>Technical + organizational factors both matter</td>
</tr>
</tbody>
</table>
<p><a id="cloud-native-principles-2010s"></a></p>
</section>
<section id="cloud-native-principles-2010s-1" class="level3" data-number="16.4">
<h3 data-number="16.4" class="anchored" data-anchor-id="cloud-native-principles-2010s-1"><span class="header-section-number">16.4</span> Cloud-Native Principles (2010s)</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 19%">
<col style="width: 43%">
<col style="width: 36%">
</colgroup>
<thead>
<tr class="header">
<th>Factor</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Config</td>
<td>IVP-3 for environment</td>
<td>Separates <code>γ_app</code> from <code>γ_environment</code></td>
</tr>
<tr class="even">
<td>Backing Services</td>
<td>IVP-3 for providers</td>
<td>Separates <code>γ_app</code> from <code>γ_provider</code></td>
</tr>
<tr class="odd">
<td>Build/Release/Run</td>
<td>IVP-3 for lifecycle</td>
<td>Separates <code>γ_build</code> from <code>γ_run</code></td>
</tr>
<tr class="even">
<td>Dev/Prod Parity</td>
<td>IVP alignment</td>
<td>Minimizes accidental <code>γ_dev</code> vs.&nbsp;<code>γ_prod</code> divergence</td>
</tr>
<tr class="odd">
<td>Processes</td>
<td>IVP-3 via statelessness</td>
<td>Isolates instances from each other</td>
</tr>
</tbody>
</table>
<p><a id="gof-principles"></a></p>
</section>
<section id="gof-principles-1" class="level3" data-number="16.5">
<h3 data-number="16.5" class="anchored" data-anchor-id="gof-principles-1"><span class="header-section-number">16.5</span> GoF Principles</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Program to Interface</td>
<td>IVP-3 at type level</td>
<td>Apply when implementation might vary independently</td>
</tr>
<tr class="even">
<td>Composition over Inheritance</td>
<td>IVP-3 for flexibility</td>
<td>Use inheritance only when parent/child share change driver</td>
</tr>
</tbody>
</table>
<p><a id="solid-principles"></a></p>
</section>
<section id="solid-principles-1" class="level3" data-number="16.6">
<h3 data-number="16.6" class="anchored" data-anchor-id="solid-principles-1"><span class="header-section-number">16.6</span> SOLID Principles</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>SRP</td>
<td>IVP at class level</td>
<td>Precise definition of “reason to change”</td>
</tr>
<tr class="even">
<td>OCP</td>
<td>IVP-3 for stable/variant separation</td>
<td>Criterion for <em>when</em> extension points are needed</td>
</tr>
<tr class="odd">
<td>LSP</td>
<td>IVP-4 behavioral constraint</td>
<td>Explains why contracts matter (prevents false unification)</td>
</tr>
<tr class="even">
<td>ISP</td>
<td>IVP-3 at interface level</td>
<td>Criterion for segregation boundaries</td>
</tr>
<tr class="odd">
<td>DIP</td>
<td>IVP-3 at layer level</td>
<td>Criterion for <em>when</em> abstraction is necessary</td>
</tr>
</tbody>
</table>
<p><a id="package-principles"></a></p>
</section>
<section id="package-principles" class="level3" data-number="16.7">
<h3 data-number="16.7" class="anchored" data-anchor-id="package-principles"><span class="header-section-number">16.7</span> Package Principles</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>CCP</td>
<td>Literally IVP-4</td>
<td>Defines “same kind of change” as same change driver</td>
</tr>
<tr class="even">
<td>CRP</td>
<td>IVP-4 via usage</td>
<td>Usage patterns as heuristic for shared change drivers</td>
</tr>
<tr class="odd">
<td>REP</td>
<td>IVP for releases</td>
<td>Change driver determines release granularity</td>
</tr>
<tr class="even">
<td>ADP</td>
<td>IVP-3 for cycles</td>
<td>Explains <em>why</em> cycles are problematic (forced co-variation)</td>
</tr>
<tr class="odd">
<td>SDP</td>
<td>IVP-3 for stability</td>
<td>Stability = slow-changing drivers; dependencies flow toward stability</td>
</tr>
<tr class="even">
<td>SAP</td>
<td>IVP via abstraction</td>
<td>Abstractions stable because they unify diverse implementations</td>
</tr>
</tbody>
</table>
<p><a id="grasp-principles"></a></p>
</section>
<section id="grasp-principles-1" class="level3" data-number="16.8">
<h3 data-number="16.8" class="anchored" data-anchor-id="grasp-principles-1"><span class="header-section-number">16.8</span> GRASP Principles</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Information Expert</td>
<td>IVP-4 for responsibility</td>
<td>Expert = class whose change driver governs the knowledge</td>
</tr>
<tr class="even">
<td>Creator</td>
<td>IVP-4 for instantiation</td>
<td>Creation follows change driver alignment</td>
</tr>
<tr class="odd">
<td>Controller</td>
<td>IVP-3 for UI separation</td>
<td>Isolates UI variation from use case variation</td>
</tr>
<tr class="even">
<td>Low Coupling</td>
<td>Goal of IVP-3</td>
<td>Don’t couple independent change drivers</td>
</tr>
<tr class="odd">
<td>High Cohesion</td>
<td>Goal of IVP-4</td>
<td>Group elements with same change driver</td>
</tr>
<tr class="even">
<td>Polymorphism</td>
<td>IVP-3 via interfaces</td>
<td>Encapsulates each variant’s change driver</td>
</tr>
<tr class="odd">
<td>Indirection</td>
<td>IVP-3 boundary</td>
<td>Creates boundary between independent change drivers</td>
</tr>
<tr class="even">
<td>Protected Variations</td>
<td>Essentially IVP-3</td>
<td>Isolate independent variation behind stable interfaces</td>
</tr>
<tr class="odd">
<td>Pure Fabrication</td>
<td>IVP-compliant structure</td>
<td>Non-domain classes for change driver isolation</td>
</tr>
</tbody>
</table>
<p><a id="functional-programming-principles"></a></p>
</section>
<section id="functional-programming-principles-1" class="level3" data-number="16.9">
<h3 data-number="16.9" class="anchored" data-anchor-id="functional-programming-principles-1"><span class="header-section-number">16.9</span> Functional Programming Principles</h3>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 40%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Principle</th>
<th>IVP Relationship</th>
<th>What IVP Adds</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Immutability</td>
<td>Eliminates variation</td>
<td>Removes a category of change drivers entirely</td>
</tr>
<tr class="even">
<td>Pure Functions</td>
<td>Maximal cohesion by construction</td>
<td>No accidental coupling possible</td>
</tr>
<tr class="odd">
<td>Referential Transparency</td>
<td>Enables IVP refactoring</td>
<td>Safe to reorganize when no hidden dependencies</td>
</tr>
<tr class="even">
<td>Function Composition</td>
<td>IVP-3 at function level</td>
<td>Preserves change driver isolation across composition</td>
</tr>
<tr class="odd">
<td>Higher-Order Functions</td>
<td>IVP-3 for behavior</td>
<td>Isolates behavioral variation from structural variation</td>
</tr>
<tr class="even">
<td>Declarative over Imperative</td>
<td>IVP-3 for intent/mechanism</td>
<td>Separates business intent from runtime mechanism</td>
</tr>
<tr class="odd">
<td>Algebraic Data Types</td>
<td>IVP-4 for variants</td>
<td>Makes variation explicit; groups related cases</td>
</tr>
<tr class="even">
<td>Currying</td>
<td>IVP-3 across time</td>
<td>Separates configuration from execution</td>
</tr>
<tr class="odd">
<td>Lazy Evaluation</td>
<td>IVP-3 for execution</td>
<td>Decouples definition from execution timing</td>
</tr>
</tbody>
</table>
<hr>
<p><a id="why-existing-principles-still-matter"></a></p>
</section>
</section>
<section id="why-existing-principles-still-matter" class="level2" data-number="17">
<h2 data-number="17" class="anchored" data-anchor-id="why-existing-principles-still-matter"><span class="header-section-number">17</span> Why Existing Principles Still Matter</h2>
<p>I want to be clear about something: this analysis should not be read as suggesting that established principles are obsolete or that practitioners should abandon them in favor of IVP alone. Quite the opposite.</p>
<p><a id="ivp-requires-domain-expertise"></a></p>
<section id="ivp-requires-domain-expertise" class="level3" data-number="17.1">
<h3 data-number="17.1" class="anchored" data-anchor-id="ivp-requires-domain-expertise"><span class="header-section-number">17.1</span> IVP Requires Domain Expertise</h3>
<p>IVP’s generality—<em>separate elements that vary for different causes; unify elements that vary for the same cause</em>—is both its strength and its challenge. Applying IVP effectively requires the ability to identify change drivers, and identifying change drivers requires <strong>domain expertise</strong>.</p>
<p>Consider a developer new to a codebase. They may not yet understand: - Who the stakeholders are and what each cares about - Which external systems the application integrates with - What regulations govern different parts of the business - Which parts of the system are stable versus volatile - The historical patterns of change revealed in version control</p>
<p>Without this context, “identify the change drivers” is not immediately actionable advice. The developer knows the <em>principle</em> but lacks the <em>knowledge</em> to apply it.</p>
<p><a id="established-principles-as-actionable-heuristics"></a></p>
</section>
<section id="established-principles-as-actionable-heuristics" class="level3" data-number="17.2">
<h3 data-number="17.2" class="anchored" data-anchor-id="established-principles-as-actionable-heuristics"><span class="header-section-number">17.2</span> Established Principles as Actionable Heuristics</h3>
<p>This is where the established principles prove their enduring value, despite presenting serious flaws in some cases. Each principle encapsulates domain-independent patterns that experienced practitioners have observed across many contexts:</p>
<p><strong>SRP</strong>: “Does this class have multiple reasons to change?” Even without knowing the specific change drivers, asking this question prompts useful reflection.</p>
<p><strong>DRY</strong>: “Am I duplicating knowledge?” This triggers examination of whether code fragments represent the same underlying concept.</p>
<p><strong>SOLID</strong>: Each principle offers a specific lens for examining code structure, with concrete structural indicators (interface size, dependency direction, substitutability).</p>
<p><strong>Law of Demeter</strong>: “Am I reaching through too many objects?” This is immediately observable without deep domain knowledge.</p>
<p><strong>12-Factor</strong>: The factors provide a checklist applicable to any cloud-native application, regardless of business domain.</p>
<p>These principles remain <strong>immediately actionable</strong> because they operate on structural properties visible in the code itself, not on causal relationships that require domain understanding.</p>
<p><a id="ivp-established-principles-complementary-tools"></a></p>
</section>
<section id="ivp-established-principles-complementary-tools" class="level3" data-number="17.3">
<h3 data-number="17.3" class="anchored" data-anchor-id="ivp-established-principles-complementary-tools"><span class="header-section-number">17.3</span> IVP + Established Principles: Complementary Tools</h3>
<p>The relationship between IVP and established principles is not replacement but <strong>complementarity</strong>:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 42%">
<col style="width: 57%">
</colgroup>
<thead>
<tr class="header">
<th>Situation</th>
<th>Best Approach</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Experienced in the domain, understand change drivers</td>
<td>Use IVP directly for principled decisions</td>
</tr>
<tr class="even">
<td>New to domain, learning the codebase</td>
<td>Use established principles as guardrails while building domain understanding</td>
</tr>
<tr class="odd">
<td>Principles conflict or seem to recommend different actions</td>
<td>Use IVP to resolve the conflict by analyzing change drivers</td>
</tr>
<tr class="even">
<td>Explaining a decision to others</td>
<td>Use IVP to provide the <em>why</em>, established principles for the <em>what</em></td>
</tr>
<tr class="odd">
<td>Teaching junior developers</td>
<td>Start with concrete principles, introduce IVP as the unifying explanation</td>
</tr>
</tbody>
</table>
<p><a id="principles-provide-context-ivp-lacks"></a></p>
</section>
<section id="principles-provide-context-ivp-lacks" class="level3" data-number="17.4">
<h3 data-number="17.4" class="anchored" data-anchor-id="principles-provide-context-ivp-lacks"><span class="header-section-number">17.4</span> Principles Provide Context IVP Lacks</h3>
<p>Each established principle carries contextual information that IVP’s generality cannot provide:</p>
<ul>
<li><strong>SRP</strong> focuses attention on the class level</li>
<li><strong>ISP</strong> focuses attention on interface design</li>
<li><strong>DIP</strong> focuses attention on layer boundaries</li>
<li><strong>Law of Demeter</strong> focuses attention on method call chains</li>
<li><strong>12-Factor</strong> focuses attention on deployment concerns</li>
</ul>
<p>When combined with IVP’s unifying insight, these principles become <em>more</em> powerful, not less. You understand not just <em>what</em> to do but <em>why</em> it works—and crucially, <em>when</em> to deviate because the change driver analysis suggests a different approach.</p>
<p><a id="the-learning-journey"></a></p>
</section>
<section id="the-learning-journey" class="level3" data-number="17.5">
<h3 data-number="17.5" class="anchored" data-anchor-id="the-learning-journey"><span class="header-section-number">17.5</span> The Learning Journey</h3>
<p>For practitioners at different experience levels:</p>
<p><strong>Beginners</strong>: Learn the established principles. They provide concrete, actionable guidance that improves code quality immediately. Don’t worry yet about the deeper unification.</p>
<p><strong>Intermediate</strong>: Start noticing when principles conflict or when applying them “correctly” still produces poor results. This is the signal to look deeper—to ask <em>why</em> these principles exist.</p>
<p><strong>Advanced</strong>: Use IVP as the foundational lens. Recognize established principles as constrained instantiations of IVP. Apply IVP directly when you understand the change drivers; fall back to established principles as reliable heuristics when domain knowledge is incomplete.</p>
<p><strong>Expert</strong>: Teach both. Use established principles to make ideas concrete and accessible. Use IVP to explain the underlying unity and to guide decisions in novel situations where no established principle directly applies.</p>
<p><a id="when-no-existing-principle-applies"></a></p>
</section>
<section id="when-no-existing-principle-applies" class="level3" data-number="17.6">
<h3 data-number="17.6" class="anchored" data-anchor-id="when-no-existing-principle-applies"><span class="header-section-number">17.6</span> When No Existing Principle Applies</h3>
<p>Sometimes you face a design decision where none of the established principles seem directly relevant:</p>
<ul>
<li>A novel architectural pattern with no precedent in the literature</li>
<li>A domain-specific structure that doesn’t map to standard OO or FP patterns</li>
<li>A cross-cutting concern that spans multiple traditional boundaries</li>
<li>An integration point between systems with incompatible assumptions</li>
</ul>
<p>In these situations, <strong>IVP is always applicable</strong>. The question “What causes this to change, and are those causes independent?” applies universally—to code, configuration, infrastructure, data schemas, team structures, and any other aspect of software systems.</p>
<p>The established principles are IVP applied to common, recurring situations. When you encounter an uncommon situation, you can derive the appropriate guidance directly from IVP by analyzing the change drivers involved.</p>
<p><a id="the-principles-remain-valid"></a></p>
</section>
<section id="the-principles-remain-valid" class="level3" data-number="17.7">
<h3 data-number="17.7" class="anchored" data-anchor-id="the-principles-remain-valid"><span class="header-section-number">17.7</span> The Principles Remain Valid</h3>
<p>Nothing in this article invalidates any of the principles discussed. SRP is still correct: a class <em>should</em> have only one reason to change. IVP simply explains <em>what</em> a “reason to change” is (a change driver) and provides the criterion for identifying when you’ve achieved it.</p>
<p>The principles represent five decades of accumulated wisdom about software structure. IVP doesn’t replace this wisdom—it <em>explains</em> it, <em>unifies</em> it, and <em>extends</em> it to situations where the established principles don’t directly apply.</p>
<p>Use IVP to understand why the principles work. Use the principles to make IVP actionable in your daily work. And when no principle seems to fit, use IVP directly.</p>
<hr>
<p><a id="practical-takeaways"></a></p>
</section>
</section>
<section id="practical-takeaways" class="level2" data-number="18">
<h2 data-number="18" class="anchored" data-anchor-id="practical-takeaways"><span class="header-section-number">18</span> Practical Takeaways</h2>
<ol type="1">
<li><p><strong>One principle to rule them all</strong>: Instead of memorizing 15+ independent principles, learn IVP and derive specific guidance for any situation through change driver analysis.</p></li>
<li><p><strong>Empirical, not predictive</strong>: Analyze your version control history. What actually changes together? What changes independently? Let causal reality guide structure.</p></li>
<li><p><strong>Question before abstracting</strong>: Before adding interfaces, inheritance, or shared utilities, verify that you’re dealing with genuinely independent or dependent variation. Abstraction without independent variation is premature.</p></li>
<li><p><strong>Cohesion primacy</strong>: Focus on cohesion, not coupling. Accidental coupling manifests as reduced cohesion (foreign change drivers). Maximize cohesion and coupling takes care of itself.</p></li>
<li><p><strong>Architecture is knowledge work</strong>: You’re not just managing dependencies. You’re organizing domain knowledge. Each module should completely and purely embody one domain’s knowledge.</p></li>
</ol>
<hr>
<p><a id="references"></a></p>
</section>
<section id="references" class="level2" data-number="19">
<h2 data-number="19" class="anchored" data-anchor-id="references"><span class="header-section-number">19</span> References</h2>
<p><a id="ivp"></a></p>
<section id="ivp" class="level3" data-number="19.1">
<h3 data-number="19.1" class="anchored" data-anchor-id="ivp"><span class="header-section-number">19.1</span> IVP</h3>
<ul>
<li>Loth, Y. (2025). “The Independent Variation Principle - A Unifying Meta-Principle for Software Architecture”</li>
</ul>
<p><a id="classic-principles"></a></p>
</section>
<section id="classic-principles" class="level3" data-number="19.2">
<h3 data-number="19.2" class="anchored" data-anchor-id="classic-principles"><span class="header-section-number">19.2</span> Classic Principles</h3>
<ul>
<li>Beck, K. (2000). <em>Extreme Programming Explained: Embrace Change</em>. Addison-Wesley. (Four Rules of Simple Design, YAGNI, OAOO)</li>
<li>Conway, M.E. (1968). “How Do Committees Invent?” <em>Datamation</em>, 14(4), 28–31.</li>
<li>Dijkstra, E.W. (1974). “On the Role of Scientific Thought.” EWD447.</li>
<li>Hunt, A. &amp; Thomas, D. (1999). <em>The Pragmatic Programmer: From Journeyman to Master</em>. Addison-Wesley.</li>
<li>Lieberherr, K., Holland, I., &amp; Riel, A. (1988). “Object-Oriented Programming: An Objective Sense of Style.” <em>OOPSLA ’88 Proceedings</em>, 323–334.</li>
<li>Meyer, B. (1988). <em>Object-Oriented Software Construction</em>. Prentice Hall. (CQS origin)</li>
<li>Parnas, D.L. (1972). “On the Criteria To Be Used in Decomposing Systems into Modules.” <em>Communications of the ACM</em>, 15(12), 1053–1058.</li>
</ul>
<p><a id="agile-and-cloud-native"></a></p>
</section>
<section id="agile-and-cloud-native" class="level3" data-number="19.3">
<h3 data-number="19.3" class="anchored" data-anchor-id="agile-and-cloud-native"><span class="header-section-number">19.3</span> Agile and Cloud-Native</h3>
<ul>
<li>Beck, K. et al.&nbsp;(2001). <a href="https://agilemanifesto.org/">“Manifesto for Agile Software Development”</a>. (Agile Manifesto)</li>
<li>Beck, K. et al.&nbsp;(2001). <a href="https://agilemanifesto.org/principles.html">“Principles behind the Agile Manifesto”</a>. (12 Principles)</li>
<li>Wiggins, A. (2011). <a href="https://12factor.net/">“The Twelve-Factor App”</a>. Heroku.</li>
</ul>
<p><a id="systems-of-systems"></a></p>
</section>
<section id="systems-of-systems" class="level3" data-number="19.4">
<h3 data-number="19.4" class="anchored" data-anchor-id="systems-of-systems"><span class="header-section-number">19.4</span> Systems-of-Systems</h3>
<ul>
<li>INCOSE (2022). <a href="https://www.incose.org/2023_redesign/publications/products/se-principles">“Systems Engineering Principles”</a>. International Council on Systems Engineering.</li>
<li>Maier, M.W. (1998). “Architecting Principles for Systems-of-Systems.” <em>Systems Engineering</em>, 1(4), 267–284.</li>
<li>Maier, M.W. &amp; Rechtin, E. (2009). <em>The Art of Systems Architecting</em>. 3rd ed.&nbsp;CRC Press.</li>
</ul>
<p><a id="oo-design-patterns-and-principles"></a></p>
</section>
<section id="oo-design-patterns-and-principles" class="level3" data-number="19.5">
<h3 data-number="19.5" class="anchored" data-anchor-id="oo-design-patterns-and-principles"><span class="header-section-number">19.5</span> OO Design Patterns and Principles</h3>
<ul>
<li>Gamma, E., Helm, R., Johnson, R., &amp; Vlissides, J. (1994). <em>Design Patterns: Elements of Reusable Object-Oriented Software</em>. Addison-Wesley. (GoF)</li>
<li>Larman, C. (2004). <em>Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design</em>. 3rd ed.&nbsp;Prentice Hall. (GRASP)</li>
</ul>
<p><a id="solid-principles"></a></p>
</section>
<section id="solid-principles-2" class="level3" data-number="19.6">
<h3 data-number="19.6" class="anchored" data-anchor-id="solid-principles-2"><span class="header-section-number">19.6</span> SOLID Principles</h3>
<ul>
<li>Liskov, B. &amp; Wing, J. (1994). “A Behavioral Notion of Subtyping.” <em>ACM Transactions on Programming Languages and Systems</em>, 16(6), 1811–1841.</li>
<li>Martin, R.C. (1996). “The Open-Closed Principle.” <em>C++ Report</em>.</li>
<li>Martin, R.C. (1996). “The Dependency Inversion Principle.” <em>C++ Report</em>.</li>
<li>Martin, R.C. (1996). “The Interface Segregation Principle.” <em>C++ Report</em>.</li>
<li>Martin, R.C. (2003). <em>Agile Software Development: Principles, Patterns, and Practices</em>. Prentice Hall.</li>
<li>Martin, R.C. (2017). <em>Clean Architecture: A Craftsman’s Guide to Software Structure and Design</em>. Prentice Hall.</li>
</ul>
<p><a id="critiques-and-alternatives"></a></p>
</section>
<section id="critiques-and-alternatives" class="level3" data-number="19.7">
<h3 data-number="19.7" class="anchored" data-anchor-id="critiques-and-alternatives"><span class="header-section-number">19.7</span> Critiques and Alternatives</h3>
<ul>
<li>Dodds, K.C. (2019). <a href="https://kentcdodds.com/blog/aha-programming">“AHA Programming”</a> — Avoid Hasty Abstractions.</li>
<li>North, D. (2022). <a href="https://dannorth.net/cupid-for-joyful-coding/">“CUPID—for joyful coding”</a> — Properties over principles.</li>
<li>Swizec, T. (2020). <a href="https://swizec.com/blog/dry-the-common-source-of-bad-abstractions/">“DRY—the common source of bad abstractions”</a>.</li>
<li>Tedinski, T. (2019). <a href="https://www.tedinski.com/2019/04/02/solid-critique.html">“Deconstructing SOLID design principles”</a>.</li>
</ul>
<hr>
<p>IVP Paper: <a href="https://zenodo.org/records/18024111">https://zenodo.org/records/18024111</a></p>


</section>
</section>

 ]]></description>
  <category>ivp</category>
  <category>engineering</category>
  <category>design</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-02-13-the-independent-variation-principle-what-it-brings-compared-to-every-design-principle-you-know-4ip7.html</guid>
  <pubDate>Fri, 13 Feb 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>My AI Deleted Important Files, So I Added Model Routing</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-01-27-my-ai-deleted-important-files-so-i-added-model-routing-50gl.html</link>
  <description><![CDATA[ 





<p>Last week I asked Claude Code to “clean up the old summary files” and it deleted documentation I actually needed. Git saved me, but when I looked at the diff I noticed something important: the session was running on Haiku, which I’d forgotten I’d switched to. Haiku did exactly what I asked — and that was precisely the problem. I had given a vague deletion request to a model that doesn’t stop to consider what “old” might mean in context.</p>
<section id="the-actual-problem" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-actual-problem"><span class="header-section-number">1</span> The actual problem</h2>
<p>Claude offers three models, each with different capabilities and costs:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Model</th>
<th>Cost</th>
<th>Good at</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Haiku</td>
<td>cheap</td>
<td>fast, mechanical stuff</td>
</tr>
<tr class="even">
<td>Sonnet</td>
<td>10x</td>
<td>thinking things through</td>
</tr>
<tr class="odd">
<td>Opus</td>
<td>75x</td>
<td>heavy reasoning</td>
</tr>
</tbody>
</table>
<p>Haiku works fine for tasks like “change this variable name” or “add a semicolon.” However, it falls apart when you ask it to “delete the old files” — because “old” means whatever Haiku decides it means, and Haiku doesn’t pause to question its interpretation.</p>
</section>
<section id="what-i-changed" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-i-changed"><span class="header-section-number">2</span> What I changed</h2>
<p>To fix this, I added routing rules to my global <code>~/.claude/CLAUDE.md</code> (which applies to all projects, unless a project defines its own routing rules). The key change is that a dedicated router agent — running on Sonnet — now examines every request first and decides where to send it:</p>
<ol type="1">
<li><strong>Parse intent</strong>: What does this request actually mean?</li>
<li><strong>Assess risk</strong>: Is it going to delete or overwrite something?</li>
<li><strong>Match to agents</strong>: Is there a specialized agent for this exact task?</li>
<li><strong>Choose model tier</strong>: If not specialized, which model tier makes sense?</li>
<li><strong>Route immediately</strong>: Delegate to the chosen agent without attempting the task itself</li>
</ol>
<p>In other words, Sonnet reads the request, applies these rules, and then routes to the appropriate agent. It never executes the task itself.</p>
<section id="why-sonnet-does-the-routing" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="why-sonnet-does-the-routing"><span class="header-section-number">2.1</span> Why Sonnet does the routing</h3>
<p>Every request goes through <code>router</code> first — no exceptions, regardless of what model the session runs on or how obvious the task seems. This might seem like unnecessary overhead, so let me explain why it matters.</p>
<p><strong>The core rationale:</strong></p>
<ul>
<li><strong>Cost efficiency</strong>: Without a dedicated router, capable models tend to handle tasks themselves. If you start a session on Opus, Opus will eventually decide “I can do this” for some request — even trivial ones that Haiku could handle for 1/75th the cost. By forcing everything through <code>router</code>, execution always goes to the cheapest model that can actually handle the task.</li>
<li><strong>Consistency</strong>: Because all routing decisions flow through one component, you get predictable behavior regardless of your session model.</li>
<li><strong>Simplicity</strong>: The architecture stays clean — just one hop (router → executor) rather than chains of delegation.</li>
</ul>
<p>Yes, spawning an agent adds latency. But the alternative is Opus burning tokens on tasks Haiku could handle just as well. In practice, the routing overhead pays for itself many times over.</p>
<p><strong>Important caveat:</strong> CLAUDE.md instructions are advisory, not mechanically enforced. The model may still decide to handle simple tasks directly. That said, the routing works best when the model recognizes it should delegate — and in my experience, it usually does.</p>
<p><strong>The “no direct agent spawning” rule:</strong> This is perhaps the most important constraint: the main session model must NEVER spawn agents directly. The ONLY valid flow is <code>User request → router → agent</code>. This applies even when the task seems obvious.</p>
<p>Why so strict? Because without this rule, capable models will rationalize shortcuts. They’ll think: “This is clearly an Explore task, I’ll just spawn the Explore agent directly.” But that defeats the entire routing system. The router exists precisely to make these decisions — not the main session model. Put differently: the extra hop through router is not optional overhead — it IS the system.</p>
<p>There’s also a fallback for edge cases. When Sonnet isn’t sure how to route something, it delegates to <code>router-escalation</code> (which runs on Opus). This escalation agent analyzes the ambiguous request and spawns the appropriate agent directly. In practice, Sonnet handles 95%+ of routing decisions correctly; the remaining cases get escalated before anything runs.</p>
</section>
</section>
<section id="how-the-routing-works" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="how-the-routing-works"><span class="header-section-number">3</span> How the routing works</h2>
<p>Here’s the actual decision flow. Every request goes to a <code>router</code> agent first, which interprets the request, assesses risk, and decides where to send it:</p>
<pre class="text"><code>router receives request
    ↓
1. Parse intent: What is the user asking?
2. Assess risk: Deletion? Major changes? Significant consequences?
3. Match to agents: Is there a specialized agent for this exact task?

Priority 1: Project-specific specialized agent exists?
    → route to project agent (.claude/agents/)

Priority 2: No specialized agent - route to general agent:
    Mechanical + explicit paths + reversible?
        → haiku-general

    Ambiguous OR destructive OR needs judgment?
        → sonnet-general

    Math proofs, logic verification, high-stakes?
        → opus-general

Priority 3: Main Claude (no agent spawn):
    Conversation/coordination only
    Questions about the system itself
    Tasks requiring no tool use

Uncertain about routing decision?
    → escalate to router-escalation (Opus) first</code></pre>
<p><strong>Key insight:</strong> The router agent is critical because without it, whatever model is active interprets the routing rules. If your session runs on Haiku, then Haiku decides where to route — which completely defeats the purpose. By contrast, using a dedicated router ensures consistent routing logic regardless of what model the session happens to be running.</p>
</section>
<section id="why-it-has-to-be-agents" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="why-it-has-to-be-agents"><span class="header-section-number">4</span> Why it has to be agents</h2>
<p>You might wonder why I’m using agents at all rather than just having the model switch modes. The reason is architectural: Claude Code can’t switch models mid-conversation. If you start a session on Haiku, everything runs on Haiku until the session ends. There’s no built-in way to say “this looks risky, bump up to Sonnet for this part.”</p>
<p>Spawning an agent is the only mechanism to use a different model. Agents run as subprocesses with their own model setting, which means if you need Sonnet to handle a deletion while your main session runs on Haiku, you have to spawn a Sonnet agent.</p>
<p>This leads to an important realization: agents aren’t just for organizing specialized tasks — they’re the only way to get the right model on the right task. The routing system depends entirely on this capability.</p>
</section>
<section id="the-five-agents" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-five-agents"><span class="header-section-number">5</span> The five agents</h2>
<p>The system uses two router agents for routing decisions, plus three general agents for execution.</p>
<p><strong>router (Sonnet)</strong> serves as the entry point for all requests. It interprets intent, assesses risk, and routes to the appropriate agent. Crucially, it never executes tasks itself — it always spawns another agent (either project-specific or general). When uncertain about a routing decision, it escalates to router-escalation.</p>
<p><strong>router-escalation (Opus)</strong> handles the edge cases where router isn’t confident. It analyzes the ambiguous request, makes the routing decision, and spawns the appropriate agent directly. Like router, it never executes tasks itself.</p>
<p>The remaining three agents are general-purpose executors for tasks that don’t match any specialized agent:</p>
<p><strong>haiku-general (Haiku)</strong> handles mechanical operations with no judgment needed — find-replace, pattern matching, simple transforms. It’s fast and cheap for explicit operations.</p>
<p><strong>sonnet-general (Sonnet)</strong> is the default for tasks requiring reasoning, analysis, or judgment calls. Anything that needs a second thought before executing lands here.</p>
<p><strong>opus-general (Opus)</strong> tackles complex reasoning: mathematical proofs, detecting subtle logical flaws, high-stakes decisions with significant consequences.</p>
<p>One important distinction: general agents are endpoints. They execute tasks themselves and do NOT further route to specialized agents. Only the router knows about project-specific agents.</p>
</section>
<section id="project-specific-specialized-agents" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="project-specific-specialized-agents"><span class="header-section-number">6</span> Project-specific specialized agents</h2>
<p>Beyond the five core agents, the router also checks a project’s <code>.claude/agents/</code> directory for specialized agents tailored to that project’s domain.</p>
<p>To give a concrete example, one of my research projects includes agents like <code>tikz-illustrator</code> (creates diagrams), <code>literature-researcher</code> (finds and integrates research papers), and <code>math-verifier</code> (validates mathematical models). This particular project to date has 42 such agents.</p>
<p>The key architectural principle here is that project-specific agents are the ONLY specialized agents in the system. General agents like haiku-general, sonnet-general, and opus-general do NOT route to them — only the router knows about project agents.</p>
<p>This explains why the “no direct spawning” rule is so important: if the main session model could spawn agents directly, it might bypass the router entirely and miss project-specific agents that would be better suited for the task.</p>
</section>
<section id="risk-assessment-for-deletions" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="risk-assessment-for-deletions"><span class="header-section-number">7</span> Risk assessment for deletions</h2>
<p>For any task involving file deletion or major changes, the router performs a quick risk assessment: What’s the scope? Does the content look valuable? Did the user give exact paths or just patterns? Is this reversible?</p>
<p>Based on these factors, it routes defensively:</p>
<ul>
<li>High risk → <code>sonnet-general</code> or <code>opus-general</code></li>
<li>Low risk + explicit paths → <code>haiku-general</code></li>
<li>Any uncertainty → <code>sonnet-general</code> for analysis first</li>
</ul>
<p>Haiku only touches destructive operations when the user provided exact file paths, the files are clearly disposable, and the operation is easily reversible. Everything else goes to Sonnet, which examines what matches, checks if it looks important, and asks before deleting.</p>
</section>
<section id="some-examples" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="some-examples"><span class="header-section-number">8</span> Some examples</h2>
<p><code>"Change 'colour' to 'color' in src/utils.ts"</code> → <strong>Haiku</strong>. The file is explicit, the change is non-destructive, and the intent is clear.</p>
<p><code>"Clean up the old files in this directory"</code> → <strong>Sonnet</strong>. Both “old” and “clean up” are ambiguous, so this needs judgment before execution.</p>
<p><code>"Check if the proof in section 3.2 is valid"</code> → <strong>Opus</strong>. Verifying math proofs is exactly where you don’t want mistakes.</p>
</section>
<section id="built-in-guardrails" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="built-in-guardrails"><span class="header-section-number">9</span> Built-in guardrails</h2>
<p>Each general agent has rules baked into its definition: read files before touching them, don’t delete based on patterns alone, and if uncertain, ask or escalate. These aren’t suggestions — they’re part of the agent specification.</p>
</section>
<section id="before-and-after" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="before-and-after"><span class="header-section-number">10</span> Before and after</h2>
<p><strong>Before:</strong></p>
<p>“Delete the old implementation files” → Haiku (session model) → wrong files gone</p>
<p><strong>After:</strong></p>
<p>“Delete the old implementation files” → router → sonnet-general → “these 3 files match, they contain X, want me to proceed?”</p>
</section>
<section id="results" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="results"><span class="header-section-number">11</span> Results</h2>
<p>I haven’t had an accidental deletion since. Costs went down too, because right-sizing models saves money. And perhaps most importantly, I actually trust the system now — something I didn’t realize was missing until I had it.</p>
</section>
<section id="if-you-want-to-try-this" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="if-you-want-to-try-this"><span class="header-section-number">12</span> If you want to try this</h2>
<p>Ask Claude Code to set it up. Here’s roughly what I used:</p>
<pre class="text"><code>Create routing and general-purpose agents in ~/.claude/agents/:

Router agents (ensure routing happens on the right model):
1. router (Sonnet) - entry point for all requests; interprets intent,
   assesses risk, routes to project-specific or general agents
2. router-escalation (Opus) - handles edge cases when router is uncertain;
   makes routing decision and spawns agent directly

General agents (for tasks without specialized agents):
3. haiku-general (Haiku) - mechanical operations, no judgment needed
4. sonnet-general (Sonnet) - default for reasoning, analysis, judgment calls
5. opus-general (Opus) - complex reasoning, proofs, high-stakes decisions

Then add routing rules to ~/.claude/CLAUDE.md:
- If a project has its own routing rules in .claude/CLAUDE.md, use those instead
  (project-specific configuration takes precedence over global rules)
- EVERY request goes through router first, no exceptions
  (even if session runs on Opus, even if task seems obvious)
- The main session model MUST NOT spawn agents directly
  (ONLY valid flow: user request → router → agent)
- router follows this decision tree:
  1. Parse intent: What is the user asking?
  2. Assess risk: Deletion? Major changes? Consequences?
  3. Match to agents: Check project's .claude/agents/ first
  4. Choose model tier: Haiku/Sonnet/Opus based on complexity
  5. Route immediately: Delegate without attempting task
- Project-specific agents (Priority 1): Route when exact match exists
- General agents (Priority 2): Execute tasks themselves - they do NOT
  further route to specialized agents
- Main Claude (Priority 3): Conversation/coordination/system questions only
- Risk assessment for destructive operations:
  - Never route to haiku-general unless explicit paths + disposable + reversible
  - High risk → sonnet-general or opus-general
  - Any uncertainty → sonnet-general for analysis
- If router is uncertain about routing decision → escalate to router-escalation

Include examples showing when to use each tier and the risk assessment rules.

Context for Claude (why this matters):

Without explicit routing through router, behavior depends on session model.
Haiku might misroute deletions. Opus might handle everything itself.
By forcing every request through router, routing logic is consistent
regardless of session model.

The "no direct spawning" rule prevents shortcuts: without it, capable
models rationalize "this is obviously task X, I'll spawn agent Y directly."
The extra hop through router is not overhead - it IS the system.

Claude Code can't switch models mid-session. Spawning an agent is the
only way to use a different model. Router isn't optional - it's the
mechanism that guarantees consistent routing behavior.</code></pre>
<p>Claude will generate the agent files and update your global configuration. Since it’s in <code>~/.claude/</code>, it applies to all your projects by default.</p>
<hr>
<p>If you’ve tried something similar or have a different approach, I’d be interested to hear about it.</p>


</section>

 ]]></description>
  <category>ai</category>
  <category>architecture</category>
  <category>engineering</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-01-27-my-ai-deleted-important-files-so-i-added-model-routing-50gl.html</guid>
  <pubDate>Tue, 27 Jan 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>IVP Compliance Review: CodeAI - An AI-Designed Language Evaluated Against the Independent Variation Principle</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-01-13-ivp-compliance-review-codeai-an-ai-designed-language-evaluated-against-the-independent-variation-4ca9.html</link>
  <description><![CDATA[ 





<section id="executive-summary" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="executive-summary"><span class="header-section-number">1</span> Executive Summary</h2>
<p>This document presents a formal architectural review of <a href="https://github.com/bargom/codeai">CodeAI</a>, a domain-specific language designed by large language models for backend service declaration. The review evaluates the language against the <strong>Independent Variation Principle (IVP)</strong>: the principle that each concern should vary in exactly one place.</p>
<p><strong>Key Findings:</strong> - ✅ <strong>Strong IVP Compliance</strong>: CodeAI demonstrates excellent concern separation at the language design level - ✅ <strong>Seven Independent Syntactic Domains</strong>: Infrastructure, data schema (relational), data schema (document), API surface, events, integrations, workflows, and scheduled jobs each have distinct variation points - ✅ <strong>Enforced Separation</strong>: The language syntax prevents concern entanglement through mandatory structural boundaries - ⚠️ <strong>Implementation Context</strong>: Review based on v1.0 codebase examples; runtime implementation not evaluated</p>
<p><strong>Verdict</strong>: CodeAI exhibits IVP-compliant design that actively guides developers toward maintainable, loosely-coupled system architectures.</p>
<hr>
</section>
<section id="introduction" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="introduction"><span class="header-section-number">2</span> 1. Introduction</h2>
<section id="context" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="context"><span class="header-section-number">2.1</span> 1.1 Context</h3>
<p>On LinkedIn, <a href="https://lnkd.in/exzsDHz7">Barış Gömeç announced</a> an experiment: “I asked AI to design a programming language that AI understands better.” The resulting language, CodeAI (<code>.cai</code>), is a declarative DSL for backend service definition, with the entire implementation generated by Claude Opus 4.5.</p>
<p>The creator’s premise: simpler declarative syntax optimized for LLM code generation. This review adds a complementary architectural lens: <strong>Is the language also optimized for human maintainability through concern separation?</strong></p>
</section>
<section id="the-independent-variation-principle-ivp" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="the-independent-variation-principle-ivp"><span class="header-section-number">2.2</span> 1.2 The Independent Variation Principle (IVP)</h3>
<p>The Independent Variation Principle, as formally defined by Loth (2025), states four directives:</p>
<ol type="1">
<li><strong>Element admissibility (IVP-1):</strong> every element has at least one change driver.</li>
<li><strong>Change driver assignment (IVP-2):</strong> each element is assigned every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>Unit purity — separation (IVP-3):</strong> elements with different change driver assignments belong in distinct units.</li>
<li><strong>Unit completeness — unification (IVP-4):</strong> elements with the same change driver assignment belong in a single unit.</li>
</ol>
<p>A <strong>change driver</strong> is any source of variation in a system—a reason why code might need to change. A <strong>change driver assignment</strong> maps each element (function, class, module, file) to the set of change drivers that influence it. IVP prescribes that elements varying for the same reasons should be grouped together, while elements varying for different reasons should be separated.</p>
<p>IVP generalizes classical principles like Single Responsibility (SRP), Don’t Repeat Yourself (DRY), and Separation of Concerns (SoC) by providing a unified framework based on independent variability. It extends Parnas’s information hiding criterion by making change drivers explicit.</p>
<p><strong>IVP Compliance Criteria:</strong> 1. <strong>Identification</strong>: Can distinct change drivers be clearly identified? 2. <strong>Localization</strong>: Does each change driver have a single, well-defined unit where it varies? 3. <strong>Independence</strong>: Can one change driver change without forcing changes to units governed by different change drivers? 4. <strong>Non-Repetition</strong>: Is each change driver assignment expressed exactly once?</p>
<section id="the-role-of-programming-languages-in-ivp" class="level4" data-number="2.2.1">
<h4 data-number="2.2.1" class="anchored" data-anchor-id="the-role-of-programming-languages-in-ivp"><span class="header-section-number">2.2.1</span> 1.2.1 The Role of Programming Languages in IVP</h4>
<p><strong>A well-designed programming language should help developers achieve IVP compliance</strong> through its syntactic and semantic structure. Language design influences architectural quality by:</p>
<ol type="1">
<li><strong>Providing Appropriate Abstractions</strong>: Offering constructs that map naturally to distinct change drivers (e.g., separate syntax for data schema vs.&nbsp;business logic)</li>
<li><strong>Enforcing Boundaries</strong>: Making it syntactically impossible or awkward to mix concerns that should vary independently</li>
<li><strong>Guiding Composition</strong>: Enabling references between concerns without requiring embedding (composition over containment)</li>
<li><strong>Encoding Architectural Intent</strong>: Making the separation of concerns visible and explicit in the code structure</li>
</ol>
<p>Languages that conflate multiple change drivers into single constructs (e.g., OOP classes mixing schema, validation, business logic, and persistence) make IVP compliance harder. Developers must fight against the language’s default organization. Conversely, languages with distinct syntactic spaces for distinct concerns (like CodeAI’s separation of <code>entity</code>, <code>endpoint</code>, <code>workflow</code>, <code>integration</code>, etc.) make IVP the path of least resistance.</p>
<p><strong>This review evaluates whether CodeAI succeeds in this linguistic support for IVP.</strong> If it does, the language not only benefits LLM code generation (through semantic clarity) but also human maintainability (through enforced concern separation).</p>
</section>
</section>
<section id="review-methodology" class="level3" data-number="2.3">
<h3 data-number="2.3" class="anchored" data-anchor-id="review-methodology"><span class="header-section-number">2.3</span> 1.3 Review Methodology</h3>
<p>This review analyzes CodeAI’s syntax and semantics through: 1. <strong>Syntactic Domain Analysis</strong>: Identifying top-level language constructs 2. <strong>Concern Mapping</strong>: Mapping change drivers to language constructs 3. <strong>Variation Scenario Testing</strong>: Evaluating independence through hypothetical change scenarios 4. <strong>Comparison Analysis</strong>: Contrasting with traditional mixed-concern frameworks</p>
<p><strong>Source Material</strong>: Official examples from the <a href="https://github.com/bargom/codeai">CodeAI repository</a> (<code>examples/</code> directory, v1.0).</p>
<hr>
</section>
</section>
<section id="architectural-analysis" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="architectural-analysis"><span class="header-section-number">3</span> 2. Architectural Analysis</h2>
<section id="identified-syntactic-domains" class="level3" data-number="3.1">
<h3 data-number="3.1" class="anchored" data-anchor-id="identified-syntactic-domains"><span class="header-section-number">3.1</span> 2.1 Identified Syntactic Domains</h3>
<p>CodeAI provides <strong>seven top-level declarative constructs</strong>, each targeting a distinct architectural concern:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 18%">
<col style="width: 20%">
<col style="width: 36%">
</colgroup>
<thead>
<tr class="header">
<th>Construct</th>
<th>Syntax</th>
<th>Purpose</th>
<th>Lines of Code*</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Configuration</td>
<td><code>config { }</code></td>
<td>Infrastructure settings</td>
<td>14-46</td>
</tr>
<tr class="even">
<td>Entity</td>
<td><code>entity Name { }</code></td>
<td>PostgreSQL data models</td>
<td>41-193</td>
</tr>
<tr class="odd">
<td>Collection</td>
<td><code>database mongodb { collection { } }</code></td>
<td>MongoDB document schemas</td>
<td>19-242</td>
</tr>
<tr class="even">
<td>Endpoint</td>
<td><code>endpoint METHOD /path { }</code></td>
<td>RESTful API definitions</td>
<td>200-617</td>
</tr>
<tr class="odd">
<td>Event</td>
<td><code>event Name { }</code></td>
<td>Event-driven messaging</td>
<td>623-711</td>
</tr>
<tr class="even">
<td>Integration</td>
<td><code>integration Name { }</code></td>
<td>External service clients</td>
<td>422-555</td>
</tr>
<tr class="odd">
<td>Workflow</td>
<td><code>workflow Name { }</code></td>
<td>Multi-step business processes</td>
<td>560-782</td>
</tr>
<tr class="even">
<td>Job</td>
<td><code>job Name { }</code></td>
<td>Scheduled background tasks</td>
<td>197-653</td>
</tr>
</tbody>
</table>
<p>*Line ranges from example files: <code>blog-api.cai</code>, <code>ecommerce.cai</code>, <code>mongodb-collections.cai</code>, <code>scheduled-jobs.cai</code></p>
</section>
<section id="concern-to-construct-mapping" class="level3" data-number="3.2">
<h3 data-number="3.2" class="anchored" data-anchor-id="concern-to-construct-mapping"><span class="header-section-number">3.2</span> 2.2 Concern-to-Construct Mapping</h3>
<p>Each syntactic domain addresses a specific change driver:</p>
<section id="infrastructure-configuration-concern" class="level4" data-number="3.2.1">
<h4 data-number="3.2.1" class="anchored" data-anchor-id="infrastructure-configuration-concern"><span class="header-section-number">3.2.1</span> 2.2.1 Infrastructure Configuration Concern</h4>
<p><strong>Change Driver</strong>: “How the application runtime is configured”</p>
<p><strong>Variation Point</strong>: <code>config { }</code> block</p>
<pre class="cai"><code>config {
    name: "blog-api"
    version: "1.0.0"

    database: postgres {
        pool_size: 20
        timeout: 30s
    }

    cache: redis {
        ttl: 5m
        prefix: "blog:"
    }

    auth: jwt {
        issuer: env(JWT_ISSUER)
        secret: env(JWT_SECRET)
        expiry: 24h
    }
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Database configuration varies independently of entity definitions - Cache settings can change without modifying endpoints - Authentication parameters isolated from business logic</p>
</section>
<section id="data-schema-concern-relational" class="level4" data-number="3.2.2">
<h4 data-number="3.2.2" class="anchored" data-anchor-id="data-schema-concern-relational"><span class="header-section-number">3.2.2</span> 2.2.2 Data Schema Concern (Relational)</h4>
<p><strong>Change Driver</strong>: “What data structures the application persists”</p>
<p><strong>Variation Point</strong>: <code>entity { }</code> blocks</p>
<pre class="cai"><code>entity Post {
    description: "A blog post with content and metadata"

    id: uuid, primary, auto

    // Content
    title: string, required, searchable
    slug: string, required, unique
    content: text, required, searchable

    // Relationships
    author_id: ref(User), required
    category_id: ref(Category), optional

    // Tags (stored as JSON array)
    tags: list(string), optional

    // Publishing
    status: enum(draft, pending_review, published, archived), default(draft)
    published_at: timestamp, optional

    created_at: timestamp, auto
    updated_at: timestamp, auto_update

    index: [author_id, status]
    index: [slug]
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Schema evolution localized to entity definitions - Adding fields doesn’t require endpoint modifications - Index changes independent of business logic</p>
</section>
<section id="data-schema-concern-document" class="level4" data-number="3.2.3">
<h4 data-number="3.2.3" class="anchored" data-anchor-id="data-schema-concern-document"><span class="header-section-number">3.2.3</span> 2.2.3 Data Schema Concern (Document)</h4>
<p><strong>Change Driver</strong>: “How document-oriented data is structured”</p>
<p><strong>Variation Point</strong>: <code>database mongodb { collection { } }</code> blocks</p>
<pre class="cai"><code>database mongodb {
    collection Product {
        description: "E-commerce products with variants"

        _id: objectid, primary, auto
        sku: string, required, unique
        name: string, required

        // Embedded document for attributes
        attributes: embedded {
            color: string, optional
            size: string, optional
            dimensions: embedded {
                length: double, optional
                width: double, optional
                height: double, optional
            }
        }

        categories: array(string), optional

        indexes {
            index: [sku] unique
            index: [name, description] text
        }
    }
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - MongoDB schemas separated from relational schemas - Embedded document structures vary independently - Geospatial and text indexes localized to collections</p>
</section>
<section id="api-surface-concern" class="level4" data-number="3.2.4">
<h4 data-number="3.2.4" class="anchored" data-anchor-id="api-surface-concern"><span class="header-section-number">3.2.4</span> 2.2.4 API Surface Concern</h4>
<p><strong>Change Driver</strong>: “What HTTP endpoints are exposed and how they behave”</p>
<p><strong>Variation Point</strong>: <code>endpoint { }</code> blocks</p>
<pre class="cai"><code>// Create post (author/editor/admin)
endpoint POST /posts {
    description: "Create a new post"
    auth: required
    roles: [author, editor, admin]

    body {
        title: string, required
        slug: string, required
        content: text, required
        category_id: uuid, optional
        tags: list(string), optional
        status: string, optional
    }

    returns: Post
    on_success: emit(PostCreated)
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Endpoint definitions independent of entity schemas - Authentication requirements vary per-endpoint - Request/response contracts localized - Role-based access control declarative and isolated</p>
</section>
<section id="event-driven-messaging-concern" class="level4" data-number="3.2.5">
<h4 data-number="3.2.5" class="anchored" data-anchor-id="event-driven-messaging-concern"><span class="header-section-number">3.2.5</span> 2.2.5 Event-Driven Messaging Concern</h4>
<p><strong>Change Driver</strong>: “What events are published and their payloads”</p>
<p><strong>Variation Point</strong>: <code>event { }</code> blocks</p>
<pre class="cai"><code>event PostPublished {
    description: "Post published"
    payload {
        post_id: uuid
        title: string
        slug: string
        published_at: timestamp
    }
    publish_to: [webhook("post-updates"), kafka("posts")]
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Event contracts vary independently of endpoints that emit them - Payload structure changes don’t affect entity definitions - Publishing destinations (Kafka, webhooks) configurable per-event</p>
</section>
<section id="external-integration-concern" class="level4" data-number="3.2.6">
<h4 data-number="3.2.6" class="anchored" data-anchor-id="external-integration-concern"><span class="header-section-number">3.2.6</span> 2.2.6 External Integration Concern</h4>
<p><strong>Change Driver</strong>: “How external services are consumed”</p>
<p><strong>Variation Point</strong>: <code>integration { }</code> blocks</p>
<pre class="cai"><code>integration PaymentGateway {
    description: "Stripe payment processing"
    type: rest
    base_url: env(STRIPE_API_URL)

    auth: bearer(env(STRIPE_SECRET_KEY))

    timeout: 30s
    retry: 3 times with exponential_backoff
    circuit_breaker: {
        threshold: 5 failures in 1m
        reset_after: 30s
    }

    operation create_payment_intent {
        method: POST
        path: "/payment_intents"
        body: {
            amount: integer, required
            currency: string, default("usd")
        }
        returns: {
            id: string
            status: string
            client_secret: string
        }
    }
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Integration definitions isolated from workflows that consume them - Retry and circuit breaker policies vary independently - Switching providers (Stripe → PayPal) requires only integration block changes - Fault tolerance strategies localized</p>
</section>
<section id="business-process-concern" class="level4" data-number="3.2.7">
<h4 data-number="3.2.7" class="anchored" data-anchor-id="business-process-concern"><span class="header-section-number">3.2.7</span> 2.2.7 Business Process Concern</h4>
<p><strong>Change Driver</strong>: “How multi-step business workflows execute”</p>
<p><strong>Variation Point</strong>: <code>workflow { }</code> blocks</p>
<pre class="cai"><code>workflow OrderProcessing {
    description: "Process an order from placement to fulfillment"
    trigger: OrderPlaced

    steps {
        // Step 1: Validate order
        validate_order {
            for_each: trigger.order.items
            check: item.product.available_quantity &gt;= item.quantity
            on_fail: cancel_order("Insufficient inventory")
        }

        // Step 2: Reserve inventory (with compensation)
        reserve_inventory {
            for_each: trigger.order.items
            action: reserve_product_inventory(item.product_id, item.quantity)
            timeout: 30s
            retry: 3 times with exponential_backoff
            on_fail: rollback
        }

        // Step 3: Process payment (with compensation)
        process_payment {
            call: PaymentGateway.create_payment_intent {
                amount: trigger.order.total * 100
            }
            timeout: 30s
            on_fail: rollback
        }

        confirm_order {
            action: update(trigger.order.status = "confirmed")
        }
    }

    on_complete: emit(OrderConfirmed)
    on_fail: emit(OrderFailed)
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Workflow orchestration logic separated from entity definitions - Saga pattern with compensation localized to workflow - Adding/removing steps doesn’t affect endpoints or integrations - Error handling and retry strategies per-step</p>
</section>
<section id="scheduled-task-concern" class="level4" data-number="3.2.8">
<h4 data-number="3.2.8" class="anchored" data-anchor-id="scheduled-task-concern"><span class="header-section-number">3.2.8</span> 2.2.8 Scheduled Task Concern</h4>
<p><strong>Change Driver</strong>: “When and how background jobs execute”</p>
<p><strong>Variation Point</strong>: <code>job { }</code> blocks</p>
<pre class="cai"><code>job DailySalesReport {
    description: "Generate daily sales report"
    schedule: "0 6 * * *"                 // Every day at 6:00 AM
    timezone: "America/New_York"

    queue: default
    timeout: 30m
    retry: 3 times

    steps {
        fetch_sales {
            query: select Order
                where status = "completed"
                and created_at &gt;= yesterday_start()
            as: orders
        }

        generate_report {
            template: "daily_sales_report"
            data: { orders: orders }
            format: pdf
            as: report_file
        }

        distribute {
            send: email(config.reports.recipients) {
                template: "daily_report_email"
                attachment: report_file
            }
        }
    }

    on_complete: emit(ReportGenerated)
}</code></pre>
<p><strong>IVP Assessment</strong>: ✅ <strong>Compliant</strong> - Job scheduling (cron expressions) varies independently of business logic - Changing report frequency doesn’t affect entity schemas - Queue priorities and timeouts localized to job definitions - Retry strategies per-job</p>
<hr>
</section>
</section>
</section>
<section id="variation-scenario-testing" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="variation-scenario-testing"><span class="header-section-number">4</span> 3. Variation Scenario Testing</h2>
<p>To validate IVP compliance, we test hypothetical change scenarios across each concern.</p>
<section id="scenario-change-payment-provider" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="scenario-change-payment-provider"><span class="header-section-number">4.1</span> 3.1 Scenario: Change Payment Provider</h3>
<p><strong>Change Driver</strong>: External payment integration (Stripe → PayPal)</p>
<p><strong>Required Changes</strong>: - Modify <code>integration PaymentGateway</code> block only - Update operation definitions for PayPal API - Change authentication from <code>bearer</code> to <code>api_key</code></p>
<p><strong>Unaffected Components</strong>: - ✅ Entity definitions (Order, Payment remain unchanged) - ✅ Endpoint definitions (checkout endpoint unchanged) - ✅ Workflow logic (OrderProcessing calls remain syntactically identical) - ✅ Event definitions (OrderConfirmed payload unchanged)</p>
<p><strong>IVP Verdict</strong>: ✅ <strong>Independent variation achieved</strong>. The “payment provider integration” concern varies in exactly one place.</p>
</section>
<section id="scenario-add-gift-message-to-orders" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="scenario-add-gift-message-to-orders"><span class="header-section-number">4.2</span> 3.2 Scenario: Add Gift Message to Orders</h3>
<p><strong>Change Driver</strong>: Order entity schema evolution</p>
<p><strong>Required Changes</strong>: - Add <code>gift_message: string, optional</code> to <code>entity Order</code></p>
<p><strong>Unaffected Components</strong>: - ✅ Configuration (database settings unchanged) - ✅ Endpoints (automatically handle new optional field) - ✅ Workflows (OrderProcessing logic unchanged) - ✅ Integrations (payment gateway unaffected)</p>
<p><strong>IVP Verdict</strong>: ✅ <strong>Independent variation achieved</strong>. The “order data structure” concern varies in exactly one place.</p>
</section>
<section id="scenario-change-report-schedule" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="scenario-change-report-schedule"><span class="header-section-number">4.3</span> 3.3 Scenario: Change Report Schedule</h3>
<p><strong>Change Driver</strong>: Scheduled job timing (6am → 7am)</p>
<p><strong>Required Changes</strong>: - Modify <code>schedule: "0 6 * * *"</code> to <code>schedule: "0 7 * * *"</code> in <code>job DailySalesReport</code></p>
<p><strong>Unaffected Components</strong>: - ✅ Entity definitions (Report entity unchanged) - ✅ Endpoints (report listing unchanged) - ✅ Workflows (unrelated to scheduling) - ✅ Job business logic (report generation steps unchanged)</p>
<p><strong>IVP Verdict</strong>: ✅ <strong>Independent variation achieved</strong>. The “when jobs run” concern varies in exactly one place.</p>
</section>
<section id="scenario-add-fraud-detection-to-order-processing" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="scenario-add-fraud-detection-to-order-processing"><span class="header-section-number">4.4</span> 3.4 Scenario: Add Fraud Detection to Order Processing</h3>
<p><strong>Change Driver</strong>: Business workflow logic enhancement</p>
<p><strong>Required Changes</strong>: - Add new step to <code>workflow OrderProcessing</code>: <code>cai   check_fraud {       call: FraudDetectionService.analyze {           order_id: trigger.order.id           amount: trigger.order.total       }       on_fail: cancel_order("Fraud detected")   }</code></p>
<p><strong>Unaffected Components</strong>: - ✅ Entity definitions (Order entity unchanged) - ✅ Endpoints (checkout endpoint unchanged) - ✅ Integrations (PaymentGateway unchanged, new FraudDetectionService separate) - ✅ Events (OrderPlaced unchanged, workflow internal)</p>
<p><strong>IVP Verdict</strong>: ✅ <strong>Independent variation achieved</strong>. The “order processing logic” concern varies in exactly one place.</p>
</section>
<section id="scenario-change-authentication-from-jwt-to-oauth2" class="level3" data-number="4.5">
<h3 data-number="4.5" class="anchored" data-anchor-id="scenario-change-authentication-from-jwt-to-oauth2"><span class="header-section-number">4.5</span> 3.5 Scenario: Change Authentication from JWT to OAuth2</h3>
<p><strong>Change Driver</strong>: Authentication mechanism</p>
<p><strong>Required Changes</strong>: - Modify <code>config { auth: { } }</code> block - Update from <code>jwt</code> to <code>oauth2</code> configuration</p>
<p><strong>Unaffected Components</strong>: - ✅ Entity definitions (unchanged) - ✅ Endpoint definitions (auth policies declarative, runtime handles) - ✅ Workflows (authentication orthogonal) - ⚠️ Runtime implementation must support OAuth2 (implementation concern, not DSL concern)</p>
<p><strong>IVP Verdict</strong>: ✅ <strong>Mostly independent variation</strong>. Configuration change localized; endpoint <code>auth: required</code> declarations remain valid.</p>
<hr>
</section>
</section>
<section id="comparison-mixed-concern-frameworks" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="comparison-mixed-concern-frameworks"><span class="header-section-number">5</span> 4. Comparison: Mixed-Concern Frameworks</h2>
<p>To contextualize CodeAI’s IVP compliance, compare with traditional frameworks that entangle concerns.</p>
<section id="rails-model-mixed-concerns" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="rails-model-mixed-concerns"><span class="header-section-number">5.1</span> 4.1 Rails Model (Mixed Concerns)</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode ruby code-with-copy"><code class="sourceCode ruby"><span id="cb9-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Order</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">ApplicationRecord</span></span>
<span id="cb9-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># CONCERN 1: Schema/Relationships</span></span>
<span id="cb9-3">  belongs_to <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:customer</span></span>
<span id="cb9-4">  has_many <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:order_items</span></span>
<span id="cb9-5"></span>
<span id="cb9-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># CONCERN 2: Validation</span></span>
<span id="cb9-7">  validates <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:total</span>, <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">presence:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">true</span>, <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">numericality:</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">greater_than:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-8"></span>
<span id="cb9-9">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># CONCERN 3: Business Logic</span></span>
<span id="cb9-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> process!</span>
<span id="cb9-11">    reserve_inventory</span>
<span id="cb9-12">    charge_payment</span>
<span id="cb9-13">    send_confirmation</span>
<span id="cb9-14">    <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">self</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">.status</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'confirmed'</span></span>
<span id="cb9-15">    save!</span>
<span id="cb9-16">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span>
<span id="cb9-17"></span>
<span id="cb9-18">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># CONCERN 4: Queries</span></span>
<span id="cb9-19">  scope <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:pending</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> where(<span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">status:</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'pending'</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-20">  scope <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:completed</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> where(<span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">status:</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'completed'</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-21"></span>
<span id="cb9-22">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># CONCERN 5: Callbacks</span></span>
<span id="cb9-23">  after_create <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:send_order_placed_event</span></span>
<span id="cb9-24">  before_destroy <span class="wa" style="color: #5E5E5E;
background-color: null;
font-style: italic;">:refund_payment</span></span>
<span id="cb9-25"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">end</span></span></code></pre></div></div>
<p><strong>IVP Violations</strong>: - ❌ Schema and business logic in same file - ❌ Changing workflow requires touching model - ❌ Query scopes mixed with validation rules - ❌ Callbacks entangle lifecycle with business events</p>
</section>
<section id="codeai-equivalent-separated-concerns" class="level3" data-number="5.2">
<h3 data-number="5.2" class="anchored" data-anchor-id="codeai-equivalent-separated-concerns"><span class="header-section-number">5.2</span> 4.2 CodeAI Equivalent (Separated Concerns)</h3>
<pre class="cai"><code>// CONCERN 1: Schema (entity Order { })
entity Order {
    id: uuid, primary, auto
    customer_id: ref(Customer), required
    total: decimal(10,2), required
    status: enum(pending, confirmed, ...), default(pending)
}

// CONCERN 2: Validation (embedded in endpoint)
endpoint POST /orders {
    body {
        total: decimal, required, min(0.01)
    }
}

// CONCERN 3: Business Logic (workflow OrderProcessing { })
workflow OrderProcessing {
    steps {
        reserve_inventory { ... }
        charge_payment { ... }
        send_confirmation { ... }
        confirm_order { ... }
    }
}

// CONCERN 4: Queries (used in endpoints/workflows where needed)
endpoint GET /orders {
    query {
        status: string, optional
    }
}

// CONCERN 5: Events (event OrderPlaced { })
event OrderPlaced {
    payload { order_id: uuid, ... }
}</code></pre>
<p><strong>IVP Advantages</strong>: - ✅ Changing workflow doesn’t touch entity - ✅ Schema evolution independent of validation - ✅ Event contracts separated from business logic - ✅ Each concern has single, clear variation point</p>
<hr>
</section>
</section>
<section id="language-design-patterns-supporting-ivp" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="language-design-patterns-supporting-ivp"><span class="header-section-number">6</span> 5. Language Design Patterns Supporting IVP</h2>
<section id="mandatory-structural-boundaries" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="mandatory-structural-boundaries"><span class="header-section-number">6.1</span> 5.1 Mandatory Structural Boundaries</h3>
<p>CodeAI <strong>enforces</strong> separation through syntax:</p>
<pre class="cai"><code>// ✅ Valid: Endpoint references entity
endpoint GET /users/{id} {
    returns: User
}

// ❌ Invalid: Cannot define entity inside endpoint
endpoint GET /users/{id} {
    entity User { ... }  // Syntax error
}

// ❌ Invalid: Cannot embed workflow in integration
integration API {
    workflow Process { ... }  // Syntax error
}</code></pre>
<p><strong>IVP Benefit</strong>: Language prevents accidental concern entanglement at parse time.</p>
</section>
<section id="declarative-reference-semantics" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="declarative-reference-semantics"><span class="header-section-number">6.2</span> 5.2 Declarative Reference Semantics</h3>
<p>Concerns reference each other declaratively without embedding:</p>
<pre class="cai"><code>// Endpoint references entity (doesn't embed it)
endpoint POST /posts {
    returns: Post
}

// Workflow calls integration (doesn't define it)
workflow OrderProcessing {
    process_payment {
        call: PaymentGateway.create_payment_intent { ... }
    }
}

// Event references entity (doesn't own it)
event PostCreated {
    payload {
        post_id: uuid  // References Post.id
    }
}</code></pre>
<p><strong>IVP Benefit</strong>: References create coupling at usage sites, but definitions remain independently variable.</p>
</section>
<section id="single-responsibility-per-block" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="single-responsibility-per-block"><span class="header-section-number">6.3</span> 5.3 Single Responsibility per Block</h3>
<p>Each top-level block has exactly one responsibility:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 24%">
<col style="width: 32%">
<col style="width: 42%">
</colgroup>
<thead>
<tr class="header">
<th>Block Type</th>
<th>Responsibility</th>
<th>Not Responsible For</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>entity</code></td>
<td>Schema definition</td>
<td>API exposure, business logic, scheduling</td>
</tr>
<tr class="even">
<td><code>endpoint</code></td>
<td>API contract</td>
<td>Data storage, workflow orchestration, events</td>
</tr>
<tr class="odd">
<td><code>workflow</code></td>
<td>Process orchestration</td>
<td>Schema definition, API routing, scheduling</td>
</tr>
<tr class="even">
<td><code>job</code></td>
<td>Temporal scheduling</td>
<td>Schema, endpoints, immediate workflows</td>
</tr>
<tr class="odd">
<td><code>integration</code></td>
<td>External service client</td>
<td>Internal entities, workflows, events</td>
</tr>
<tr class="even">
<td><code>event</code></td>
<td>Message contract</td>
<td>Publishers, subscribers, data storage</td>
</tr>
<tr class="odd">
<td><code>config</code></td>
<td>Infrastructure settings</td>
<td>Business logic, schema, API surface</td>
</tr>
</tbody>
</table>
<p><strong>IVP Benefit</strong>: Each block varies for exactly one reason.</p>
</section>
<section id="compositional-rather-than-hierarchical" class="level3" data-number="6.4">
<h3 data-number="6.4" class="anchored" data-anchor-id="compositional-rather-than-hierarchical"><span class="header-section-number">6.4</span> 5.4 Compositional Rather Than Hierarchical</h3>
<p>Blocks compose through references, not containment:</p>
<pre class="cai"><code>// Composition: workflow uses integration + entity + event
workflow OrderProcessing {
    trigger: OrderPlaced             // Composes with event

    process_payment {
        call: PaymentGateway.create  // Composes with integration
    }

    confirm_order {
        action: update(order.status)  // Composes with entity
    }
}

// Each composed concern varies independently</code></pre>
<p><strong>IVP Benefit</strong>: Composition maintains independence; hierarchy would create cascading changes.</p>
<hr>
</section>
</section>
<section id="potential-ivp-concerns" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="potential-ivp-concerns"><span class="header-section-number">7</span> 6. Potential IVP Concerns</h2>
<section id="cross-cutting-retry-logic" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="cross-cutting-retry-logic"><span class="header-section-number">7.1</span> 6.1 Cross-Cutting Retry Logic</h3>
<p><strong>Observation</strong>: Retry strategies appear in multiple constructs:</p>
<pre class="cai"><code>// In integration
integration API {
    retry: 3 times with exponential_backoff
}

// In workflow step
workflow Process {
    steps {
        call_api {
            retry: 5 times
        }
    }
}

// In job
job Task {
    retry: 2 times
}</code></pre>
<p><strong>Analysis</strong>: This is <strong>not</strong> an IVP violation. Each retry concern is distinct: - Integration retries = “How external service calls recover from transient failures” - Workflow step retries = “How individual workflow steps recover” - Job retries = “How entire job executions recover”</p>
<p>These are different change drivers at different architectural layers.</p>
<p><strong>Verdict</strong>: ✅ Acceptable repetition of a <em>pattern</em>, not repetition of a <em>concern</em>.</p>
</section>
<section id="validation-in-multiple-places" class="level3" data-number="7.2">
<h3 data-number="7.2" class="anchored" data-anchor-id="validation-in-multiple-places"><span class="header-section-number">7.2</span> 6.2 Validation in Multiple Places</h3>
<p><strong>Observation</strong>: Validation logic appears in: - Entity field constraints: <code>title: string, required</code> - Endpoint body validation: <code>body { title: string, required }</code></p>
<p><strong>Analysis</strong>: These are <strong>different concerns</strong>: - Entity constraints = “What the database schema enforces” - Endpoint validation = “What the API contract requires”</p>
<p>Valid API input might still violate database constraints (e.g., optional in API, required in DB for existing records).</p>
<p><strong>Verdict</strong>: ✅ Not an IVP violation; distinct validation layers with different purposes.</p>
</section>
<section id="data-structure-duplication" class="level3" data-number="7.3">
<h3 data-number="7.3" class="anchored" data-anchor-id="data-structure-duplication"><span class="header-section-number">7.3</span> 6.3 Data Structure Duplication</h3>
<p><strong>Observation</strong>: Event payloads sometimes mirror entity fields:</p>
<pre class="cai"><code>entity Post {
    id: uuid
    title: string
    slug: string
}

event PostPublished {
    payload {
        post_id: uuid
        title: string
        slug: string
    }
}</code></pre>
<p><strong>Analysis</strong>: These are <strong>different concerns</strong>: - Entity = “Persistent storage structure” - Event = “Message contract for external consumers”</p>
<p>They may evolve independently (e.g., entity adds internal fields not exposed in events).</p>
<p><strong>Verdict</strong>: ✅ Not an IVP violation; events intentionally denormalize for stable contracts.</p>
<hr>
</section>
</section>
<section id="conclusion" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="conclusion"><span class="header-section-number">8</span> 7. Conclusion</h2>
<section id="overall-ivp-compliance-rating" class="level3" data-number="8.1">
<h3 data-number="8.1" class="anchored" data-anchor-id="overall-ivp-compliance-rating"><span class="header-section-number">8.1</span> 7.1 Overall IVP Compliance Rating</h3>
<p><strong>Grade: A (Excellent IVP Compliance)</strong></p>
<p>CodeAI demonstrates strong adherence to the Independent Variation Principle across all evaluated dimensions:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 37%">
<col style="width: 27%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Criterion</th>
<th>Rating</th>
<th>Evidence</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Concern Identification</td>
<td>✅ Excellent</td>
<td>Seven distinct syntactic domains clearly identified</td>
</tr>
<tr class="even">
<td>Localization</td>
<td>✅ Excellent</td>
<td>Each concern has single, well-defined variation point</td>
</tr>
<tr class="odd">
<td>Independence</td>
<td>✅ Excellent</td>
<td>Variation scenarios confirm independent mutability</td>
</tr>
<tr class="even">
<td>Non-Repetition</td>
<td>✅ Excellent</td>
<td>Concerns expressed exactly once; apparent repetition is pattern reuse</td>
</tr>
<tr class="odd">
<td>Enforcement</td>
<td>✅ Excellent</td>
<td>Language syntax prevents concern entanglement</td>
</tr>
</tbody>
</table>
</section>
<section id="key-strengths" class="level3" data-number="8.2">
<h3 data-number="8.2" class="anchored" data-anchor-id="key-strengths"><span class="header-section-number">8.2</span> 7.2 Key Strengths</h3>
<ol type="1">
<li><strong>Syntactic Enforcement</strong>: Language design prevents accidental concern mixing through parse-time validation</li>
<li><strong>Declarative Composition</strong>: Blocks reference rather than embed each other, maintaining independence</li>
<li><strong>Domain Alignment</strong>: Constructs map naturally to architectural concerns in backend systems</li>
<li><strong>Scalability</strong>: Seven distinct variation points allow systems to grow along multiple independent axes</li>
</ol>
</section>
<section id="architectural-implications" class="level3" data-number="8.3">
<h3 data-number="8.3" class="anchored" data-anchor-id="architectural-implications"><span class="header-section-number">8.3</span> 7.3 Architectural Implications</h3>
<p><strong>For Maintainability</strong>: - Changes localize predictably to single files/blocks - Reduced cognitive load: developers work within single concern at a time - Lower regression risk: isolated changes reduce cascading failures</p>
<p><strong>For Team Scalability</strong>: - Different developers can own different concerns (schema team, API team, workflow team) - Parallel development enabled by independence - Clear boundaries reduce merge conflicts</p>
<p><strong>For Evolution</strong>: - Concerns can evolve at different rates without coordination - Technology substitution simplified (swap Redis for Memcached in config only) - Feature additions don’t require refactoring existing concerns</p>
</section>
<section id="comparison-to-original-claim" class="level3" data-number="8.4">
<h3 data-number="8.4" class="anchored" data-anchor-id="comparison-to-original-claim"><span class="header-section-number">8.4</span> 7.4 Comparison to Original Claim</h3>
<p><strong>Original Claim</strong> (Barış Gömeç): “Simpler declarative syntax maps more directly to semantic meaning — making it easier for LLMs to generate accurate, production-ready code.”</p>
<p><strong>IVP Finding</strong>: The same properties that benefit LLMs (clear semantic boundaries, declarative structure, single-purpose constructs) <strong>also benefit human maintainability</strong> through IVP compliance.</p>
<p><strong>Synthesis</strong>: CodeAI is optimized for both: 1. <strong>LLM code generation</strong> (clear semantic mapping) 2. <strong>Human code maintenance</strong> (independent variation of concerns)</p>
<p>These are not competing goals—they emerge from the same underlying principle: <strong>semantic clarity through concern separation</strong>.</p>
</section>
<section id="recommendations" class="level3" data-number="8.5">
<h3 data-number="8.5" class="anchored" data-anchor-id="recommendations"><span class="header-section-number">8.5</span> 7.5 Recommendations</h3>
<p><strong>For Language Evolution</strong>: 1. <strong>Maintain syntactic boundaries</strong>: Resist temptation to add “convenience features” that mix concerns 2. <strong>Document concern mapping</strong>: Explicitly state which construct handles which change driver 3. <strong>Add linting</strong>: Enforce IVP at tooling level (e.g., warn if workflow embeds schema logic)</p>
<p><strong>For Users</strong>: 1. <strong>Respect boundaries</strong>: Don’t work around constructs; use them as designed 2. <strong>One concern per file</strong>: Consider organizing large systems with one entity/endpoint/workflow per file 3. <strong>Reference, don’t duplicate</strong>: Use composition over copy-paste</p>
<p><strong>For Researchers</strong>: 1. <strong>Empirical study</strong>: Measure maintenance velocity in CodeAI vs.&nbsp;traditional frameworks 2. <strong>Cognitive load</strong>: Study developer comprehension with separated vs.&nbsp;entangled concerns 3. <strong>LLM performance</strong>: Compare accuracy of LLM-generated CodeAI vs.&nbsp;traditional code</p>
<hr>
</section>
</section>
<section id="references" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="references"><span class="header-section-number">9</span> 8. References</h2>
<section id="primary-sources" class="level3" data-number="9.1">
<h3 data-number="9.1" class="anchored" data-anchor-id="primary-sources"><span class="header-section-number">9.1</span> 8.1 Primary Sources</h3>
<ul>
<li><strong>CodeAI GitHub Repository</strong>: https://github.com/bargom/codeai
<ul>
<li><code>examples/02-blog-api/blog-api.cai</code></li>
<li><code>examples/03-ecommerce/ecommerce.cai</code></li>
<li><code>examples/05-scheduled-jobs/scheduled-jobs.cai</code></li>
<li><code>examples/06-mongodb-collections/mongodb-collections.cai</code></li>
</ul></li>
<li><strong>Original LinkedIn Post</strong>: Barış Gömeç, “I asked AI to design a programming language…”</li>
<li><strong>CodeAI Website</strong>: https://cai-lang.dev</li>
</ul>
</section>
<section id="ivp-background" class="level3" data-number="9.2">
<h3 data-number="9.2" class="anchored" data-anchor-id="ivp-background"><span class="header-section-number">9.2</span> 8.2 IVP Background</h3>
<ul>
<li><strong>Loth, Y. (2025)</strong>. “The Independent Variation Principle: A Unifying Framework for Software Design.” <em>Zenodo</em>. https://doi.org/10.5281/zenodo.17677315
<ul>
<li><strong>Formal definition of IVP</strong>: “Separate elements with different change driver assignments into distinct units; unify elements with the same change driver assignment within a single unit.”</li>
<li>Provides mathematical formalization of change drivers, change driver assignments, and architectural quality metrics</li>
</ul></li>
<li>Dijkstra, E. W. (1982). “On the role of scientific thought.” <em>Selected Writings on Computing: A Personal Perspective</em>.</li>
<li>Martin, R. C. (2003). <em>Agile Software Development: Principles, Patterns, and Practices</em> (Single Responsibility Principle)</li>
<li>Parnas, D. L. (1972). “On the Criteria To Be Used in Decomposing Systems into Modules.” <em>Communications of the ACM</em>.</li>
</ul>
</section>
<section id="related-principles" class="level3" data-number="9.3">
<h3 data-number="9.3" class="anchored" data-anchor-id="related-principles"><span class="header-section-number">9.3</span> 8.3 Related Principles</h3>
<ul>
<li><strong>SOLID Principles</strong>: SRP, OCP, LSP, ISP, DIP (Robert C. Martin)</li>
<li><strong>Separation of Concerns</strong> (SoC): Dijkstra, Parnas</li>
<li><strong>Don’t Repeat Yourself</strong> (DRY): Hunt &amp; Thomas, <em>The Pragmatic Programmer</em></li>
<li><strong>Single Source of Truth</strong> (SSOT): Database design, data management</li>
</ul>
<hr>
</section>
</section>
<section id="appendix-formal-ivp-evaluation-matrix" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="appendix-formal-ivp-evaluation-matrix"><span class="header-section-number">10</span> 9. Appendix: Formal IVP Evaluation Matrix</h2>
<table class="caption-top table">
<colgroup>
<col style="width: 10%">
<col style="width: 13%">
<col style="width: 20%">
<col style="width: 20%">
<col style="width: 23%">
<col style="width: 10%">
</colgroup>
<thead>
<tr class="header">
<th>Concern</th>
<th>Construct</th>
<th>Change Examples</th>
<th>Isolation Score</th>
<th>Independence Score</th>
<th>Overall</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Infrastructure Config</td>
<td><code>config { }</code></td>
<td>DB pool size, cache TTL, JWT expiry</td>
<td>5/5</td>
<td>5/5</td>
<td>✅ Excellent</td>
</tr>
<tr class="even">
<td>Relational Schema</td>
<td><code>entity { }</code></td>
<td>Add fields, change indexes, alter types</td>
<td>5/5</td>
<td>5/5</td>
<td>✅ Excellent</td>
</tr>
<tr class="odd">
<td>Document Schema</td>
<td><code>collection { }</code></td>
<td>Embedded docs, arrays, geospatial</td>
<td>5/5</td>
<td>5/5</td>
<td>✅ Excellent</td>
</tr>
<tr class="even">
<td>API Surface</td>
<td><code>endpoint { }</code></td>
<td>Add parameters, change auth, modify responses</td>
<td>5/5</td>
<td>4/5</td>
<td>✅ Very Good*</td>
</tr>
<tr class="odd">
<td>Event Contracts</td>
<td><code>event { }</code></td>
<td>Modify payloads, change publishers</td>
<td>5/5</td>
<td>5/5</td>
<td>✅ Excellent</td>
</tr>
<tr class="even">
<td>External Integration</td>
<td><code>integration { }</code></td>
<td>Change providers, update retries, modify circuit breakers</td>
<td>5/5</td>
<td>4/5</td>
<td>✅ Very Good**</td>
</tr>
<tr class="odd">
<td>Business Workflows</td>
<td><code>workflow { }</code></td>
<td>Add steps, modify saga logic, change timeouts</td>
<td>5/5</td>
<td>4/5</td>
<td>✅ Very Good***</td>
</tr>
<tr class="even">
<td>Scheduled Jobs</td>
<td><code>job { }</code></td>
<td>Change cron schedule, update queue, modify retries</td>
<td>5/5</td>
<td>5/5</td>
<td>✅ Excellent</td>
</tr>
</tbody>
</table>
<p><strong>Legend</strong>: - Isolation Score: How well the concern is localized (5 = single file/block) - Independence Score: How independently it can vary (5 = zero coupling to other concerns)</p>
<p><strong>Notes</strong>: - * Endpoints reference entities in <code>returns:</code> clauses (unavoidable semantic coupling) - ** Integrations are called from workflows (usage coupling, not definition coupling) - *** Workflows compose entities, integrations, events (orchestration requires references)</p>
<hr>


</section>

 ]]></description>
  <category>ivp</category>
  <category>ai</category>
  <category>architecture</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-01-13-ivp-compliance-review-codeai-an-ai-designed-language-evaluated-against-the-independent-variation-4ca9.html</guid>
  <pubDate>Tue, 13 Jan 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Tailwind CSS Through the Lens of the Independent Variation Principle</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-01-10-tailwind-css-through-the-lens-of-the-independent-variation-principle-1pke.html</link>
  <description><![CDATA[ 





<p>With all that’s going on around Tailwind at the moment, I thought that it would be interesting to analyze what IVP says about Tailwind CSS.</p>
<section id="the-coupling-critique-misidentifies-the-problem" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-coupling-critique-misidentifies-the-problem"><span class="header-section-number">1</span> The Coupling Critique Misidentifies the Problem</h2>
<p>“Tailwind couples appearance to structure.” This critique surfaces in every Tailwind discussion. The argument seems intuitive: by placing <code>bg-blue-500 p-4 flex items-center</code> directly in HTML, we’re violating the sacred separation of concerns—mixing what something <em>is</em> with how it <em>looks</em>.</p>
<p>But what if this intuition is wrong? What if Tailwind actually <em>improves</em> architectural quality by a measure more rigorous than “feels clean”?</p>
<p>The <strong>Independent Variation Principle</strong> (IVP) offers exactly such a measure. IVP’s structural formulation has four directives: every element has at least one change driver; each element is assigned every change driver whose knowledge it embodies; elements with different change driver assignments belong in distinct units; elements with the same change driver assignment belong in a single unit. Quality isn’t about file types—it’s about <strong>change drivers</strong>.</p>
</section>
<section id="change-drivers-as-the-unit-of-architectural-concern" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="change-drivers-as-the-unit-of-architectural-concern"><span class="header-section-number">2</span> Change Drivers as the Unit of Architectural Concern</h2>
<p>A change driver represents an independently varying source of change to domain knowledge. Think about where change actually originates: business rules change because stakeholders request new features; UI layouts change because designers iterate; database schemas change because data requirements evolve. These are fundamentally different reasons for modification, and they often involve different people.</p>
<p>Here’s where IVP becomes useful: group code by who decides how and why it changes, not by what it is. When a stakeholder says “make the Buy button more prominent,” that’s a single change driver. Now imagine an architecture where fulfilling that request requires modifying both an HTML file <em>and</em> a CSS file. You’ve just scattered knowledge about “the Buy button” across two locations. The architecture forces you to synchronize changes manually—a cognitive burden that could have been avoided.</p>
</section>
<section id="semantic-css-architectures-create-transitive-dependencies" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="semantic-css-architectures-create-transitive-dependencies"><span class="header-section-number">3</span> Semantic CSS Architectures Create Transitive Dependencies</h2>
<p>Consider BEM (Block Element Modifier) or other “semantic” CSS approaches:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb1-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">button</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"btn btn--primary btn--large"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>Buy Now<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">button</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode css code-with-copy"><code class="sourceCode css"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.btn</span> { <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* base styles */</span> }</span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.btn--primary</span> { <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">background</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">blue</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">color</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">white</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb2-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.btn--large</span> { <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">padding</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">rem</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">rem</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span></code></pre></div></div>
<p>This looks clean—HTML declares <em>what</em>, CSS declares <em>how</em>. But look at what actually changes:</p>
<p>The button’s existence comes from HTML. The button’s appearance comes from CSS. And then there’s the contract between them: the class name <code>.btn--primary</code>. When the designer says “that button needs more padding,” you edit the CSS. Straightforward. But what if you decide to rename the variant or restructure the component? Suddenly you’re touching both files. The class name becomes a <strong>transitive dependency</strong>—HTML depends on it, CSS depends on it. Change one, and you must change the other.</p>
<p>The real problem emerges in deletion. Delete the HTML, and the CSS lingers as orphaned code. Delete the CSS, and the HTML silently breaks. The knowledge of “how this button looks” is split across an artificial boundary, making it impossible to reason about either piece independently.</p>
</section>
<section id="tailwind-unifies-change-drivers-within-components" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="tailwind-unifies-change-drivers-within-components"><span class="header-section-number">4</span> Tailwind Unifies Change Drivers Within Components</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb3-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">button</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"bg-blue-500 text-white px-8 py-4 rounded-lg"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb3-2">  Buy Now</span>
<span id="cb3-3"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">button</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div></div>
<p>The “coupling accusation” sees this as mixing concerns. But ask a different question: when does this code actually change? The visual appearance of <em>this specific button</em> changes when a designer modifies <em>this specific button</em>. All the knowledge required to render this button sits in one place. Delete the component, and the styles vanish—no orphaned CSS. Modify the padding, and no other button in the application is affected.</p>
<p>That’s not coupling. That’s <strong>cohesion</strong>. Tailwind unifies elements that share a single change driver: <em>the visual manifestation of this component</em>.</p>
</section>
<section id="the-cascade-as-implicit-shared-state" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-cascade-as-implicit-shared-state"><span class="header-section-number">5</span> The Cascade as Implicit Shared State</h2>
<p>CSS’s “C” is precisely what IVP warns against. The cascade creates a form of <strong>implicit dependency</strong> that violates independent variation. Consider a simple rule like <code>.card { padding: 1rem; background: white; }</code>. This declaration means every element with class <code>card</code> now varies together. Change the rule once, and every card in your application changes—the product card, the modal card you forgot about, the legacy card nobody maintains, the third-party component you styled to match your brand.</p>
<p>This is <strong>transitive coupling through shared state</strong>. A modification intended for one concern propagates unexpectedly to another. The problem compounds in large codebases where you can’t hold the entire cascade in your head.</p>
<p>Tailwind bypasses this entirely. The utility classes <code>p-4 bg-white</code> on one component have zero effect on another. Each component varies independently. This is what IVP actually demands.</p>
</section>
<section id="design-tokens-reconcile-global-consistency-with-local-variation" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="design-tokens-reconcile-global-consistency-with-local-variation"><span class="header-section-number">6</span> Design Tokens Reconcile Global Consistency with Local Variation</h2>
<p>“If every component hard-codes its colors, how do you change the brand palette?”</p>
<p>This reveals the real architectural boundary. Tailwind’s <code>tailwind.config.js</code> serves as the knowledge partition for design system constants. Rather than hard-coding hex codes, components reference semantic aliases like <code>bg-primary</code>. Change the brand color once in the config, and the change propagates everywhere automatically. Meanwhile, individual components still vary their <em>application</em> of those tokens independently based on feature requirements.</p>
<p>The separation works because different change drivers are at play. Design tokens change when brand or system requirements change. Component styling changes when feature requirements change. The config ensures global consistency without forcing local components to vary together. The utility classes ensure each component can vary independently. Both principles are satisfied—IVP operates correctly at both levels.</p>
</section>
<section id="rethinking-what-html-actually-does" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="rethinking-what-html-actually-does"><span class="header-section-number">7</span> Rethinking What HTML Actually Does</h2>
<p>Here’s where the analysis gets interesting. The traditional separation of concerns doctrine taught us that HTML handles content, CSS handles appearance, and JavaScript handles behavior. This framing makes intuitive sense until you examine where content actually lives in modern web applications. In a typical system, content doesn’t live in HTML. It lives in databases, APIs, content management systems. The HTML file isn’t the authoritative source of content—it’s a rendering template that transforms data for human consumption.</p>
<p>If HTML isn’t organizing content, then what is it actually doing? It’s <strong>presenting data and enabling interaction</strong>. HTML is fundamentally a presentation tool. Its job is to take structured data from elsewhere and manifest it in visual and interactive form for human consumption. Once we accept this reality, coupling HTML to styling stops being a violation. They’re both expressions of the same concern: the <strong>human interface</strong>. A <code>&lt;button&gt;</code> with Tailwind classes isn’t mixing “content” with “appearance”—it’s describing a single unit of user experience.</p>
</section>
<section id="semantic-html-enriches-the-human-interface" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="semantic-html-enriches-the-human-interface"><span class="header-section-number">8</span> Semantic HTML Enriches the Human Interface</h2>
<p>“But what about <code>&lt;article&gt;</code> and <code>&lt;section&gt;</code>? Isn’t semantic HTML for machines?”</p>
<p>No.&nbsp;Semantic HTML is for <strong>humans</strong>, delivered through browser features. Consider what semantic tags actually accomplish: Reader View functionality strips away navigation and ads to present clean content—for human reading. Screen readers convey document structure to users with visual impairments—for human accessibility. The <code>&lt;time&gt;</code> element allows browsers to parse dates and offer “Add to Calendar” functionality—for human convenience. Form inputs with proper semantic attributes enable browser autofill—for human efficiency.</p>
<p>Semantic HTML is metadata that helps browsers provide enhanced capabilities to human users. It’s analogous to ARIA attributes—not a completely separate interface layer, but enrichment delivered through a different channel. Both serve the same consumer: the human using the browser.</p>
<p>A <code>&lt;div&gt;</code> styled with Tailwind and an <code>&lt;article&gt;</code> styled with Tailwind serve the same change driver: the human experience. The semantic tag adds metadata that unlocks browser capabilities; the utility classes define visual appearance. Both are aspects of the presentation layer serving the same user. There’s no violation in placing them together—meaning and appearance are <strong>co-located knowledge</strong> for a unified concern.</p>
</section>
<section id="search-engines-audit-the-human-interface-not-a-separate-one" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="search-engines-audit-the-human-interface-not-a-separate-one"><span class="header-section-number">9</span> Search Engines Audit the Human Interface, Not a Separate One</h2>
<p>“Surely Google’s crawler is a machine consumer that needs semantic HTML?”</p>
<p>This seems like a counterexample—a machine that consumes the presentation layer. But examine what the bot actually evaluates. Google’s crawler measures Core Web Vitals to proxy for perceived load speed and human experience. Mobile-friendliness gets assessed to measure usability on small screens where humans actually browse. Content quality signals get analyzed to predict whether humans will find the content valuable. Accessibility checks ensure the site works for humans with disabilities.</p>
<p>Google’s crawler is fundamentally an <strong>automated auditor of the human interface</strong>. It uses semantic HTML not because the bot needs semantic structure for its own evaluation logic, but because semantic structure correlates with good human experience. The bot isn’t a different consumer—it’s mimicking human usage patterns to evaluate human-centric quality metrics.</p>
<p>There’s ultimately one change driver for the presentation layer: the human user. Google’s approach recognizes this. The bot doesn’t require a separate interface; it audits the same interface humans use, for the purpose of predicting human satisfaction. Any attempt to serve bots differently—through cloaking or dynamic rendering with alternate content—is penalized precisely because Google prioritizes a single source of truth: the interface as humans experience it.</p>
</section>
<section id="the-actual-architectural-boundary-data-versus-presentation" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="the-actual-architectural-boundary-data-versus-presentation"><span class="header-section-number">10</span> The Actual Architectural Boundary: Data versus Presentation</h2>
<p>If there <em>is</em> a meaningful architectural boundary worth defending, it’s not between HTML and CSS. It’s between <strong>data and presentation</strong>.</p>
<p>The Interface Segregation Principle (ISP) states that no client should depend on methods it doesn’t use. When applied to web architecture, this becomes clear: system consumers like mobile apps, integrations, and third-party services need raw data and shouldn’t be forced to parse HTML to extract information. Human consumers using browsers need a rendered interface and shouldn’t have to consume JSON directly. These are genuinely different consumers with fundamentally different needs, and the proper architectural response is to provide <strong>different views over the same data</strong>:</p>
<pre><code>┌─────────────────────────────────────────────────┐
│                 Domain Data                     │
│            (database, business logic)           │
└───────────────────┬─────────────────────────────┘
                    │
        ┌───────────┴───────────┐
        │                       │
        ▼                       ▼
┌───────────────┐         ┌───────────────────────┐
│   JSON API    │         │  HTML + Tailwind      │
│  (systems)    │         │  (humans)             │
└───────────────┘         └───────────────────────┘</code></pre>
<p>The JSON API serves as the interface for system-to-system communication. It contains pure domain knowledge without presentational noise. Mobile apps consume it, analytics services consume it, partner integrations consume it. The HTML + Tailwind view, by contrast, serves as the interface for human consumption. It contains the same domain knowledge, but transformed into visual and interactive form. Semantic tags provide metadata that unlocks browser features; utility classes provide visual styling.</p>
<p>Within the presentation layer, further separation between “structure” and “style” only creates artificial boundaries that scatter knowledge across multiple files. The actual boundary worth defending is between <em>what the data means</em> and <em>how humans interact with it</em>.</p>
</section>
<section id="how-independent-variation-plays-out-in-practice" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="how-independent-variation-plays-out-in-practice"><span class="header-section-number">11</span> How Independent Variation Plays Out in Practice</h2>
<p>Consider a system where you need to display a product catalog:</p>
<p><strong>The Data (JSON API):</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"products"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb5-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Widget"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"price"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">29.99</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"inStock"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb5-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"id"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"name"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Gadget"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"price"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">49.99</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"inStock"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-5">  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb5-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>The Human View (HTML + Tailwind):</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb6-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">article</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grid gap-6"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">div</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"p-4 bg-white rounded-lg shadow"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">h2</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"text-xl font-bold"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>Widget<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">h2</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">p</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"text-gray-600"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>$29.99<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">p</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-5">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">span</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"text-green-600"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>In Stock<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">span</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-6">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">div</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span>
<span id="cb6-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;!-- ... --&gt;</span></span>
<span id="cb6-8"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">article</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div></div>
<p>Each layer operates under different change drivers. The data layer changes when business rules change—when new fields are needed or pricing logic evolves. The presentation layer changes when user experience requirements change—when designers want a different layout or new visual treatment. The React/Vue/Svelte component acts as the <strong>mapping layer</strong> that connects them, pulling data from one interface and projecting it onto the human interface. This mapping is where the two concerns meet, and keeping it small is the architectural goal.</p>
<p>When you want to change how prices display, you modify the presentation layer. When you want to add a new product attribute, you modify the data layer and then decide whether to surface it in the presentation. Each concern varies independently.</p>
</section>
<section id="architectural-patterns-that-follow-from-this-analysis" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="architectural-patterns-that-follow-from-this-analysis"><span class="header-section-number">12</span> Architectural Patterns That Follow from This Analysis</h2>
<p>Treating the component as the unit of change means recognizing that a compon With all that’s going on around Tailwind at the moment, I thought that it would be interesting to analyze what IVP says about Tailwind CSS. ent’s HTML, Tailwind classes, and JavaScript logic all vary together for the same fundamental reason: the component’s requirements changed. This is the proper granularity for architectural reasoning.</p>
<p>Design system constants belong in <code>tailwind.config.js</code>. Colors, spacing scales, and typography change for brand or system reasons, not component reasons. Centralizing them ensures global consistency while components remain locally independent.</p>
<p>Semantic HTML should be chosen based on what browser capabilities it actually unlocks for users—Reader View, accessibility features, form autofill. The semantic tag is presentation metadata, part of the human interface layer, not a separate concern.</p>
<p>Data and presentation must be strictly segregated. Provide a JSON API for system consumers. Don’t force mobile apps to parse HTML or embed business logic in templates. The architectural clarity of this separation is worth the effort.</p>
<p>Dead code elimination becomes trivial with Tailwind. Remove a component, and its styles vanish. In traditional CSS architectures, deletion requires archeological investigation to find and remove orphaned rules. This practical difference reflects deeper architectural alignment.</p>
<p>The visual verbosity of utility classes is actually the <em>manifestation</em> of explicit knowledge. Hidden complexity scattered across distant CSS files isn’t cleaner—it’s just hidden, deferring the cognitive burden rather than eliminating it.</p>
</section>
<section id="conclusion" class="level2" data-number="13">
<h2 data-number="13" class="anchored" data-anchor-id="conclusion"><span class="header-section-number">13</span> Conclusion</h2>
<p>The “separation of concerns” argument against Tailwind rests on a category error. It treats file types (HTML, CSS) as if they were concerns. IVP reveals what the actual concerns are: change drivers. HTML doesn’t organize content in modern applications—it presents data that lives elsewhere. Semantic HTML doesn’t serve machines—it’s metadata that enables browser features for human users. The cascade isn’t an abstraction mechanism—it’s transitive coupling that forces independent variations together.</p>
<p>When appearance and structure share a change driver, unifying them isn’t coupling. It’s cohesion. For UI components, appearance and structure genuinely do share a single change driver: the component’s requirements. Tailwind’s utility-first approach recognizes this, localizing knowledge about each component’s visual manifestation in one place and enabling independent variation across the codebase.</p>
<p>The real architectural boundary is between data (for systems) and presentation (for humans). Within the presentation layer, HTML structure and CSS styling are co-located knowledge serving a single consumer. Tailwind recognizes this reality; traditional CSS architectures pretend otherwise, creating artificial boundaries.</p>
<p>The practical consequences follow naturally: changes stay local rather than propagating unexpectedly, dead code disappears when components are removed, and the cognitive overhead of maintaining synchronized files across multiple locations vanishes. This isn’t because Tailwind is convenient. It’s because Tailwind aligns code structure with actual causal structure.</p>
<hr>
<p><em>The Independent Variation Principle is formally developed in <a href="https://doi.org/10.5281/zenodo.17677315">The Independent Variation Principle - A Unifying Meta-Principle for Software Architecture</a>.</em></p>


</section>

 ]]></description>
  <category>languages</category>
  <category>ivp</category>
  <category>architecture</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-01-10-tailwind-css-through-the-lens-of-the-independent-variation-principle-1pke.html</guid>
  <pubDate>Sat, 10 Jan 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Cohesion Is Not What You Think: A Formal Response to Eberhard Wolff</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2026-01-08-cohesion-is-not-what-you-think-a-formal-response-to-eberhard-wolff-14bn.html</link>
  <description><![CDATA[ 





<p>Eberhard Wolff recently published <a href="https://ewolff.com/2026/01/08/cohesion-modules-hierachies.html">“Cohesion, Modules, and Hierarchies”</a> (<a href="https://web.archive.org/web/20260108222417/https://ewolff.com/2026/01/08/cohesion-modules-hierachies.html">Internet Archive</a>), a post that captures how software architects think about cohesion, coupling, and software design. It also captures why our field struggles with these concepts: we lack rigorous definitions, which leads to contradictory advice and confused reasoning.</p>
<p>I want to be clear: this isn’t a criticism of Wolff personally. He’s articulating the mainstream view accurately—the problem is that the mainstream view has been broken for decades. Wolff is a skilled architect and communicator; he’s just working with the same incomplete conceptual toolkit the rest of us inherited.</p>
<p>I’ve formalized what I call the <strong>Independent Variation Principle (IVP)</strong>, and Wolff’s post is a good case study in what has been going wrong in our industry for more than five decades: we operate on intuition instead of theory.</p>
<p><strong>IVP (Structural Formulation):</strong> <em>Every element has at least one change driver; each element is assigned every change driver whose knowledge it embodies; elements with different change driver assignments belong in distinct units; elements with the same change driver assignment belong in a single unit.</em></p>
<p>Here’s my analysis of Wolff’s post, sentence by sentence.</p>
<hr>
<section id="going-through-wolffs-claims" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="going-through-wolffs-claims"><span class="header-section-number">1</span> Going Through Wolff’s Claims</h2>
<section id="the-cohesion-of-a-module-is-good-when-the-individual-parts-of-the-module-somehow-belong-together." class="level3" data-number="1.1">
<h3 data-number="1.1" class="anchored" data-anchor-id="the-cohesion-of-a-module-is-good-when-the-individual-parts-of-the-module-somehow-belong-together."><span class="header-section-number">1.1</span> “The cohesion of a module is good when the individual parts of the module somehow belong together.”</h3>
<p>This is the core problem. “Somehow belong together” is not a definition—it’s a hand-wave. What does “belong together” mean? By what criterion? Without a precise answer, cohesion becomes whatever the architect intuits it to be.</p>
<p><strong>IVP’s answer:</strong> Elements belong together when they share the same <em>change driver assignments</em>. A change driver is an independently varying source of change to domain knowledge (business rules, infrastructure requirements, UI frameworks, etc.). Typically, a change driver is a team or a person who has the authority to decide that a change must be made to a part of a software system: it’s a matter of “decisional authority”. Two elements belong in the same module if and only if they share the same set of change drivers.</p>
</section>
<section id="wolffs-claim-that-separating-related-functionalities-forces-constant-communication-to-maintain-consistency" class="level3" data-number="1.2">
<h3 data-number="1.2" class="anchored" data-anchor-id="wolffs-claim-that-separating-related-functionalities-forces-constant-communication-to-maintain-consistency"><span class="header-section-number">1.2</span> Wolff’s claim that separating related functionalities forces “constant communication to maintain consistency”</h3>
<p>This observation correctly identifies a symptom but misdiagnoses the cause. The problem isn’t that “related” things were separated—it’s that elements <em>with the same change driver assignments</em> were separated. When you split elements that vary for the same reason, you create artificial coupling because changes must now propagate across module boundaries.</p>
<p>But Wolff treats this as evidence that cohesion and coupling are symmetric concerns. They’re not.</p>
</section>
<section id="the-laptop-example-ordering-reserving-and-delivering-sharing-state" class="level3" data-number="1.3">
<h3 data-number="1.3" class="anchored" data-anchor-id="the-laptop-example-ordering-reserving-and-delivering-sharing-state"><span class="header-section-number">1.3</span> The Laptop Example: ordering, reserving, and delivering sharing state</h3>
<p>Wolff argues these operations “could share a data model in which the state of a product (ordered, reserved, delivered) is stored” and therefore belong together.</p>
<p>This reasoning is backwards. The question isn’t whether they <em>could</em> share a data model—many things <em>could</em> share data. The question is: <strong>do they share the same change driver assignment?</strong></p>
<p>If orders, reservations, and deliveries are governed by the same business rules and change together when those rules change, they share a change driver and belong together. If they’re governed by different policies that evolve independently (order policies vs.&nbsp;delivery logistics vs.&nbsp;inventory management), they have different change drivers and should be separated—even if they reference the same laptop entity.</p>
<p>Sharing data is not the criterion. Sharing <em>variation sources</em> is.</p>
</section>
<section id="when-functionalities-that-share-data-models-are-separated-across-modules-they-must-constantly-communicate-to-maintain-consistency-undermining-both-cohesion-and-loose-coupling." class="level3" data-number="1.4">
<h3 data-number="1.4" class="anchored" data-anchor-id="when-functionalities-that-share-data-models-are-separated-across-modules-they-must-constantly-communicate-to-maintain-consistency-undermining-both-cohesion-and-loose-coupling."><span class="header-section-number">1.4</span> “When functionalities that share data models are separated across modules, they must constantly communicate to maintain consistency, undermining both cohesion and loose coupling.”</h3>
<p>This conflates data sharing with variation dependence. Two modules can share data structures without sharing change drivers—this is precisely what stable abstractions enable. The problem Wolff describes occurs specifically when elements with <em>shared change drivers</em> are separated, not when elements sharing data are separated.</p>
</section>
<section id="treating-cohesion-and-coupling-as-interdependent-concepts-on-equal-footing" class="level3" data-number="1.5">
<h3 data-number="1.5" class="anchored" data-anchor-id="treating-cohesion-and-coupling-as-interdependent-concepts-on-equal-footing"><span class="header-section-number">1.5</span> Treating cohesion and coupling as “interdependent concepts” on equal footing</h3>
<p>This might be his biggest mistake. Wolff presents cohesion and coupling as two symmetric properties that must be balanced. This framing appears throughout software architecture literature, and it’s wrong.</p>
<p><strong>IVP establishes cohesion primacy:</strong> Proper cohesion (aligning module boundaries with change driver assignments) <em>causes</em> minimal coupling as an emergent property. When you correctly group elements that share variation sources, coupling between modules is minimized to what’s causally required by the domain.</p>
<p>Coupling is not an independent variable to optimize. It’s a <em>symptom</em> of cohesion quality. Accidental coupling (coupling beyond what the domain causally requires) shows up as reduced cohesion—specifically, it introduces foreign change drivers into modules, reducing their purity.</p>
<p>Software design is not a tension between cohesion and coupling; it is <em>not</em> a balancing act: IVP shows that software design is a matter of realizing optimal cohesion.</p>
<p>Focus on maximizing cohesion. Low coupling follows.</p>
</section>
<section id="code-duplication-violates-cohesion-but-can-create-loose-coupling" class="level3" data-number="1.6">
<h3 data-number="1.6" class="anchored" data-anchor-id="code-duplication-violates-cohesion-but-can-create-loose-coupling"><span class="header-section-number">1.6</span> “Code duplication violates cohesion but can create loose coupling”</h3>
<p>Wolff writes: “When code is duplicated, the two copies can be evolved independently. For example, if a specific software solution for one customer is to be turned into an industry solution, one can copy the specific solution for each customer and adapt it. This is very easy to implement and enables completely separate development, making customer-specific changes easy.”</p>
<p>He then notes the apparent trade-off: “On the other hand, copying code also means that a separate, specific solution emerges for each customer, making it nearly impossible to implement features for all customers.”</p>
<p>This framing reveals the confusion. Wolff sees a tension: duplication enables loose coupling but “violates cohesion.” Under IVP, there’s no tension—the analysis depends entirely on <em>change driver assignments</em>.</p>
<p>Credit where it’s due: Wolff’s intuition here is correct. Duplicating code for different customers <em>does</em> create loose coupling. He sees the right outcome. The problem is that his definition of cohesion can’t explain <em>why</em> it’s right. Under IVP, the explanation is clear: duplication creates loose coupling <em>because</em> it achieves proper cohesion—when customer-specific code has customer-specific change drivers, separating them is exactly what IVP prescribes. Cohesion primacy at work. Wolff’s practical instinct is sound; what’s missing is the theoretical foundation that would let him generalize from this example to a consistent principle.</p>
<p><strong>Case 1: Different change drivers.</strong> If each customer’s requirements evolve independently (Customer A’s business rules change without affecting Customer B), the duplicated code has <em>different change drivers</em>. The code looks identical today, but it varies for different reasons. Duplication is <em>correct</em>—it’s not a cohesion violation. Each copy belongs with its customer’s change driver. Wolff’s observation that “changes are thus completely decoupled” confirms this: independent variation sources should be separated.</p>
<p><strong>Case 2: Shared set of change drivers.</strong> If there are features that must apply to <em>all</em> customers (a regulatory requirement, a core platform capability), those features represent a <em>shared set of change drivers</em>. Code implementing shared features should be unified, not duplicated. Wolff correctly notes that duplication “makes it nearly impossible to implement features for all customers”—but this isn’t a trade-off against loose coupling. It’s a cohesion failure: elements with the same change driver are scattered across customer codebases.</p>
<p>The resolution: identify which parts have customer-specific change drivers (separate them) and which parts have a shared set of change drivers (unify them). There’s no inherent tension between cohesion and coupling—there’s only the question of correctly identifying change driver assignments.</p>
<p>Wolff even hints at this: “some actually recommend implementing a generic core only after the third similar implementation.” This advice exists precisely because early apparent duplication often represents independent variation sources. Premature unification would create false cohesion—grouping elements that will diverge.</p>
<p>The principle: <strong>Cohesion is about variation dependence, not textual similarity.</strong> Duplicated code with different change drivers is correctly separated. Duplicated code with the same change driver is a cohesion failure and represents increased, accidental coupling.</p>
</section>
<section id="simply-following-dry-principles-doesnt-guarantee-good-cohesion" class="level3" data-number="1.7">
<h3 data-number="1.7" class="anchored" data-anchor-id="simply-following-dry-principles-doesnt-guarantee-good-cohesion"><span class="header-section-number">1.7</span> “Simply following DRY principles doesn’t guarantee good cohesion”</h3>
<p>Correct, but for the wrong reasons. DRY (Don’t Repeat Yourself) addresses <em>knowledge duplication</em>—the idea that every piece of knowledge should have a single authoritative representation. DRY says nothing about <em>where</em> that representation should live or how modules should be organized.</p>
<p>Cohesion is about organizing elements by their variation sources. DRY is about avoiding inconsistent representations of the same knowledge. They’re orthogonal concerns. You can have perfect DRY compliance with terrible cohesion (everything in one module) or perfect cohesion with DRY violations (when apparently similar code represents different change drivers).</p>
</section>
<section id="modules-form-a-hierarchyfrom-microservices-down-to-packages-classes-and-methods.-different-organizational-principles-apply-at-each-level." class="level3" data-number="1.8">
<h3 data-number="1.8" class="anchored" data-anchor-id="modules-form-a-hierarchyfrom-microservices-down-to-packages-classes-and-methods.-different-organizational-principles-apply-at-each-level."><span class="header-section-number">1.8</span> “Modules form a hierarchy—from microservices down to packages, classes, and methods. Different organizational principles apply at each level.”</h3>
<p>Wolff claims coarse-grained modules (microservices) should follow “domain concerns” while fine-grained modules (packages, classes) should follow “technical separation.”</p>
<p>This is arbitrary. Why would the organizing principle change based on granularity?</p>
<p><strong>IVP’s answer:</strong> The same principle—align boundaries with change drivers—applies at every level (and in any dimension, but that discussion is out of scope here). What changes is the <em>granularity of change drivers</em> being considered.</p>
<p>At the microservice level, you might have coarse-grained change drivers: <code>γ_orders</code>, <code>γ_inventory</code>, <code>γ_shipping</code>. At the class level within the orders service, you refine <code>γ_orders</code> into finer-grained drivers: <code>γ_pricing</code>, <code>γ_validation</code>, <code>γ_persistence</code>. The principle remains constant; the analysis granularity varies.</p>
<p>There’s no magical switch from “domain concerns” to “technical concerns” at some arbitrary boundary. Technical concerns (UI frameworks, persistence mechanisms, infrastructure) simply have their own change drivers like any other concern. They should be separated from business logic because they vary independently—not because of some special rule about technical layers.</p>
</section>
<section id="grouping-everything-together-ensures-nothing-is-torn-apart-but-creates-incomprehensibly-large-modules." class="level3" data-number="1.9">
<h3 data-number="1.9" class="anchored" data-anchor-id="grouping-everything-together-ensures-nothing-is-torn-apart-but-creates-incomprehensibly-large-modules."><span class="header-section-number">1.9</span> “Grouping everything together ensures nothing is ‘torn apart,’ but creates incomprehensibly large modules.”</h3>
<p>This is presented as a paradox requiring judgment. Under IVP, there’s no paradox.</p>
<p>A module should contain all elements sharing the same change driver assignments—no more, no less. If a module is “incomprehensibly large,” either:</p>
<ol type="1">
<li>You’re analyzing at too coarse a granularity (the change driver should be refined into finer-grained independent drivers), or</li>
<li>The module genuinely embodies a large, coherent body of domain knowledge that varies together.</li>
</ol>
<p>Case (2) isn’t a problem—it’s reality. Some concerns are genuinely large and coherent. The “incomprehensibility” comes from trying to understand code without understanding the domain knowledge it embodies. And… domain knowledge (what is part of the domain, its policies, its ubiquitous language…) is defined by the decisional authority structure that governs it. Here we’re back to decisional authority.</p>
</section>
<section id="cohesion-demands-both-grouping-related-components-and-separating-unrelated-ones-to-maintain-manageability." class="level3" data-number="1.10">
<h3 data-number="1.10" class="anchored" data-anchor-id="cohesion-demands-both-grouping-related-components-and-separating-unrelated-ones-to-maintain-manageability."><span class="header-section-number">1.10</span> “Cohesion demands both grouping related components AND separating unrelated ones to maintain manageability.”</h3>
<p>Finally, something close to correct—but imprecisely stated.</p>
<p>IVP formalizes this as four directives:</p>
<ul>
<li><strong>IVP-1 (Element Admissibility):</strong> Every element must be governed by at least one change driver.</li>
<li><strong>IVP-2 (Change Driver Assignment):</strong> Assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>IVP-3 (Unit Purity — Separation):</strong> Elements with different change driver assignments must be in different modules.</li>
<li><strong>IVP-4 (Unit Completeness — Unification):</strong> Elements with the same change driver assignment must be in the same module.</li>
</ul>
<p>The last two establish a biconditional: two elements share a module if and only if they share the same set of change drivers. This isn’t a vague call for “grouping and separating”—it’s a precise criterion for exactly what goes where.</p>
<hr>
</section>
</section>
<section id="the-ivp-framework-in-brief" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-ivp-framework-in-brief"><span class="header-section-number">2</span> The IVP Framework in Brief</h2>
<p>Here’s the rigorous foundation Wolff’s post lacks.</p>
<section id="core-definitions" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="core-definitions"><span class="header-section-number">2.1</span> Core Definitions</h3>
<p>A <strong>change driver</strong> (γ) represents an independently varying source of change to domain knowledge. Change drivers are independent when changes to one don’t necessitate changes to another.</p>
<p>Examples: business rules (γ_business), UI framework (γ_UI), persistence mechanism (γ_persistence), external API contracts (γ_API).</p>
<p>An <strong>element</strong> is an atomic unit of code at whatever granularity you’re analyzing (class, function, module).</p>
<p>The <strong>change driver assignment</strong> Γ(e) maps each element to the set of change drivers that could cause it to change.</p>
<p>Some elements are <em>pure</em>—they have a single change driver (|Γ(e)| = 1). These are your core domain logic, your infrastructure implementations, your UI components. Other elements legitimately have <em>multiple</em> change drivers (|Γ(e)| &gt; 1). These are typically adapters, integration points, or boundaries between domains. An adapter between your business logic and your persistence layer has Γ(adapter) = {γ_business, γ_persistence}—it must change when either domain changes. This is not a design flaw; it represents the <em>legitimate coupling</em> between pure domains. IVP doesn’t eliminate such elements; it ensures they’re grouped with other elements sharing the same multi-driver assignment, and it makes explicit where the necessary, legitimate coupling lives.</p>
</section>
<section id="the-structural-formulation" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="the-structural-formulation"><span class="header-section-number">2.2</span> The Structural Formulation</h3>
<p><strong>IVP:</strong> <em>Separate elements with different change driver assignments into distinct units; unify elements with the same change driver assignment within a single unit.</em></p>
<p>Formally: - <strong>IVP-1:</strong> ∀e ∈ E: |Γ(e)| ≥ 1 - <strong>IVP-2:</strong> ∀e ∈ E: |Γ(e)| = 1, unless the multi-driver assignment is irreducible - <strong>IVP-3:</strong> ∀e_i, e_j ∈ E: Γ(e_i) ≠ Γ(e_j) ⟹ they’re in different modules - <strong>IVP-4:</strong> ∀e_i, e_j ∈ E: Γ(e_i) = Γ(e_j) ⟹ they’re in the same module</p>
<p>IVP-3 and IVP-4 together form a biconditional: elements share a module ⟺ they share the same set of change drivers.</p>
</section>
<section id="causal-cohesion-properly-defined" class="level3" data-number="2.3">
<h3 data-number="2.3" class="anchored" data-anchor-id="causal-cohesion-properly-defined"><span class="header-section-number">2.3</span> Causal Cohesion (Properly Defined)</h3>
<p>Cohesion has two measurable dimensions:</p>
<ol type="1">
<li><strong>Purity:</strong> purity(M) = 1/|{Γ(e) : e ∈ M}| ∈ (0, 1], where we count the number of <em>distinct</em> change driver assignments across all elements in the module. Equals 1 when all elements share the same change driver assignment. Note: an adapter module where all elements have Γ(e) = {γ_A, γ_B} has purity = 1—the elements are homogeneous even though each element has multiple drivers.</li>
<li><strong>Completeness:</strong> completeness(M) = min over σ ∈ {Γ(e) : e ∈ M} of |{e ∈ M : Γ(e) = σ}|/|ε(σ)| ∈ [0, 1], where ε(σ) is the set of all elements in the system with assignment σ. For each distinct assignment present in M, we measure what fraction of all elements with that assignment are in M; the minimum gives the worst case. Equals 1 when, for every assignment present in M, all elements with that assignment are unified in M.</li>
</ol>
<p>A module has <em>maximal cohesion</em> when both equal 1: cohesion(M) = (1, 1)—pure and complete. An adapter module with all elements sharing assignment {γ_A, γ_B} can achieve (1, 1) if it contains all such elements. Note that an impure module (purity &lt; 1) can still have completeness = 1 if, for each distinct assignment it contains, all elements with that assignment are in the module—though this typically indicates the module should be split. ### Cohesion Primacy</p>
<p><strong>Theorem:</strong> In an IVP-compliant system, maximal cohesion implies minimal coupling.</p>
<p><strong>Proof sketch:</strong> Accidental coupling (dependencies beyond what the domain requires) introduces foreign change drivers into modules—an element that depends on another inherits that element’s variation sources. This reduces structural purity (by introducing elements with different assignments into the same module), showing up as degraded cohesion. Accidental coupling is therefore detectable as a cohesion problem.</p>
<p>Conversely, when all modules have purity = 1 (all elements share the same assignment) and completeness = 1 (all elements with that assignment are unified), inter-module dependencies can only exist between modules with different assignments—which represents the legitimate, domain-required coupling between different concerns. No accidental coupling remains.</p>
<p><strong>Corollary:</strong> You don’t need to measure coupling and cohesion as separate metrics. Measure cohesion. If it’s maximal, coupling is minimal. If cohesion is degraded, find the heterogeneous assignments—they reveal the accidental coupling.</p>
<p>This is why coupling and cohesion aren’t symmetric: coupling problems are a consequence of cohesion problems. Cohesion has primacy.</p>
<hr>
</section>
</section>
<section id="what-this-means-in-practice" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="what-this-means-in-practice"><span class="header-section-number">3</span> What This Means in Practice</h2>
<p>What does this mean for architects?</p>
<ol type="1">
<li><p><strong>Stop treating cohesion intuitively.</strong> “Belongs together” is not a criterion. Ask: “What are the change drivers? Do these elements share them?”</p></li>
<li><p><strong>Stop balancing cohesion against coupling.</strong> There’s no trade-off. Maximize cohesion (by IVP’s definition); coupling minimizes automatically.</p></li>
<li><p><strong>Code duplication isn’t automatically bad.</strong> If duplicated code has different change drivers (varies for different reasons), it’s correctly separated. Unifying it would <em>reduce</em> cohesion.</p></li>
<li><p><strong>The organizing principle doesn’t change by granularity.</strong> Apply IVP at every level. Change the granularity of your change driver analysis, not your organizing principle.</p></li>
<li><p><strong>Technical vs.&nbsp;domain is a false dichotomy.</strong> Technical concerns (persistence, UI, infrastructure) are simply change drivers. Separate them from business logic because they’re independent variation sources, not because of some layer rule.</p></li>
</ol>
<hr>
</section>
<section id="wrapping-up" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="wrapping-up"><span class="header-section-number">4</span> Wrapping Up</h2>
<p>Wolff’s post is representative of mainstream architectural thinking—and that’s been the problem for more than 5 decades. This isn’t Wolff’s fault; he’s faithfully representing what our field has taught for generations. The issue is that what we’ve been teaching is built on sand. We operate on intuition, vague definitions, and folk wisdom. We treat cohesion and coupling as mysterious forces to be balanced. We offer contradictory advice because we lack the theoretical foundation to resolve contradictions.</p>
<p>IVP provides that foundation. The core insights aren’t new—Parnas articulated them in 1972 in “On the Criteria To Be Used in Decomposing Systems into Modules”: modularization should be based on design decisions likely to change (information hiding), and module boundaries should align with work assignments. But Parnas left these as separate, loosely articulated concepts. He probably didn’t recognize that “likely to change” and “work assignments” are two facets of the same underlying idea—what IVP now calls change drivers. For more than five decades, nobody connected these dots or formalized them into a rigorous, operational framework. IVP does exactly that—what might be the first unifying foundational theory of software architecture.</p>
<p>IVP defines cohesion precisely, establishes its primacy over coupling, and gives architects a clear criterion for modularization decisions. When you understand that cohesion is about aligning module boundaries with change driver assignments, the confusion dissolves.</p>
<p>The question isn’t whether elements “somehow belong together.” The question is: <strong>Do they share the same set of change drivers?</strong></p>
<hr>
<p><em>The full exposition of IVP is available in <a href="https://doi.org/10.5281/zenodo.17677315">The Independent Variation Principle (IVP)</a>. Formal mathematical foundations, including proofs of its relationship to SOLID principles, are forthcoming.</em></p>


</section>

 ]]></description>
  <category>ivp</category>
  <category>engineering</category>
  <category>architecture</category>
  <category>cohesion</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2026-01-08-cohesion-is-not-what-you-think-a-formal-response-to-eberhard-wolff-14bn.html</guid>
  <pubDate>Thu, 08 Jan 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>What the Independent Variation Principle Reveals About Type Safety</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-12-22-what-the-independent-variation-principle-reveals-about-type-safety-14ng.html</link>
  <description><![CDATA[ 





<p>I recently published <a href="https://zenodo.org/records/17677315">“The Independent Variation Principle: A Unifying Meta-Principle for Software Architecture”</a>, a paper that formalizes a framework unifying design principles like SOLID, Domain-Driven Design, and common patterns. The IVP addresses broad architectural concerns, but it has something specific to say about an old debate: type-safe versus dynamically-typed languages.</p>
<p>The IVP gives us a way to understand <em>why</em> type systems matter for long-term software evolution, beyond the usual arguments about catching bugs.</p>
<section id="types-as-change-driver-boundaries" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="types-as-change-driver-boundaries"><span class="header-section-number">1</span> Types as Change Driver Boundaries</h2>
<p>Type systems enforce change driver boundaries. That’s what they’re for.</p>
<p>The IVP revolves around <strong>change drivers</strong>: the distinct forces that cause different parts of a system to evolve. Its structural formulation states four directives:</p>
<ul>
<li><strong>IVP-1 — Element Admissibility:</strong> every element must be governed by at least one change driver.</li>
<li><strong>IVP-2 — Change Driver Assignment:</strong> assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>IVP-3 — Unit Purity (Separation):</strong> elements with different change driver assignments belong in distinct units.</li>
<li><strong>IVP-4 — Unit Completeness (Unification):</strong> elements with the same change driver assignment belong in a single unit.</li>
</ul>
<section id="type-safe-languages" class="level3" data-number="1.1">
<h3 data-number="1.1" class="anchored" data-anchor-id="type-safe-languages"><span class="header-section-number">1.1</span> Type-Safe Languages</h3>
<p>Type-safe languages provide formal separation through interfaces. Consider a payment processing system. You have multiple change drivers: - <strong>Business Logic</strong>: What constitutes a valid payment - <strong>Data Representation</strong>: How payment data is structured in memory - <strong>Infrastructure</strong>: How payments are persisted</p>
<p>In a type-safe language (Java, TypeScript, Rust), an interface is a formal contract:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode typescript code-with-copy"><code class="sourceCode typescript"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentMethod {</span>
<span id="cb1-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">authorize</span>(amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Money)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>AuthResult<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;;</span></span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">capture</span>(authId<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">string</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>CaptureResult<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;;</span></span>
<span id="cb1-4">}</span></code></pre></div></div>
<p>This interface creates a mechanical boundary. The business logic that uses <code>PaymentMethod</code> has <em>zero knowledge</em> of whether the implementation uses Stripe, PayPal, or a mock service. The IVP calls this <strong>structural purity</strong>: the compiler ensures that each module contains all and only the knowledge required by its change driver.</p>
<p>If you modify the internal implementation of a concrete payment processor, the type system guarantees that unrelated business logic cannot be affected. The change drivers vary independently.</p>
</section>
<section id="dynamic-languages" class="level3" data-number="1.2">
<h3 data-number="1.2" class="anchored" data-anchor-id="dynamic-languages"><span class="header-section-number">1.2</span> Dynamic Languages</h3>
<p>Dynamic languages rely on implicit coupling. Change driver boundaries exist only through convention and discipline. Consider the same system in JavaScript without types:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">processPayment</span>(payment<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> paymentMethod) {</span>
<span id="cb2-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// What properties does 'paymentMethod' have?</span></span>
<span id="cb2-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// What paymentMethod can I call?</span></span>
<span id="cb2-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The answers exist only in documentation and hope.</span></span>
<span id="cb2-5">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> paymentMethod<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">authorize</span>(payment<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">amount</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-6">}</span></code></pre></div></div>
<p>The IVP identifies this as <strong>accidental coupling</strong>. The business logic and the payment implementation are coupled not through explicit dependencies, but through <em>implicit knowledge</em>. If the payment implementation changes its internal structure (say, renaming <code>authorize</code> to <code>initiateAuth</code>), there is no compiler to identify all coupled points.</p>
<p>The change drivers are not formally separated. What the IVP calls “knowledge partitioning” happens through developer discipline rather than mechanical enforcement.</p>
</section>
</section>
<section id="why-this-matters-at-scale" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="why-this-matters-at-scale"><span class="header-section-number">2</span> Why This Matters at Scale</h2>
<p>The paper introduces the <strong>Knowledge Theorem</strong>, which says that architectural quality is a measure of how well code reflects the partition of domain knowledge.</p>
<p>In type-safe languages, knowledge partitions are <strong>explicit and enforced</strong>: - Each type encapsulates specific knowledge about a change driver - The compiler prevents knowledge from leaking across boundaries - When a change driver evolves, the compiler identifies exactly which modules must adapt</p>
<p>In dynamically-typed languages, knowledge partitions are <strong>implicit and conventional</strong>: - Knowledge boundaries exist in developer intention - Changes can propagate through the system unpredictably - A schema change in the database can “ghost fail” in UI logic without any formal indication</p>
<p>The IVP describes this as higher <strong>transitive coupling</strong>. Because implementation details leak through dynamic access patterns, a change in a low-level driver often forces changes in high-level drivers that should have been isolated.</p>
</section>
<section id="purity-as-a-measurable-property" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="purity-as-a-measurable-property"><span class="header-section-number">3</span> Purity as a Measurable Property</h2>
<p>The IVP treats architectural quality as measurable. Purity is a metric for how well a module isolates its change driver.</p>
<p><strong>Type-safe languages provide structural purity</strong>: The compiler mechanically enforces that a module’s dependencies match its change driver. A <code>UserService</code> depends only on <code>UserRepository</code> and <code>ValidationEngine</code>, not on the internal SQL queries or validation regex patterns.</p>
<p><strong>Dynamic languages provide heuristic purity</strong>: Purity depends entirely on conventions (naming, folder structure, code review practices). These are valuable but fragile. They erode over time as deadlines press and the team changes.</p>
<p>From the IVP perspective, type safety is not about being “better” in some aesthetic sense. It is about mechanical enforcement of architectural boundaries that would otherwise require constant vigilance.</p>
</section>
<section id="change-propagation" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="change-propagation"><span class="header-section-number">4</span> Change Propagation</h2>
<p>Change propagation is either controlled or unpredictable, depending on your type system. When a change driver evolves, how does the impact propagate?</p>
<section id="type-safe-languages-1" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="type-safe-languages-1"><span class="header-section-number">4.1</span> Type-Safe Languages</h3>
<p>Type systems provide explicit change maps. The compiler generates a complete map of what must change.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode typescript code-with-copy"><code class="sourceCode typescript"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Changing this interface...</span></span>
<span id="cb3-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> UserRepository {</span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">findById</span>(id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> UserId)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>User <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;;</span></span>
<span id="cb3-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// NEW: Add method</span></span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">findByEmail</span>(email<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Email)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Promise</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>User <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;;</span></span>
<span id="cb3-6">}</span>
<span id="cb3-7"></span>
<span id="cb3-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...immediately flags all implementations</span></span>
<span id="cb3-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PostgresUserRepo <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> UserRepository {</span>
<span id="cb3-10">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Compiler error: Missing 'findByEmail'</span></span>
<span id="cb3-11">}</span></code></pre></div></div>
<p>There are no silent failures.</p>
</section>
<section id="dynamic-languages-1" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="dynamic-languages-1"><span class="header-section-number">4.2</span> Dynamic Languages</h3>
<p>Dynamic languages create implicit change ripples. Changes propagate unpredictably through the system.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Changing this object...</span></span>
<span id="cb4-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> userRepo <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb4-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">findById</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> (id) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> { <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> }</span>
<span id="cb4-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// NEW: Add method</span></span>
<span id="cb4-5">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">findByEmail</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">async</span> (email) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> { <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> }</span>
<span id="cb4-6">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-7"></span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...provides no feedback on consumers</span></span>
<span id="cb4-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// They fail at runtime, potentially in production</span></span></code></pre></div></div>
<p>Type systems do not eliminate change. They make change visible and localized.</p>
</section>
</section>
<section id="implications-for-large-scale-systems" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="implications-for-large-scale-systems"><span class="header-section-number">5</span> Implications for Large-Scale Systems</h2>
<p>The IVP’s formal treatment shows that the value of type safety scales non-linearly with system size and team size:</p>
<ul>
<li><strong>Small projects</strong>: Convention and discipline can maintain knowledge boundaries</li>
<li><strong>Large codebases</strong>: The combinatorial explosion of dependencies makes informal boundaries untenable</li>
<li><strong>Distributed teams</strong>: Without mechanical enforcement, different parts of the system drift toward incompatible assumptions</li>
</ul>
<p>This matches what we see in practice: dynamic languages dominate in early-stage startups and scripting contexts, while type-safe languages dominate in large enterprise systems and critical infrastructure.</p>
<p>The IVP explains why: as the number of change drivers grows, the cost of maintaining their independence without formal boundaries grows exponentially.</p>
</section>
<section id="type-safety-as-architectural-discipline" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="type-safety-as-architectural-discipline"><span class="header-section-number">6</span> Type Safety as Architectural Discipline</h2>
<p>The Independent Variation Principle reframes type safety. It’s not about personal preference or “catching typos.” It’s an architectural mechanism for managing change driver independence.</p>
<p>Type-safe languages provide: 1. Formal separation of change drivers through interfaces and types 2. Structural purity enforced by the compiler 3. Explicit change propagation maps when drivers evolve</p>
<p>Dynamic languages rely on: 1. Implicit separation maintained by convention 2. Heuristic purity depending on discipline 3. Unpredictable change propagation detected at runtime</p>
<p>Neither is “wrong.” They operate at different points on the trade-off curve between implementation speed and long-term change management. The IVP gives us a vocabulary for understanding <em>why</em> that trade-off exists and <em>when</em> each approach is appropriate.</p>
<p>For systems where change drivers are few, stable, and well-understood, the overhead of type safety may not justify its benefits. But for systems where drivers are many, evolving, and managed by distributed teams, type safety is not just helpful. It is the mechanical enforcement of the Independent Variation Principle itself.</p>
<hr>
<p><em>The full paper is available at <a href="https://zenodo.org/records/17677315">Zenodo: 10.5281/zenodo.17677315</a>. This article represents an interpretation of the IVP’s implications for type systems.</em></p>


</section>

 ]]></description>
  <category>engineering</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-12-22-what-the-independent-variation-principle-reveals-about-type-safety-14ng.html</guid>
  <pubDate>Mon, 22 Dec 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Novel Contributions of the Independent Variation Principle</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-12-16-novel-contributions-of-the-independent-variation-principle-lmd.html</link>
  <description><![CDATA[ 





<section id="the-independent-variation-principle-ivp" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-independent-variation-principle-ivp"><span class="header-section-number">1</span> The Independent Variation Principle (IVP)</h2>
<p>The structural formulation states four directives:</p>
<ol type="1">
<li><strong>IVP-1 — Element Admissibility:</strong> every element must be governed by at least one change driver.</li>
<li><strong>IVP-2 — Change Driver Assignment:</strong> assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>IVP-3 — Unit Purity (Separation):</strong> elements with different change driver assignments belong in distinct units.</li>
<li><strong>IVP-4 — Unit Completeness (Unification):</strong> elements with the same change driver assignment belong in a single unit.</li>
</ol>
</section>
<section id="the-novel-contributions" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-novel-contributions"><span class="header-section-number">2</span> The Novel Contributions</h2>
<p>What does IVP contribute that wasn’t already present in Separation of Concerns, Information Hiding, SOLID or other software design principles? Here are the genuinely novel elements, organized as layers of a hierarchy of logic:</p>
<hr>
<section id="the-foundation" class="level3" data-number="2.1">
<h3 data-number="2.1" class="anchored" data-anchor-id="the-foundation"><span class="header-section-number">2.1</span> The Foundation</h3>
<blockquote class="blockquote">
<p>This layer recognizes the <strong>reality</strong>: The Partition Property grounded in Decisional Authority.</p>
</blockquote>
<p><strong>1. The Partition Property</strong></p>
<p>Previous principles say “separate concerns” but don’t specify how concerns relate to each other. IVP establishes that independent change drivers <em>partition</em> domain knowledge: they are disjoint (no overlap) and exhaustive (no gaps). This transforms vague advice into a mathematical structure. Every piece of knowledge belongs to exactly one driver; if it seems to belong to two, either the drivers aren’t truly independent or the knowledge needs to be split.</p>
<p><strong>2. Grounding in Decisional Authority</strong></p>
<p>Earlier principles ground separation in technical criteria (information hiding), predicted change (encapsulate what varies), or vague “responsibilities” (SRP). IVP grounds separation in <em>observable organizational reality</em>: who has the authority to request changes? This shifts from speculation about future technical evolution to mapping existing decision structures—something that can be discovered through stakeholder interviews, not predicted through technical intuition.</p>
<p><strong>3. The Relational Nature of Design Properties</strong></p>
<p>IVP establishes that cohesion, coupling, responsibility, and change driver ownership are <em>not intrinsic to code constructs but are relational</em>—they emerge from the relationship between the construct and its context of use. A code element’s membership in a change driver depends on context, not on inherent properties. This resolves persistent confusion in software design by anchoring relational properties in concrete, context-specific reality.</p>
<hr>
</section>
<section id="the-logic" class="level3" data-number="2.2">
<h3 data-number="2.2" class="anchored" data-anchor-id="the-logic"><span class="header-section-number">2.2</span> The Logic</h3>
<blockquote class="blockquote">
<p>This layer provides the <strong>rules</strong>: The Biconditional, the 1/n Purity scale, and the focus on Causal relationships over structural ones.</p>
</blockquote>
<p><strong>4. The Biconditional (IVP-3 + IVP-4)</strong></p>
<p>Most principles focus on separation: “don’t put different things together.” IVP adds the equally important unification directive: “do put same things together.” The biconditional—elements share a module <em>if and only if</em> they share change drivers—is stronger than either directive alone. It prohibits both over-separation (scattered concerns) and under-separation (mixed concerns).</p>
<p><strong>5. Causal vs.&nbsp;Structural Cohesion</strong></p>
<p>Traditional cohesion metrics are structural: do these elements access the same data? Call the same functions? IVP introduces <em>causal</em> cohesion: do these elements change for the same reason? Two elements with identical structural properties may have completely different causal relationships. This distinction is invisible to static analysis but fundamental to maintainability.</p>
<p><strong>6. The Discrete Nature of Purity</strong></p>
<p>IVP reveals that cohesion isn’t continuous. A module with one change driver has purity 1; with two drivers, purity drops to 1/2; with three, to 1/3. Even “small” contamination (1% foreign knowledge) halves structural purity. This discreteness explains why architectural debt compounds: the first violation is disproportionately costly.</p>
<p><strong>7. Transitive Coupling as Knowledge Gap</strong></p>
<p>IVP reveals that problematic transitive coupling (A→B→C where changes to C propagate through B to A) reflects <em>incomplete knowledge formalization</em>. Element B mixes “knowledge A depends on” with “knowledge about C’s implementation,” creating multiple change drivers where there should be one. Transitive coupling is not merely a structural problem but a knowledge completeness problem.</p>
<hr>
</section>
<section id="the-action" class="level3" data-number="2.3">
<h3 data-number="2.3" class="anchored" data-anchor-id="the-action"><span class="header-section-number">2.3</span> The Action</h3>
<blockquote class="blockquote">
<p>The function of this layer is the <strong>construction</strong>: Deriving elements from knowledge and distinguishing necessary from accidental impurity.</p>
</blockquote>
<p><strong>8. Necessary vs.&nbsp;Accidental Impurity</strong></p>
<p>IVP doesn’t require all modules to have exactly one change driver. Adapters, bridges, and coordinators legitimately serve multiple drivers. The question is whether each driver is <em>necessary</em> for the module’s purpose. This distinction—between modules that are impure by necessity and those that are impure by accident—resolves apparent counterexamples to single-responsibility thinking.</p>
<p><strong>9. Derivation of Elements from Knowledge</strong></p>
<p>IVP provides a principled answer to “what elements should exist?” Elements are not invented arbitrarily; they are <em>derived</em> from the partition structure of domain knowledge. For each change driver’s knowledge partition, create elements that embody all knowledge in that partition. This grounds software structure in domain structure.</p>
<hr>
</section>
<section id="the-evaluation" class="level3" data-number="2.4">
<h3 data-number="2.4" class="anchored" data-anchor-id="the-evaluation"><span class="header-section-number">2.4</span> The Evaluation</h3>
<blockquote class="blockquote">
<p>The function of this layer is the <strong>optimization</strong>: The Objective Function. Prioritizing debt and measuring knowledge hygiene.</p>
</blockquote>
<p><strong>10. The Six Dimensions for Prioritization</strong></p>
<p>IVP provides a framework for deciding <em>which</em> separations matter most: frequency, magnitude, predictability, control, scope, and authority distance. Not all IVP violations are equally urgent. This transforms IVP from a binary judgment (“compliant or not”) into a prioritized improvement roadmap.</p>
<p><strong>11. The Knowledge Theorem</strong></p>
<p>IVP establishes a formal connection between knowledge organization and architectural quality: cohesion measures how completely a module embodies its concern’s knowledge; coupling measures how much foreign knowledge has leaked in. This makes “good architecture” a matter of knowledge hygiene rather than aesthetic preference.</p>
<hr>
</section>
<section id="the-result" class="level3" data-number="2.5">
<h3 data-number="2.5" class="anchored" data-anchor-id="the-result"><span class="header-section-number">2.5</span> The Result</h3>
<blockquote class="blockquote">
<p>This layer concludes with the grand <strong>unification</strong>: The convergence of all prior principles.</p>
</blockquote>
<p><strong>12. Cohesion Primacy</strong></p>
<p>IVP establishes that coupling and cohesion are not independent variables to be optimized separately. Focus on cohesion—ensuring each module fully embodies its concern’s knowledge—and minimal coupling follows automatically. When a module contains all and only the knowledge for its change driver, there is nothing foreign to couple to and nothing missing that would require reaching elsewhere. This inverts the traditional framing: don’t ask “how do I reduce coupling?” but “how do I complete the knowledge?”</p>
<p><strong>13. The Unification of Prior Principles</strong></p>
<p>Perhaps most importantly, IVP shows that Information Hiding, SRP, OCP, ISP, DIP, Package Architecture Principles, DDD bounded contexts, GoF patterns, EIP patterns and more are all <em>instantiations</em> of a single underlying principle. They aren’t independent guidelines to be balanced against each other; they’re different perspectives on the same truth. This unification simplifies architectural reasoning: instead of juggling multiple principles, apply IVP and the others follow.</p>
<hr>
</section>
</section>
<section id="summary-the-13-novel-contributions" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="summary-the-13-novel-contributions"><span class="header-section-number">3</span> Summary: The 13 Novel Contributions</h2>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Layer</th>
<th>#</th>
<th>Contribution</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Foundation</strong></td>
<td>1</td>
<td>The Partition Property</td>
</tr>
<tr class="even">
<td></td>
<td>2</td>
<td>Grounding in Decisional Authority</td>
</tr>
<tr class="odd">
<td></td>
<td>3</td>
<td>Relational Nature of Design Properties</td>
</tr>
<tr class="even">
<td><strong>Logic</strong></td>
<td>4</td>
<td>The Biconditional (IVP-3 + IVP-4)</td>
</tr>
<tr class="odd">
<td></td>
<td>5</td>
<td>Causal vs.&nbsp;Structural Cohesion</td>
</tr>
<tr class="even">
<td></td>
<td>6</td>
<td>The Discrete Nature of Purity (1/n)</td>
</tr>
<tr class="odd">
<td></td>
<td>7</td>
<td>Transitive Coupling as Knowledge Gap</td>
</tr>
<tr class="even">
<td><strong>Action</strong></td>
<td>8</td>
<td>Necessary vs.&nbsp;Accidental Impurity</td>
</tr>
<tr class="odd">
<td></td>
<td>9</td>
<td>Derivation of Elements from Knowledge</td>
</tr>
<tr class="even">
<td><strong>Evaluation</strong></td>
<td>10</td>
<td>The Six Dimensions for Prioritization</td>
</tr>
<tr class="odd">
<td></td>
<td>11</td>
<td>The Knowledge Theorem</td>
</tr>
<tr class="even">
<td><strong>Result</strong></td>
<td>12</td>
<td>Cohesion Primacy</td>
</tr>
<tr class="odd">
<td></td>
<td>13</td>
<td>Unification of Prior Principles</td>
</tr>
</tbody>
</table>
<hr>
</section>
<section id="learn-more" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">4</span> Learn More</h2>
<p>This article applies the Independent Variation Principle framework from:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The IVP paper provides a unified framework for understanding why certain abstractions work and when to apply them.</p>


</section>

 ]]></description>
  <category>ivp</category>
  <category>architecture</category>
  <category>engineering</category>
  <category>solid</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-12-16-novel-contributions-of-the-independent-variation-principle-lmd.html</guid>
  <pubDate>Tue, 16 Dec 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Closures vs Objects: Understanding ‘A Poor Man’s’ Through the Lens of IVP</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-12-04-closures-vs-objects-understanding-a-poor-mans-through-the-lens-of-ivp-105j.html</link>
  <description><![CDATA[ 





<p>There is a famous programming koan by Anton van Straaten:</p>
<blockquote class="blockquote">
<p>The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said “Master, I have heard that objects are a very good thing - is this true?” Qc Na looked pityingly at his student and replied, “Foolish pupil - objects are merely a poor man’s closures.”</p>
<p>Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire “Lambda: The Ultimate…” series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.</p>
<p>On his next walk with Qc Na, Anton attempted to impress his master by saying “Master, I have diligently studied the matter, and now understand that objects are truly a poor man’s closures.” Qc Na responded by hitting Anton with his stick, saying “When will you learn? Closures are a poor man’s object.”</p>
<p>At that moment, Anton became enlightened.</p>
</blockquote>
<p>The koan suggests a symmetry between closures and objects. Does this symmetry hold in practice?</p>
<p>The answer requires examining when each abstraction succeeds and when it becomes a poor substitute for the other. The Independent Variation Principle provides a framework for this analysis.</p>
<section id="the-independent-variation-principle-ivp" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-independent-variation-principle-ivp"><span class="header-section-number">1</span> The Independent Variation Principle (IVP)</h2>
<p>I will use the Independent Variation Principle as the analytical framework throughout this article.</p>
<p>The structural formulation states four directives:</p>
<ul>
<li><strong>IVP-1 (Element Admissibility):</strong> every element must be governed by at least one change driver.</li>
<li><strong>IVP-2 (Change Driver Assignment):</strong> assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>IVP-3 (Unit Purity — Separation):</strong> elements governed by different change drivers belong in distinct units.</li>
<li><strong>IVP-4 (Unit Completeness — Unification):</strong> elements governed by the same change driver belong in a single unit.</li>
</ul>
<p>Change drivers are forces that cause code to change: new features, performance requirements, business rules, technical constraints. Different change drivers indicate elements that vary for independent reasons—IVP-3 separates them into distinct units. The same change driver indicates elements that vary together—IVP-4 unifies them within a single unit.</p>
<p>This guidance is what makes the principle actionable. It tells you both when to split things apart and when to keep things together.</p>
<p>For the closures versus objects question, I will identify change drivers for each scenario: behavioral variety (multiple implementations), state evolution (how data changes), resource lifecycle (acquisition and release), dependency timing (when dependencies are provided).</p>
<p>Then I will analyze whether closures or objects better respect the independence of these change drivers.</p>
<p>When an abstraction respects independent change drivers, you get high cohesion (related things stay together), low coupling (unrelated things can change independently), and easy maintenance (changes are localized).</p>
<p>When an abstraction violates independence by coupling things that should vary independently, you get fragility (changes cascade unpredictably), rigidity (hard to adapt to new requirements), and what we call a poor substitute.</p>
<p>This framework transforms the closures versus objects debate from subjective preference into principled analysis.</p>
</section>
<section id="a-note-on-terminology" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="a-note-on-terminology"><span class="header-section-number">2</span> A Note on Terminology</h2>
<p>This article discusses closures versus objects as conceptual abstractions, not closures versus classes specifically. An object is any instance combining state and behavior—whether implemented via classes (Java, C#, TypeScript), prototypes (JavaScript), closures (functional languages, JavaScript factories), or message-passing (Smalltalk, Erlang).</p>
<p>The comparison is not “closures versus classes” but rather: when should you model a problem using closure-thinking (functions capturing context) versus object-thinking (entities with state and methods)? In practice, both are often implemented using similar mechanisms. The key difference is which mental model better respects your change drivers.</p>
</section>
<section id="the-core-equivalence" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-core-equivalence"><span class="header-section-number">3</span> The Core Equivalence</h2>
<p>First, I should establish that closures and objects are fundamentally equivalent in computational power. You can implement either using the other.</p>
<p>A <strong>closure</strong> is a function that captures variables from its surrounding lexical scope. These captured variables remain accessible even after the outer function has returned. This mechanism allows functions to carry state without explicit object instantiation.</p>
<p>Object as closure:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Object approach</span></span>
<span id="cb1-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Counter {</span>
<span id="cb1-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(initial) {</span>
<span id="cb1-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">count</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-5">  }</span>
<span id="cb1-6"></span>
<span id="cb1-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>() {</span>
<span id="cb1-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">count</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-9">  }</span>
<span id="cb1-10"></span>
<span id="cb1-11">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>() {</span>
<span id="cb1-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">count</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-13">  }</span>
<span id="cb1-14">}</span>
<span id="cb1-15"></span>
<span id="cb1-16"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Counter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-17">counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1</span></span>
<span id="cb1-18">counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1</span></span></code></pre></div></div>
<p>Closure as object:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Closure approach</span></span>
<span id="cb2-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(initial) {</span>
<span id="cb2-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Variable 'count' is declared in makeCounter's scope</span></span>
<span id="cb2-4">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> count <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-5"></span>
<span id="cb2-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// The returned object contains functions that "close over" count</span></span>
<span id="cb2-7">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb2-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// These arrow functions capture 'count' from the enclosing scope</span></span>
<span id="cb2-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// They can access and modify 'count' even after makeCounter returns</span></span>
<span id="cb2-10">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span>count<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Captured: can read and write 'count'</span></span>
<span id="cb2-11">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> count      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Captured: can read 'count'</span></span>
<span id="cb2-12">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-13">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// When makeCounter returns, 'count' is not destroyed</span></span>
<span id="cb2-14">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// It remains accessible to the returned functions</span></span>
<span id="cb2-15">}</span>
<span id="cb2-16"></span>
<span id="cb2-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-18">counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1 - increments the captured 'count'</span></span>
<span id="cb2-19">counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1 - reads the captured 'count'</span></span></code></pre></div></div>
<p>They look similar. Same interface, same behavior. So what is the difference?</p>
</section>
<section id="the-ivp-lens-independent-change-drivers" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="the-ivp-lens-independent-change-drivers"><span class="header-section-number">4</span> The IVP Lens: Independent Change Drivers</h2>
<p>The Independent Variation Principle asks us to identify change drivers—the forces that cause code to change. When we separate elements governed by different change drivers, we achieve high cohesion and low coupling.</p>
<p>The change drivers relevant to data and behavior abstractions:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 34%">
<col style="width: 30%">
<col style="width: 34%">
</colgroup>
<thead>
<tr class="header">
<th>Change Driver</th>
<th>What Varies</th>
<th>Who Drives It</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Behavioral variety</td>
<td>Different implementations of the same interface</td>
<td>Product requirements, feature additions</td>
</tr>
<tr class="even">
<td>Data structure</td>
<td>How state is organized and accessed</td>
<td>Performance needs, memory constraints</td>
</tr>
<tr class="odd">
<td>State evolution</td>
<td>How data changes over time</td>
<td>Business rules, domain logic</td>
</tr>
<tr class="even">
<td>Instantiation</td>
<td>How instances are created</td>
<td>Construction complexity, dependency injection</td>
</tr>
<tr class="odd">
<td>Type relationships</td>
<td>Inheritance, composition, substitutability</td>
<td>Domain modeling, polymorphism needs</td>
</tr>
<tr class="even">
<td>Information hiding</td>
<td>What is accessible versus private</td>
<td>API design, encapsulation requirements</td>
</tr>
<tr class="odd">
<td>Instance quantity</td>
<td>How many instances exist simultaneously</td>
<td>Memory constraints, resource limits</td>
</tr>
<tr class="even">
<td>Method lifetimes</td>
<td>How long methods need to exist versus data</td>
<td>Garbage collection, memory management</td>
</tr>
<tr class="odd">
<td>Dependency timing</td>
<td>When dependencies are provided versus when needed</td>
<td>Testing strategy, staged configuration</td>
</tr>
<tr class="even">
<td>State persistence</td>
<td>Need to serialize and transfer state without behavior</td>
<td>Distributed systems, storage requirements</td>
</tr>
<tr class="odd">
<td>Concurrent access</td>
<td>How multiple threads or processes access state</td>
<td>Concurrency model, immutability needs</td>
</tr>
<tr class="even">
<td>Instantiation frequency</td>
<td>How often instances are created versus methods called</td>
<td>Performance optimization, object pooling</td>
</tr>
<tr class="odd">
<td>Contract enforcement</td>
<td>Compile-time versus runtime checking</td>
<td>Type safety requirements, bug prevention</td>
</tr>
<tr class="even">
<td>Testing strategy</td>
<td>Production API versus test doubles</td>
<td>Testability needs, mock complexity</td>
</tr>
</tbody>
</table>
<p>The key insight: closures and classes handle these drivers differently. Neither is universally better—each excels when its strengths align with your change drivers.</p>
</section>
<section id="when-classes-shine-explicit-type-hierarchies-with-shared-behavior" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="when-classes-shine-explicit-type-hierarchies-with-shared-behavior"><span class="header-section-number">5</span> When Classes Shine: Explicit Type Hierarchies with Shared Behavior</h2>
<p>Consider a graphics rendering system with multiple shape types that share common behavior:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Using classes - natural fit</span></span>
<span id="cb3-2">abstract <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Shape {</span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> string) {}</span>
<span id="cb3-4"></span>
<span id="cb3-5">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Shared behavior across all shapes</span></span>
<span id="cb3-6">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">draw</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">context</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">CanvasRenderingContext2D</span>) {</span>
<span id="cb3-7">    context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fillStyle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">render</span>(context)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logDrawing</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-10">  }</span>
<span id="cb3-11"></span>
<span id="cb3-12">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logDrawing</span>() {</span>
<span id="cb3-13">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Drew </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">constructor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> in </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-14">  }</span>
<span id="cb3-15"></span>
<span id="cb3-16">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Each shape implements its own rendering</span></span>
<span id="cb3-17">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> abstract <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">render</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">context</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">CanvasRenderingContext2D</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-18"></span>
<span id="cb3-19">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Each shape computes its own area</span></span>
<span id="cb3-20">  abstract <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> number<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-21">}</span>
<span id="cb3-22"></span>
<span id="cb3-23"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Circle <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Shape {</span>
<span id="cb3-24">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> string<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">radius</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> number) {</span>
<span id="cb3-25">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">super</span>(color)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-26">  }</span>
<span id="cb3-27"></span>
<span id="cb3-28">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">render</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">context</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">CanvasRenderingContext2D</span>) {</span>
<span id="cb3-29">    context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">beginPath</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-30">    context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arc</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">radius</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">PI</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-31">    context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fill</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-32">  }</span>
<span id="cb3-33"></span>
<span id="cb3-34">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span>() {</span>
<span id="cb3-35">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">PI</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">radius</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-36">  }</span>
<span id="cb3-37">}</span>
<span id="cb3-38"></span>
<span id="cb3-39"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Rectangle <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Shape {</span>
<span id="cb3-40">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> string<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> number<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> number) {</span>
<span id="cb3-41">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">super</span>(color)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-42">  }</span>
<span id="cb3-43"></span>
<span id="cb3-44">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">render</span>(<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">context</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">CanvasRenderingContext2D</span>) {</span>
<span id="cb3-45">    context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fillRect</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">height</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-46">  }</span>
<span id="cb3-47"></span>
<span id="cb3-48">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span>() {</span>
<span id="cb3-49">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-50">  }</span>
<span id="cb3-51">}</span>
<span id="cb3-52"></span>
<span id="cb3-53"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Polymorphic usage</span></span>
<span id="cb3-54"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderShapes</span>(shapes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> Shape[]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">CanvasRenderingContext2D</span>) {</span>
<span id="cb3-55">  shapes<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">forEach</span>(shape <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> shape<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">draw</span>(context))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-56">}</span></code></pre></div></div>
<p>IVP analysis—what are the change drivers here?</p>
<ol type="1">
<li><strong>Shared behavior driver</strong>: Drawing protocol, logging, color management evolve together</li>
<li><strong>Variant behavior driver</strong>: Each shape has unique rendering and area calculation</li>
<li><strong>Type relationship driver</strong>: All shapes ARE shapes—substitutability matters</li>
<li><strong>Data structure driver</strong>: Each shape has unique state (radius versus width and height)</li>
</ol>
<p>Why classes excel here:</p>
<ul>
<li><strong>Shared behavior is reused</strong>: The <code>draw()</code> and <code>logDrawing()</code> methods are defined once, inherited by all.</li>
<li><strong>Type relationships are explicit</strong>: The <code>Shape</code> base class documents the contract.</li>
<li><strong>Variant behavior is enforced</strong>: Abstract methods must be implemented.</li>
<li><strong>Polymorphism is natural</strong>: The <code>renderShapes()</code> function works with any <code>Shape</code> subtype.</li>
</ul>
<section id="can-closures-handle-behavioral-variants" class="level3" data-number="5.1">
<h3 data-number="5.1" class="anchored" data-anchor-id="can-closures-handle-behavioral-variants"><span class="header-section-number">5.1</span> Can Closures Handle Behavioral Variants?</h3>
<p>Absolutely. But the approach is fundamentally different. Closures achieve variants through strategy injection rather than inheritance:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Closure approach using strategy pattern</span></span>
<span id="cb4-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeShape</span>(color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> renderStrategy<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> areaStrategy) {</span>
<span id="cb4-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb4-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">draw</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (context) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb4-5">      context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fillStyle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-6">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">renderStrategy</span>(context)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-7">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Drew shape in </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>color<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-8">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-9">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">area</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">areaStrategy</span>()</span>
<span id="cb4-10">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-11">}</span>
<span id="cb4-12"></span>
<span id="cb4-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategies are just functions</span></span>
<span id="cb4-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> circleRenderer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (radius) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> (context) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb4-15">  context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">beginPath</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-16">  context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">arc</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">PI</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-17">  context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fill</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-18">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-19"></span>
<span id="cb4-20"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> circleArea <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (radius) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">PI</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> radius <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-21"></span>
<span id="cb4-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> rectangleRenderer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> height) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> (context) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb4-23">  context<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fillRect</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> height)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-24">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-25"></span>
<span id="cb4-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> rectangleArea <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> height) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-27"></span>
<span id="cb4-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage</span></span>
<span id="cb4-29"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> circle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeShape</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'red'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">circleRenderer</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">circleArea</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-30"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> rectangle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeShape</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'blue'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rectangleRenderer</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rectangleArea</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-31"></span>
<span id="cb4-32">circle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">draw</span>(context)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Works polymorphically</span></span></code></pre></div></div>
<p>This works. But notice the trade-offs.</p>
<p>What is different with closures:</p>
<ul>
<li><strong>No shared behavior inheritance</strong>: Each shape gets its own copy of the drawing logic.</li>
<li><strong>No type relationship enforcement</strong>: Nothing ensures strategies are compatible.</li>
<li><strong>Strategy coordination is manual</strong>: Passing <code>radius</code> to both renderer and area calculator requires discipline.</li>
<li><strong>No “IS-A” relationship</strong>: Shapes are not subtypes of anything—just compatible objects.</li>
</ul>
<p>When closures are better:</p>
<ul>
<li><strong>Strategies are first-class</strong>: Easy to swap rendering without changing structure.</li>
<li><strong>Composition over inheritance</strong>: Can mix behaviors independently.</li>
<li><strong>No base class coupling</strong>: Changing shared behavior does not force recompilation.</li>
</ul>
<p>The verdict: classes excel when you have true type hierarchies with shared implementation. Closures excel when you need flexible strategy composition without inheritance coupling.</p>
<p>The choice depends on your change drivers. If you need to evolve shared behavior across types, use classes to avoid duplication. If you need to mix and match strategies independently, use closures to avoid coupling.</p>
</section>
</section>
<section id="when-closures-shine-stateful-behavior-without-type-hierarchy" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="when-closures-shine-stateful-behavior-without-type-hierarchy"><span class="header-section-number">6</span> When Closures Shine: Stateful Behavior Without Type Hierarchy</h2>
<p>Now consider a different scenario: event handlers and callbacks.</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Using closures - natural fit</span></span>
<span id="cb5-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setupButton</span>(buttonId) {</span>
<span id="cb5-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> clickCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-4">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> lastClickTime <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-5"></span>
<span id="cb5-6">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> button <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getElementById</span>(buttonId)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-7"></span>
<span id="cb5-8">  button<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">addEventListener</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'click'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb5-9">    clickCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb5-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Date</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">now</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-11"></span>
<span id="cb5-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (lastClickTime <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> lastClickTime) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>) {</span>
<span id="cb5-13">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Double click detected!'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-14">    }</span>
<span id="cb5-15"></span>
<span id="cb5-16">    lastClickTime <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> now<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-17">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Total clicks: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>clickCount<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-18">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-19"></span>
<span id="cb5-20">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb5-21">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">reset</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb5-22">      clickCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-23">      lastClickTime <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-24">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb5-25">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> clickCount</span>
<span id="cb5-26">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-27">}</span>
<span id="cb5-28"></span>
<span id="cb5-29"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> buttonHandler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">setupButton</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'myButton'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>IVP analysis—what are the change drivers?</p>
<ol type="1">
<li><strong>State evolution driver</strong>: Click count and timing change with user interaction</li>
<li><strong>Information hiding driver</strong>: Internal state should not leak</li>
<li><strong>Instantiation driver</strong>: Each button needs its own isolated state</li>
</ol>
<p>Why closures excel here:</p>
<ul>
<li><strong>State encapsulation is automatic</strong>: <code>clickCount</code> and <code>lastClickTime</code> are truly private.</li>
<li><strong>No boilerplate</strong>: No class definition, constructor, or <code>this</code> binding.</li>
<li><strong>Lexical scope is clear</strong>: Reading the code reveals exactly what state is captured.</li>
<li><strong>No type hierarchy needed</strong>: This is not a “kind of” anything—it is just stateful behavior.</li>
</ul>
<section id="attempting-this-with-classes" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="attempting-this-with-classes"><span class="header-section-number">6.1</span> Attempting This with Classes</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Class approach - awkward</span></span>
<span id="cb6-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> ButtonHandler {</span>
<span id="cb6-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(buttonId) {</span>
<span id="cb6-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">clickCount</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lastClickTime</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">button</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">document</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getElementById</span>(buttonId)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-7"></span>
<span id="cb6-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Need to bind 'this' - common source of bugs</span></span>
<span id="cb6-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">handleClick</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">handleClick</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">bind</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">button</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">addEventListener</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'click'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">handleClick</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-11">  }</span>
<span id="cb6-12"></span>
<span id="cb6-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">handleClick</span>() {</span>
<span id="cb6-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">clickCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb6-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Date</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">now</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-16"></span>
<span id="cb6-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lastClickTime</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> (now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lastClickTime</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>) {</span>
<span id="cb6-18">      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Double click detected!'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-19">    }</span>
<span id="cb6-20"></span>
<span id="cb6-21">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lastClickTime</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> now<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-22">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Total clicks: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">clickCount</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-23">  }</span>
<span id="cb6-24"></span>
<span id="cb6-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reset</span>() {</span>
<span id="cb6-26">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">clickCount</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-27">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lastClickTime</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-28">  }</span>
<span id="cb6-29"></span>
<span id="cb6-30">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>() {</span>
<span id="cb6-31">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">clickCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-32">  }</span>
<span id="cb6-33">}</span>
<span id="cb6-34"></span>
<span id="cb6-35"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> buttonHandler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ButtonHandler</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'myButton'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>IVP violation—what is wrong here? The class approach has several drawbacks:</p>
<ul>
<li><strong><code>this</code> binding complexity</strong>: Must manually bind methods to preserve context.</li>
<li><strong>False encapsulation</strong>: <code>clickCount</code> and <code>lastClickTime</code> are accessible as <code>this.clickCount</code>.</li>
<li><strong>Unnecessary abstraction</strong>: No behavioral variants exist—we do not need inheritance or interfaces.</li>
<li><strong>Boilerplate overhead</strong>: Class definition, constructor, explicit method definitions for single-use code.</li>
</ul>
<p>The verdict: when you need stateful behavior without type hierarchies or multiple variants, closures are not a “poor man’s objects”—they are the right abstraction. Classes here are the poor substitute.</p>
</section>
</section>
<section id="the-deep-difference-what-each-abstraction-separates" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-deep-difference-what-each-abstraction-separates"><span class="header-section-number">7</span> The Deep Difference: What Each Abstraction Separates</h2>
<section id="classes-separating-type-from-implementation" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="classes-separating-type-from-implementation"><span class="header-section-number">7.1</span> Classes: Separating Type from Implementation</h3>
<p>Classes excel when you need to separate:</p>
<ul>
<li>Interface from implementation: “what” from “how”</li>
<li>Type hierarchy from concrete types: abstraction from specialization</li>
<li>Shared behavior from variant behavior: base class from subclasses</li>
</ul>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Classic OOP: type hierarchy with shared behavior</span></span>
<span id="cb7-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Shape</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-4">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">perimeter</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb7-5"></span>
<span id="cb7-6">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Shared behavior</span></span>
<span id="cb7-7">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">describe</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-8">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">System</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">out</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Area: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb7-9">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">System</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">out</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Perimeter: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">perimeter</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb7-10">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-11"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-12"></span>
<span id="cb7-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Circle <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Shape</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-14">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-15"></span>
<span id="cb7-16">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Circle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">radius</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-17"></span>
<span id="cb7-18">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PI</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> radius <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-19">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">perimeter</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Math</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PI</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> radius<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-20"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-21"></span>
<span id="cb7-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Shape</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-23">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-24"></span>
<span id="cb7-25">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Rectangle</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-26">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">width</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-27">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">height</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-28">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-29"></span>
<span id="cb7-30">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">area</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-31">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">perimeter</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>width <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> height<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-32"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Change drivers aligned:</p>
<ul>
<li><strong>Adding new shapes</strong>: Add new subclasses without modifying existing ones</li>
<li><strong>Changing shared behavior</strong>: Modify base class without touching subclasses</li>
<li><strong>Polymorphic operations</strong>: Work with <code>Shape</code> interface regardless of concrete type</li>
</ul>
<p>This is the Open-Closed Principle in action—and it is natural with classes.</p>
</section>
<section id="closures-separating-behavior-from-state-capture" class="level3" data-number="7.2">
<h3 data-number="7.2" class="anchored" data-anchor-id="closures-separating-behavior-from-state-capture"><span class="header-section-number">7.2</span> Closures: Separating Behavior from State Capture</h3>
<p>Closures excel when you need to separate:</p>
<ul>
<li>Stateful behavior from state management: The closure “remembers” without explicit state objects</li>
<li>Lexical scope from execution scope: What variables exist when defined versus when called</li>
<li>Configuration from execution: Captured context configures behavior</li>
</ul>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Classic closure: behavior configured by captured context</span></span>
<span id="cb8-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeRateLimiter</span>(maxRequests<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> timeWindow) {</span>
<span id="cb8-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> requests <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> []<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-4"></span>
<span id="cb8-5">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span>(action) {</span>
<span id="cb8-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Date</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">now</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-7"></span>
<span id="cb8-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Remove old requests outside time window</span></span>
<span id="cb8-9">    requests <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> requests<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">filter</span>(time <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> (now <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> time) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> timeWindow)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-10"></span>
<span id="cb8-11">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (requests<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> maxRequests) {</span>
<span id="cb8-12">      <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Rate limit exceeded'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-13">    }</span>
<span id="cb8-14"></span>
<span id="cb8-15">    requests<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push</span>(now)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">action</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-17">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-18">}</span>
<span id="cb8-19"></span>
<span id="cb8-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Each rate limiter has its own isolated state</span></span>
<span id="cb8-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> apiLimiter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeRateLimiter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60000</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 100 requests per minute</span></span>
<span id="cb8-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> authLimiter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeRateLimiter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">60000</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>   <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 5 requests per minute</span></span>
<span id="cb8-23"></span>
<span id="cb8-24"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">apiLimiter</span>(() <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">callApi</span>())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-25"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">authLimiter</span>(() <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">authenticate</span>())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Change drivers aligned:</p>
<ul>
<li><strong>Changing rate limits</strong>: Create new limiters with different parameters</li>
<li><strong>Adding rate limiting</strong>: Wrap any function without modifying its code</li>
<li><strong>Independent state</strong>: Each limiter’s state is isolated via closure</li>
</ul>
<p>This is the Strategy Pattern without the ceremony—and it is natural with closures.</p>
</section>
</section>
<section id="when-classes-are-a-poor-mans-closures" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="when-classes-are-a-poor-mans-closures"><span class="header-section-number">8</span> When Classes Are “A Poor Man’s Closures”</h2>
<p>Classes become a poor substitute for closures when:</p>
<section id="you-are-forcing-type-hierarchy-where-none-exists" class="level3" data-number="8.1">
<h3 data-number="8.1" class="anchored" data-anchor-id="you-are-forcing-type-hierarchy-where-none-exists"><span class="header-section-number">8.1</span> 1. You Are Forcing Type Hierarchy Where None Exists</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's closure using a class</span></span>
<span id="cb9-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Logger {</span>
<span id="cb9-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(prefix) {</span>
<span id="cb9-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> prefix<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-5">  }</span>
<span id="cb9-6"></span>
<span id="cb9-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(message) {</span>
<span id="cb9-8">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">prefix</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>message<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-9">  }</span>
<span id="cb9-10">}</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> logger <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Logger</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'[INFO]'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-13">logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Something happened'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-14"></span>
<span id="cb9-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Much simpler with a closure</span></span>
<span id="cb9-16"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeLogger</span>(prefix) {</span>
<span id="cb9-17">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (message) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>prefix<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>message<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-18">}</span>
<span id="cb9-19"></span>
<span id="cb9-20"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> logger <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeLogger</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'[INFO]'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logger</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Something happened'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>Configuration (prefix) versus Execution (logging messages)</strong></li>
<li><strong>No behavioral variety, no type hierarchy needed</strong></li>
</ul>
<p>IVP insight: there is no behavioral variety here. No subclasses. No polymorphism. The class adds ceremony without benefit.</p>
</section>
<section id="you-are-creating-single-method-classes" class="level3" data-number="8.2">
<h3 data-number="8.2" class="anchored" data-anchor-id="you-are-creating-single-method-classes"><span class="header-section-number">8.2</span> 2. You Are Creating Single-Method Classes</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's closure using a class</span></span>
<span id="cb10-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Validator {</span>
<span id="cb10-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(minLength<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> maxLength) {</span>
<span id="cb10-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">minLength</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> minLength<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxLength</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> maxLength<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-6">  }</span>
<span id="cb10-7"></span>
<span id="cb10-8">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span>(input) {</span>
<span id="cb10-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> input<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">minLength</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span></span>
<span id="cb10-10">           input<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">maxLength</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-11">  }</span>
<span id="cb10-12">}</span>
<span id="cb10-13"></span>
<span id="cb10-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> validator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Validator</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-15">validator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hello'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-16"></span>
<span id="cb10-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Much simpler with a closure</span></span>
<span id="cb10-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeValidator</span>(minLength<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> maxLength) {</span>
<span id="cb10-19">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (input) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span></span>
<span id="cb10-20">    input<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> minLength <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span></span>
<span id="cb10-21">    input<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> maxLength<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-22">}</span>
<span id="cb10-23"></span>
<span id="cb10-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> validator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeValidator</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-25"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validator</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'hello'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>Configuration (min, max) versus Validation (checking input)</strong></li>
<li><strong>Single responsibility: just one operation</strong></li>
</ul>
<p>IVP insight: a class with one method is just a function. The class wrapper obscures this simplicity.</p>
</section>
<section id="you-are-using-this-to-smuggle-state" class="level3" data-number="8.3">
<h3 data-number="8.3" class="anchored" data-anchor-id="you-are-using-this-to-smuggle-state"><span class="header-section-number">8.3</span> 3. You Are Using “This” to Smuggle State</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb11-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's closure using a class</span></span>
<span id="cb11-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Accumulator {</span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>() {</span>
<span id="cb11-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">total</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-5">  }</span>
<span id="cb11-6"></span>
<span id="cb11-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span>(value) {</span>
<span id="cb11-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">total</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">total</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-10">  }</span>
<span id="cb11-11">}</span>
<span id="cb11-12"></span>
<span id="cb11-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Simpler with a closure</span></span>
<span id="cb11-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeAccumulator</span>() {</span>
<span id="cb11-15">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-16">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> (value) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> total <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> value<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-17">}</span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>State (total) exists only to be captured by behavior (accumulation)</strong></li>
<li><strong>No type hierarchy or multiple methods needed</strong></li>
</ul>
<p>IVP insight: when state exists solely to be captured by methods, closures make this relationship explicit.</p>
</section>
</section>
<section id="when-closures-are-a-poor-mans-objects" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="when-closures-are-a-poor-mans-objects"><span class="header-section-number">9</span> When Closures Are “A Poor Man’s Objects”</h2>
<p>Closures become a poor substitute for classes when:</p>
<section id="you-are-faking-methods-as-properties" class="level3" data-number="9.1">
<h3 data-number="9.1" class="anchored" data-anchor-id="you-are-faking-methods-as-properties"><span class="header-section-number">9.1</span> 1. You Are Faking Methods as Properties</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb12-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's object using closures</span></span>
<span id="cb12-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePerson</span>(name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> age) {</span>
<span id="cb12-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb12-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-5">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getAge</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> age<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">haveBirthday</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> { age<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-7">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">introduce</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Hi, I'm </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>age<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> years old`</span></span>
<span id="cb12-8">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-9">}</span>
<span id="cb12-10"></span>
<span id="cb12-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// More honest with a class</span></span>
<span id="cb12-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Person {</span>
<span id="cb12-13">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> age) {</span>
<span id="cb12-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> age<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-16">  }</span>
<span id="cb12-17"></span>
<span id="cb12-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">haveBirthday</span>() {</span>
<span id="cb12-19">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb12-20">  }</span>
<span id="cb12-21"></span>
<span id="cb12-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">introduce</span>() {</span>
<span id="cb12-23">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Hi, I'm </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">, </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> years old`</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-24">  }</span>
<span id="cb12-25">}</span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>Multiple methods operating on shared state</strong></li>
<li><strong>Object cohesion: behaviors belong together</strong></li>
</ul>
<p>IVP insight: when you are returning an object with multiple methods that all operate on the same state, you are already thinking in objects—just admit it.</p>
</section>
<section id="you-are-implementing-ad-hoc-polymorphism" class="level3" data-number="9.2">
<h3 data-number="9.2" class="anchored" data-anchor-id="you-are-implementing-ad-hoc-polymorphism"><span class="header-section-number">9.2</span> 2. You Are Implementing Ad-Hoc Polymorphism</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb13-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's polymorphism using closures</span></span>
<span id="cb13-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeAnimal</span>(type<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> sound) {</span>
<span id="cb13-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb13-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">speak</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(sound)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb13-5">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getType</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> type</span>
<span id="cb13-6">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-7">}</span>
<span id="cb13-8"></span>
<span id="cb13-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> dog <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeAnimal</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'dog'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'woof'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> cat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeAnimal</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'cat'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'meow'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-11"></span>
<span id="cb13-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// More explicit with classes</span></span>
<span id="cb13-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Animal {</span>
<span id="cb13-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">speak</span>() { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Must implement"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb13-15">}</span>
<span id="cb13-16"></span>
<span id="cb13-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Dog <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Animal {</span>
<span id="cb13-18">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">speak</span>() { <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'woof'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb13-19">}</span>
<span id="cb13-20"></span>
<span id="cb13-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Cat <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Animal {</span>
<span id="cb13-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">speak</span>() { <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'meow'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb13-23">}</span>
<span id="cb13-24"></span>
<span id="cb13-25"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> dog <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Dog</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> cat <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Cat</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-27"></span>
<span id="cb13-28"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeAnimalSpeak</span>(animal) {</span>
<span id="cb13-29">  animal<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">speak</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Polymorphism enforced by type system</span></span>
<span id="cb13-30">}</span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>Behavioral variants (dog, cat) of same interface (Animal)</strong></li>
<li><strong>Type hierarchy with polymorphic substitution</strong></li>
</ul>
<p>IVP insight: when you have multiple variants of the same interface and need polymorphic substitution, classes make the type relationships explicit.</p>
</section>
<section id="you-are-manually-managing-shared-state" class="level3" data-number="9.3">
<h3 data-number="9.3" class="anchored" data-anchor-id="you-are-manually-managing-shared-state"><span class="header-section-number">9.3</span> 3. You Are Manually Managing Shared State</h3>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb14-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Poor man's shared state using closures</span></span>
<span id="cb14-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeSharedCounter</span>() {</span>
<span id="cb14-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> count <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-4"></span>
<span id="cb14-5">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb14-6">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">instance1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb14-7">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span>count<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb14-8">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">get</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> count</span>
<span id="cb14-9">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb14-10">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">instance2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb14-11">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span>count<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb14-12">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">get</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> count</span>
<span id="cb14-13">    }</span>
<span id="cb14-14">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-15">}</span>
<span id="cb14-16"></span>
<span id="cb14-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// More natural with a class</span></span>
<span id="cb14-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Counter {</span>
<span id="cb14-19">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">static</span> count <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-20"></span>
<span id="cb14-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>() {</span>
<span id="cb14-22">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span>Counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">count</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-23">  }</span>
<span id="cb14-24"></span>
<span id="cb14-25">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">get</span>() {</span>
<span id="cb14-26">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Counter<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">count</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-27">  }</span>
<span id="cb14-28">}</span>
<span id="cb14-29"></span>
<span id="cb14-30"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> counter1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Counter</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-31"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> counter2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Counter</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb14-32">counter1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Both see the same count</span></span>
<span id="cb14-33">counter2<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">get</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Change drivers:</p>
<ul>
<li><strong>Shared state across multiple instances</strong></li>
<li><strong>Instance-specific behavior accessing shared data</strong></li>
</ul>
<p>IVP insight: when you need shared state across instances, classes have explicit mechanisms (static properties). Closures require manual wiring.</p>
</section>
</section>
<section id="the-fundamental-pattern-aligning-abstraction-to-change-drivers" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="the-fundamental-pattern-aligning-abstraction-to-change-drivers"><span class="header-section-number">10</span> The Fundamental Pattern: Aligning Abstraction to Change Drivers</h2>
<p>The Independent Variation Principle reveals the deep pattern.</p>
<p>Use classes when you have:</p>
<ul>
<li><strong>Behavioral variety with type relationships</strong>: Multiple implementations of the same interface</li>
<li><strong>Polymorphic substitution</strong>: Different types used interchangeably</li>
<li><strong>Shared behavior via inheritance</strong>: Base class provides common functionality</li>
<li><strong>Explicit type hierarchy</strong>: “Is-a” relationships matter for the domain</li>
<li><strong>Multiple methods operating on shared state</strong>: The object represents a cohesive entity</li>
</ul>
<p>Example domains: payment systems, shape hierarchies, UI components, domain entities.</p>
<p>Use closures when you have:</p>
<ul>
<li><strong>Stateful behavior without type hierarchy</strong>: Just behavior plus private state</li>
<li><strong>Configuration via capture</strong>: Lexical scope parameterizes behavior</li>
<li><strong>Single-purpose functions</strong>: One operation, possibly with private state</li>
<li><strong>Callback and event handlers</strong>: Behavior tied to specific context</li>
<li><strong>Information hiding without boilerplate</strong>: True privacy via lexical scope</li>
</ul>
<p>Example domains: event handlers, rate limiters, memoization, loggers, validators.</p>
</section>
<section id="the-hybrid-approach-interfaces-and-closures" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="the-hybrid-approach-interfaces-and-closures"><span class="header-section-number">11</span> The Hybrid Approach: Interfaces and Closures</h2>
<p>Modern languages often combine both:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode typescript code-with-copy"><code class="sourceCode typescript"><span id="cb15-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// TypeScript: Interface + Closure</span></span>
<span id="cb15-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentProcessor {</span>
<span id="cb15-3">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">process</span>(amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">number</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentResult<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-4">}</span>
<span id="cb15-5"></span>
<span id="cb15-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCreditCardProcessor</span>(cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">string</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentProcessor {</span>
<span id="cb15-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Closure captures card details</span></span>
<span id="cb15-8">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb15-9">    process<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb15-10">      method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'credit'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-11">      amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-12">      card<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> cardNumber</span>
<span id="cb15-13">    })</span>
<span id="cb15-14">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-15">}</span>
<span id="cb15-16"></span>
<span id="cb15-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePayPalProcessor</span>(email<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">string</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentProcessor {</span>
<span id="cb15-18">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb15-19">    process<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb15-20">      method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'paypal'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-21">      amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb15-22">      email</span>
<span id="cb15-23">    })</span>
<span id="cb15-24">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-25">}</span>
<span id="cb15-26"></span>
<span id="cb15-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Polymorphic use with type safety</span></span>
<span id="cb15-28"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span>(processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentProcessor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">number</span>) {</span>
<span id="cb15-29">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>(amount)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-30">}</span>
<span id="cb15-31"></span>
<span id="cb15-32"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCreditCardProcessor</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'1234'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb15-33"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePayPalProcessor</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'user@example.com'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>This combines the strengths of both approaches. The interface provides compile-time type safety. The closures provide implementation simplicity. No inheritance hierarchy needed.</p>
</section>
<section id="constructor-injection-and-partial-application-the-deep-equivalence" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="constructor-injection-and-partial-application-the-deep-equivalence"><span class="header-section-number">12</span> Constructor Injection and Partial Application: The Deep Equivalence</h2>
<p>I have come to realize that constructor injection and partial application are fundamentally the same pattern expressed in different abstractions. Both separate dependency configuration from data processing.</p>
<p>Constructor injection (classes):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb16-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: Constructor injection</span></span>
<span id="cb16-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb16-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Logger</span> logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb16-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> Database db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb16-5"></span>
<span id="cb16-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentService</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Logger</span> logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Database db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb16-7">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logger</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Dependencies provided upfront</span></span>
<span id="cb16-8">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">db</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb16-9">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb16-10"></span>
<span id="cb16-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PaymentRequest request<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb16-12">        logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Processing payment"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb16-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">save</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>request<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Use captured dependencies</span></span>
<span id="cb16-14">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb16-15"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb16-16"></span>
<span id="cb16-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: dependencies provided at construction</span></span>
<span id="cb16-18">PaymentService service <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentService</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb16-19">service<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>request1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb16-20">service<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>request2<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span></code></pre></div></div>
<p>Partial application (closures):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb17-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Partial application</span></span>
<span id="cb17-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentService</span>(logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> db) {  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Dependencies provided upfront</span></span>
<span id="cb17-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">process</span>(request) {</span>
<span id="cb17-4">    logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Processing payment"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb17-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">save</span>(request)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Use captured dependencies</span></span>
<span id="cb17-6">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb17-7">}</span>
<span id="cb17-8"></span>
<span id="cb17-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: dependencies provided at factory call</span></span>
<span id="cb17-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> service <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentService</span>(logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> db)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb17-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">service</span>(request1)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb17-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">service</span>(request2)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>The structural similarity is striking. Both separate “things that change slowly” (dependencies) from “things that change often” (data to process).</p>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Dependency configuration</strong>: Logger and database connection change rarely</li>
<li><strong>Data processing</strong>: Payment requests change frequently</li>
</ol>
<p>These vary independently—you might process thousands of payments with the same logger and database.</p>
<p>Both approaches respect this independence by separating configuration (provide dependencies once) from execution (process many requests).</p>
<p>The difference is syntactic, not semantic:</p>
<ul>
<li>Constructor injection uses language constructs (constructors, fields, <code>this</code>)</li>
<li>Partial application uses function composition (factory functions, closure capture)</li>
</ul>
<p>When dependencies come all-at-once, both work equally well. The choice depends on language idioms and whether you need other object-oriented features (inheritance, interfaces, multiple methods).</p>
<section id="staged-configuration-where-closures-truly-excel" class="level3" data-number="12.1">
<h3 data-number="12.1" class="anchored" data-anchor-id="staged-configuration-where-closures-truly-excel"><span class="header-section-number">12.1</span> Staged Configuration: Where Closures Truly Excel</h3>
<p>But closures reveal their power when dependencies do not come all-at-once. When you need staged configuration, closures handle this naturally through nested function calls.</p>
<p>Consider a database query builder that needs configuration in stages:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb18-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Multi-stage configuration via nested closures</span></span>
<span id="cb18-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">query</span>(table) {</span>
<span id="cb18-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb18-4">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">where</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (condition) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb18-5">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">orderBy</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (field) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb18-6">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">limit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (n) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb18-7">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">execute</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb18-8">            <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// All parameters captured via closure chain</span></span>
<span id="cb18-9">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">execute</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`SELECT * FROM </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>table<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> WHERE </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>condition<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> ORDER BY </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>field<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;"> LIMIT </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>n<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb18-10">          }</span>
<span id="cb18-11">        })</span>
<span id="cb18-12">      })</span>
<span id="cb18-13">    })</span>
<span id="cb18-14">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb18-15">}</span>
<span id="cb18-16"></span>
<span id="cb18-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: staged configuration</span></span>
<span id="cb18-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">query</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'users'</span>)</span>
<span id="cb18-19">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'age &gt; 18'</span>)</span>
<span id="cb18-20">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderBy</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'name'</span>)</span>
<span id="cb18-21">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">limit</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>)</span>
<span id="cb18-22">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">execute</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Each stage captures its parameters, building up the closure’s captured environment. This is partial application taken to its logical conclusion.</p>
<p>Attempting this with classes requires builder pattern boilerplate:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb19-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: Builder pattern for staged configuration</span></span>
<span id="cb19-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> QueryBuilder <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> table<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> condition<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> orderByField<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Integer</span> limit<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-7"></span>
<span id="cb19-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">QueryBuilder</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> table<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-9">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> table<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-10">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-11"></span>
<span id="cb19-12">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> QueryBuilder <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> condition<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-13">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">condition</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> condition<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-15">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-16"></span>
<span id="cb19-17">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> QueryBuilder <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderBy</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> field<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-18">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderByField</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> field<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-20">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-21"></span>
<span id="cb19-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> QueryBuilder <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">limit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-23">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">limit</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-24">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb19-25">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-26"></span>
<span id="cb19-27">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ResultSet</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">execute</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb19-28">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">execute</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT * FROM "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> table <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" WHERE "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> condition <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb19-29">                         <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" ORDER BY "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> orderByField <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">" LIMIT "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> limit<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb19-30">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-31"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb19-32"></span>
<span id="cb19-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: same staged configuration</span></span>
<span id="cb19-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">ResultSet</span> results <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">QueryBuilder</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"users"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb19-35">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">where</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"age &gt; 18"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb19-36">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderBy</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb19-37">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">limit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb19-38">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">execute</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span></code></pre></div></div>
<p>This works, but notice the overhead. The class requires explicit field declarations, assignments in each method, and manual return of <code>this</code>. The closure version achieves the same result through nested function returns.</p>
<p>IVP insight: when dependency timing and usage timing vary independently—when you need to provide dependencies in stages rather than all-at-once—closures respect this independence more naturally than constructor injection. Partial application is the natural expression of staged configuration.</p>
</section>
</section>
<section id="construction-and-destruction-lifecycle-management" class="level2" data-number="13">
<h2 data-number="13" class="anchored" data-anchor-id="construction-and-destruction-lifecycle-management"><span class="header-section-number">13</span> Construction and Destruction: Lifecycle Management</h2>
<section id="construction-ensuring-valid-instances" class="level3" data-number="13.1">
<h3 data-number="13.1" class="anchored" data-anchor-id="construction-ensuring-valid-instances"><span class="header-section-number">13.1</span> Construction: Ensuring Valid Instances</h3>
<p>Both classes and closures can enforce invariants at construction, ensuring no invalid instances exist.</p>
<p>Classes with constructors:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb20" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb20-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: Constructor validates invariants</span></span>
<span id="cb20-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentRequest <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-7"></span>
<span id="cb20-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentRequest</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-9">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Validation at construction</span></span>
<span id="cb20-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>cardNumber <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-11">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IllegalArgumentException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Invalid card number"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb20-12">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>cvv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-14">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IllegalArgumentException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Invalid CVV"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb20-15">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-16">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>amount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-17">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IllegalArgumentException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Amount must be positive"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb20-18">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>currency <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-20">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IllegalArgumentException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Currency required"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb20-21">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-22">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Cross-field validation</span></span>
<span id="cb20-23">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"USD"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">equals</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> amount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb20-24">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IllegalArgumentException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"USD transactions limited to $10,000"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb20-25">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-26"></span>
<span id="cb20-27">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cardNumber</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-28">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cvv</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-29">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">amount</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-30">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">currency</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb20-31">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb20-32"></span>
<span id="cb20-33">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// If this object exists, it's valid</span></span>
<span id="cb20-34"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Closures with factory functions:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb21" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb21-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Factory validates invariants</span></span>
<span id="cb21-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentRequest</span>(cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> currency) {</span>
<span id="cb21-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// All validation upfront</span></span>
<span id="cb21-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>cardNumber <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">16</span>) {</span>
<span id="cb21-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Invalid card number"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-6">    }</span>
<span id="cb21-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>cvv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">length</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>) {</span>
<span id="cb21-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Invalid CVV"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-9">    }</span>
<span id="cb21-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (amount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) {</span>
<span id="cb21-11">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Amount must be positive"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-12">    }</span>
<span id="cb21-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>currency) {</span>
<span id="cb21-14">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Currency required"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-15">    }</span>
<span id="cb21-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (currency <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"USD"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> amount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>) {</span>
<span id="cb21-17">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"USD transactions limited to $10,000"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-18">    }</span>
<span id="cb21-19"></span>
<span id="cb21-20">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb21-21">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCardNumber</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb21-22">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCVV</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> cvv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb21-23">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getAmount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb21-24">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCurrency</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> currency<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb21-25">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">submit</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> { <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* submit logic */</span> }</span>
<span id="cb21-26">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb21-27">}</span></code></pre></div></div>
<p>The fundamental similarity: both enforce “no invalid instances”—you cannot get a reference to an invalid object or closure. The difference is in how construction complexity is expressed. Objects use language constructs (constructors, builders, access modifiers). Closures use function composition (staged factories, validation functions).</p>
<p>One key difference: with classes, you can have partially constructed objects during constructor execution (before all fields initialized). With closures, the closure only exists after the factory returns—no “partial closure” state. This makes closures slightly safer: no “this-escape” problem where <code>this</code> reference leaks during construction.</p>
</section>
<section id="destruction-resource-cleanup" class="level3" data-number="13.2">
<h3 data-number="13.2" class="anchored" data-anchor-id="destruction-resource-cleanup"><span class="header-section-number">13.2</span> Destruction: Resource Cleanup</h3>
<p>Just as construction differs between objects and closures, so does destruction and resource cleanup.</p>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Resource acquisition</strong>: When resources (files, sockets, memory) are obtained</li>
<li><strong>Resource release</strong>: When resources must be cleaned up</li>
<li><strong>Lifecycle management</strong>: How to ensure cleanup happens reliably</li>
</ol>
<p>These vary independently—you might acquire resources at construction but need to release them at different times (immediately after use, after a delay, when the program exits).</p>
<p>Objects provide explicit cleanup mechanisms:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb22-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: try-with-resources (AutoCloseable interface)</span></span>
<span id="cb22-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> FileProcessor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> AutoCloseable <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb22-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">FileInputStream</span> file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb22-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BufferedReader</span> reader<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb22-5"></span>
<span id="cb22-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileProcessor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb22-7">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">file</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">FileInputStream</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb22-8">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reader</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">BufferedReader</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">InputStreamReader</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb22-9">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb22-10"></span>
<span id="cb22-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readLine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb22-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> reader<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readLine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb22-13">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb22-14"></span>
<span id="cb22-15">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Cleanup method - called automatically by try-with-resources</span></span>
<span id="cb22-16">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@Override</span></span>
<span id="cb22-17">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb22-18">        reader<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Close reader first</span></span>
<span id="cb22-19">        file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span>    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Then close file</span></span>
<span id="cb22-20">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">System</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">out</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">println</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Resources cleaned up"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb22-21">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb22-22"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb22-23"></span>
<span id="cb22-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: cleanup happens automatically</span></span>
<span id="cb22-25"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>FileProcessor processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileProcessor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data.txt"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb22-26">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> line <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readLine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb22-27">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Use the file...</span></span>
<span id="cb22-28"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// close() called automatically here, even if exception thrown</span></span></code></pre></div></div>
<p>Closures rely on language garbage collection or explicit cleanup functions:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb23-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Explicit cleanup function</span></span>
<span id="cb23-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeFileProcessor</span>(path) {</span>
<span id="cb23-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> file <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">openSync</span>(path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> closed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">false</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-5"></span>
<span id="cb23-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb23-7">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">readLine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb23-8">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (closed) <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'File already closed'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-9">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> fs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readFileSync</span>(file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'utf8'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">split</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-10">        }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb23-11">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">close</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> {</span>
<span id="cb23-12">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>closed) {</span>
<span id="cb23-13">                fs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">closeSync</span>(file)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-14">                closed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-15">                <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Resources cleaned up'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-16">            }</span>
<span id="cb23-17">        }</span>
<span id="cb23-18">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-19">}</span>
<span id="cb23-20"></span>
<span id="cb23-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: manual cleanup (no automatic try-with-resources)</span></span>
<span id="cb23-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeFileProcessor</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data.txt'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-23"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> {</span>
<span id="cb23-24">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> line <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readLine</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb23-25">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Use the file...</span></span>
<span id="cb23-26">} <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">finally</span> {</span>
<span id="cb23-27">    processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">close</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Must remember to call this</span></span>
<span id="cb23-28">}</span></code></pre></div></div>
<p>IVP insight: when resource acquisition and resource release vary independently, explicit cleanup mechanisms (destructors, disposable pattern, try-with-resources) help ensure resources are released even when exceptions occur. Classes have language support for this (AutoCloseable in Java, IDisposable in C#, destructors in C++). Closures require manual discipline or language-level support (defer in Go, RAII via scope guards).</p>
<p>For resource management, classes with explicit lifecycle methods generally provide better guarantees than closures, because the language can enforce cleanup patterns (try-with-resources, using statements).</p>
</section>
</section>
<section id="contract-enforcement-compile-time-versus-runtime" class="level2" data-number="14">
<h2 data-number="14" class="anchored" data-anchor-id="contract-enforcement-compile-time-versus-runtime"><span class="header-section-number">14</span> Contract Enforcement: Compile-Time versus Runtime</h2>
<section id="nominal-interfaces-compile-time-safety" class="level3" data-number="14.1">
<h3 data-number="14.1" class="anchored" data-anchor-id="nominal-interfaces-compile-time-safety"><span class="header-section-number">14.1</span> Nominal Interfaces: Compile-Time Safety</h3>
<p>In statically-typed languages with nominal type systems, interfaces provide compile-time contract enforcement:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb24-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: Interface contract enforced at compile-time</span></span>
<span id="cb24-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-3">    PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb24-4">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb24-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-6"></span>
<span id="cb24-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> CreditCardProcessor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> PaymentProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb24-9"></span>
<span id="cb24-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">CreditCardProcessor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-11">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cardNumber</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb24-12">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-13"></span>
<span id="cb24-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-15">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentResult</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"credit"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb24-16">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-17"></span>
<span id="cb24-18">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-19">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Credit Card"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb24-20">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-21"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-22"></span>
<span id="cb24-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// This won't compile - missing getMethodName()</span></span>
<span id="cb24-24"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> BrokenProcessor <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> PaymentProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-25">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb24-26">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentResult</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"broken"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">null</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb24-27">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb24-28">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ERROR: BrokenProcessor is not abstract and does not override getMethodName()</span></span>
<span id="cb24-29"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Closures in statically-typed functional languages use structural typing or module signatures:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode typescript code-with-copy"><code class="sourceCode typescript"><span id="cb25-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// TypeScript: Structural typing (duck typing with compile-time checking)</span></span>
<span id="cb25-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentProcessor {</span>
<span id="cb25-3">  <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">process</span>(amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">number</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentResult<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb25-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">string</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb25-5">}</span>
<span id="cb25-6"></span>
<span id="cb25-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCreditCardProcessor</span>(cardNumber<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">string</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentProcessor {</span>
<span id="cb25-8">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb25-9">    process<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({ method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'credit'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> card<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> cardNumber })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb25-10">    getMethodName<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Credit Card'</span></span>
<span id="cb25-11">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb25-12">}</span>
<span id="cb25-13"></span>
<span id="cb25-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// This won't compile - missing getMethodName()</span></span>
<span id="cb25-15"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeBrokenProcessor</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> PaymentProcessor {</span>
<span id="cb25-16">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb25-17">    process<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({ method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'broken'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> card<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">null</span> })</span>
<span id="cb25-18">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ERROR: Type '{ process: ... }' is not assignable to type 'PaymentProcessor'</span></span>
<span id="cb25-19">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Property 'getMethodName' is missing</span></span>
<span id="cb25-20">  }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb25-21">}</span></code></pre></div></div>
<p>TypeScript provides structural typing: if the object has the right shape (properties and methods), it satisfies the interface. No explicit <code>implements</code> declaration needed. But the compiler still catches violations at compile-time.</p>
<p>For most production code, compiler-enforced contracts provide significant advantages:</p>
<ul>
<li>Fail fast: Errors caught at compile-time, not runtime</li>
<li>Refactoring safety: Changing an interface breaks all non-compliant implementations immediately</li>
<li>Documentation: The interface is the contract—no ambiguity</li>
<li>Tooling support: IDEs provide autocomplete, refactoring, navigation</li>
<li>Team coordination: Explicit contracts prevent misunderstandings</li>
<li>Maintenance: Easy to see all implementations of an interface</li>
</ul>
</section>
<section id="runtime-contract-enforcement-in-dynamic-languages" class="level3" data-number="14.2">
<h3 data-number="14.2" class="anchored" data-anchor-id="runtime-contract-enforcement-in-dynamic-languages"><span class="header-section-number">14.2</span> Runtime Contract Enforcement in Dynamic Languages</h3>
<p>In dynamic languages like JavaScript (without TypeScript) or Python, there is no compile-time checking. If you want to enforce contracts, you must do it at runtime—it is not optional, it is the only way to catch contract violations.</p>
<p>Without runtime validation, contract violations fail silently or cause cryptic errors later:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb26-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: No compile-time checking means silent failures</span></span>
<span id="cb26-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span>(processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount) {</span>
<span id="cb26-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>(amount)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// What if processor.process doesn't exist?</span></span>
<span id="cb26-4">}</span>
<span id="cb26-5"></span>
<span id="cb26-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> brokenProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb26-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Missing process() method!</span></span>
<span id="cb26-8">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Broken'</span></span>
<span id="cb26-9">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb26-10"></span>
<span id="cb26-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// This fails at RUNTIME when process() is called</span></span>
<span id="cb26-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span>(brokenProcessor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// TypeError: processor.process is not a function</span></span>
<span id="cb26-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Error happens LATE - deep in execution, hard to debug</span></span></code></pre></div></div>
<p>The problem: the error happens far from where the broken object was created. You only discover the contract violation when you try to call the missing method.</p>
<p>The solution: runtime validation catches violations early, at construction time. Both objects and closures can enforce this:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb27-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Runtime contract validation for objects</span></span>
<span id="cb27-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentProcessor {</span>
<span id="cb27-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(implementation) {</span>
<span id="cb27-4">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Validate interface at construction time</span></span>
<span id="cb27-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">process</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span>) {</span>
<span id="cb27-6">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">TypeError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PaymentProcessor must have process() method'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-7">        }</span>
<span id="cb27-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">getMethodName</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span>) {</span>
<span id="cb27-9">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">TypeError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'PaymentProcessor must have getMethodName() method'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-10">        }</span>
<span id="cb27-11"></span>
<span id="cb27-12">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">implementation</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-13">    }</span>
<span id="cb27-14"></span>
<span id="cb27-15">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">process</span>(amount) {</span>
<span id="cb27-16">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">implementation</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>(amount)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-17">    }</span>
<span id="cb27-18"></span>
<span id="cb27-19">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span>() {</span>
<span id="cb27-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">implementation</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-21">    }</span>
<span id="cb27-22">}</span>
<span id="cb27-23"></span>
<span id="cb27-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: validation happens at construction</span></span>
<span id="cb27-25"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> validImpl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb27-26">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">success</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb27-27">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Credit Card'</span></span>
<span id="cb27-28">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-29"></span>
<span id="cb27-30"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentProcessor</span>(validImpl)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// OK</span></span>
<span id="cb27-31"></span>
<span id="cb27-32"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> invalidImpl <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb27-33">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">success</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> amount })</span>
<span id="cb27-34">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Missing getMethodName!</span></span>
<span id="cb27-35">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb27-36"></span>
<span id="cb27-37"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> badProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentProcessor</span>(invalidImpl)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Throws TypeError immediately</span></span></code></pre></div></div>
<p>With closures, you can do the same validation in factory functions:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb28-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Runtime contract validation for closures</span></span>
<span id="cb28-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentProcessor</span>(implementation) {</span>
<span id="cb28-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Validate interface before creating closure</span></span>
<span id="cb28-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">process</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span>) {</span>
<span id="cb28-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">TypeError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Implementation must have process() method'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb28-6">    }</span>
<span id="cb28-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">getMethodName</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span>) {</span>
<span id="cb28-8">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">TypeError</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Implementation must have getMethodName() method'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb28-9">    }</span>
<span id="cb28-10"></span>
<span id="cb28-11">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Return closure that delegates to validated implementation</span></span>
<span id="cb28-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb28-13">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (amount) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>(amount)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb28-14">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> implementation<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span>()</span>
<span id="cb28-15">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb28-16">}</span>
<span id="cb28-17"></span>
<span id="cb28-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usage: same validation</span></span>
<span id="cb28-19"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentProcessor</span>(validImpl)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// OK</span></span>
<span id="cb28-20"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> badProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePaymentProcessor</span>(invalidImpl)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Throws TypeError</span></span></code></pre></div></div>
<p>More sophisticated runtime validation uses proxy objects in JavaScript:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb29-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Proxy-based contract enforcement</span></span>
<span id="cb29-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createContractProxy</span>(obj<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> contract) {</span>
<span id="cb29-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Proxy</span>(obj<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {</span>
<span id="cb29-4">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">get</span>(target<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> prop) {</span>
<span id="cb29-5">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!</span>(prop <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> target)) {</span>
<span id="cb29-6">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Contract violation: missing property '</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>prop<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">'`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-7">            }</span>
<span id="cb29-8">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> contract[prop] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">===</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">typeof</span> target[prop] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'function'</span>) {</span>
<span id="cb29-9">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Contract violation: '</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>prop<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">' must be a function`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-10">            }</span>
<span id="cb29-11">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> target[prop]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-12">        }</span>
<span id="cb29-13">    })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-14">}</span>
<span id="cb29-15"></span>
<span id="cb29-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Define contract</span></span>
<span id="cb29-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> paymentProcessorContract <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb29-18">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Function</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb29-19">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getMethodName</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Function</span></span>
<span id="cb29-20">}<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-21"></span>
<span id="cb29-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Wrap implementation with contract checking</span></span>
<span id="cb29-23"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">createContractProxy</span>(</span>
<span id="cb29-24">    { <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (x) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> x }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb29-25">    paymentProcessorContract</span>
<span id="cb29-26">)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb29-27"></span>
<span id="cb29-28">processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// OK</span></span>
<span id="cb29-29">processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getMethodName</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ERROR: Contract violation: missing property 'getMethodName'</span></span></code></pre></div></div>
<p>Python has similar runtime contract enforcement through protocols (PEP 544) and type checking libraries.</p>
<p>IVP insight: the choice is not about computational power—both approaches are Turing-complete. It is about which change drivers matter:</p>
<ul>
<li>Safety and maintainability drive changes: Use compiler-enforced contracts (nominal interfaces)</li>
<li>Flexibility and rapid iteration drive changes: Structural typing may suffice</li>
</ul>
<p>For production systems, especially in teams, the safety and tooling benefits of compiler-enforced contracts usually outweigh the flexibility of structural typing. TypeScript’s popularity shows this: developers wanted JavaScript’s flexibility with compile-time safety.</p>
</section>
</section>
<section id="memory-and-performance-considerations" class="level2" data-number="15">
<h2 data-number="15" class="anchored" data-anchor-id="memory-and-performance-considerations"><span class="header-section-number">15</span> Memory and Performance Considerations</h2>
<section id="memory-shared-methods-versus-per-instance-functions" class="level3" data-number="15.1">
<h3 data-number="15.1" class="anchored" data-anchor-id="memory-shared-methods-versus-per-instance-functions"><span class="header-section-number">15.1</span> Memory: Shared Methods versus Per-Instance Functions</h3>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Instance quantity</strong>: How many instances you create</li>
<li><strong>Method complexity</strong>: How much code each method contains</li>
</ol>
<p>These vary independently—you might create thousands of simple instances or a few complex ones.</p>
<p>Classes share methods via prototype chain:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb30" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb30-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Class methods shared via prototype</span></span>
<span id="cb30-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Calculator {</span>
<span id="cb30-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span>(a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb30-4">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">subtract</span>(a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb30-5">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">multiply</span>(a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb30-6">}</span>
<span id="cb30-7"></span>
<span id="cb30-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Creating 1000 instances</span></span>
<span id="cb30-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> calculators <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Array</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">from</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Calculator</span>())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb30-10"></span>
<span id="cb30-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Memory: 1000 instances + 1 shared prototype with 3 methods</span></span>
<span id="cb30-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Each instance: ~small overhead (just prototype reference)</span></span>
<span id="cb30-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Methods: defined once, shared by all</span></span></code></pre></div></div>
<p>Closures create methods per instance:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb31" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb31-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// JavaScript: Closure methods created per instance</span></span>
<span id="cb31-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCalculator</span>() {</span>
<span id="cb31-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb31-4">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb31-5">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">subtract</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb31-6">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">multiply</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> (a<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> b) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> b</span>
<span id="cb31-7">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb31-8">}</span>
<span id="cb31-9"></span>
<span id="cb31-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Creating 1000 instances</span></span>
<span id="cb31-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> calculators <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Array</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">from</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">length</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span> }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCalculator</span>())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb31-12"></span>
<span id="cb31-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Memory: 1000 instances + 3000 function objects (3 methods × 1000 instances)</span></span>
<span id="cb31-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Each instance: contains its own function objects</span></span>
<span id="cb31-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Methods: duplicated for every instance</span></span></code></pre></div></div>
<p>IVP insight: when instance quantity and method complexity vary independently, classes provide better memory efficiency when you have many instances. Closures pay a per-instance cost for each captured function.</p>
<p>However, when closures capture unique state that differs per instance, they are not duplicating anything meaningful. The memory trade-off only matters when methods could be shared but are not.</p>
</section>
<section id="garbage-collection-closure-capture-can-retain-unnecessary-data" class="level3" data-number="15.2">
<h3 data-number="15.2" class="anchored" data-anchor-id="garbage-collection-closure-capture-can-retain-unnecessary-data"><span class="header-section-number">15.2</span> Garbage Collection: Closure Capture Can Retain Unnecessary Data</h3>
<p>Closures can retain variables across multiple methods:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb32" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb32-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeHandler</span>() {</span>
<span id="cb32-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> largeArray <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Array</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000000</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fill</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1M elements</span></span>
<span id="cb32-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> someData <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'needed'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb32-4"></span>
<span id="cb32-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb32-6">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// This closure only uses someData</span></span>
<span id="cb32-7">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">handleClick</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(someData)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb32-8"></span>
<span id="cb32-9">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// But THIS closure uses largeArray!</span></span>
<span id="cb32-10">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">processData</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> largeArray<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toUpperCase</span>())</span>
<span id="cb32-11">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb32-12">}</span>
<span id="cb32-13"></span>
<span id="cb32-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// largeArray MUST be kept in memory because processData needs it</span></span>
<span id="cb32-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Even if you never call processData!</span></span>
<span id="cb32-16"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> handler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeHandler</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p>Why this happens: when returning multiple closures, all closures share the same lexical environment. If any closure references <code>largeArray</code>, it must be retained for all closures, even those that do not use it.</p>
<p>Solution: create separate closures when possible or explicitly null out unused variables.</p>
<p>Classes do not have this issue—each method can access only the fields it actually uses:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb33" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb33-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Handler {</span>
<span id="cb33-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>() {</span>
<span id="cb33-3">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">largeArray</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Array</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000000</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fill</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'data'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb33-4">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">someData</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'needed'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb33-5">    }</span>
<span id="cb33-6"></span>
<span id="cb33-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">handleClick</span>() {</span>
<span id="cb33-8">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">console</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">someData</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Only accesses someData</span></span>
<span id="cb33-9">    }</span>
<span id="cb33-10"></span>
<span id="cb33-11">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">processData</span>() {</span>
<span id="cb33-12">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">largeArray</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span>(x <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toUpperCase</span>())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Only accesses largeArray</span></span>
<span id="cb33-13">    }</span>
<span id="cb33-14">}</span>
<span id="cb33-15"></span>
<span id="cb33-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Both fields exist, but GC can see which methods use which fields</span></span></code></pre></div></div>
<p>IVP insight: when method lifetimes and data lifetimes vary independently, classes provide finer-grained memory management. Closures capture entire lexical environments, which can retain data longer than necessary.</p>
</section>
<section id="performance-execution-speed" class="level3" data-number="15.3">
<h3 data-number="15.3" class="anchored" data-anchor-id="performance-execution-speed"><span class="header-section-number">15.3</span> Performance: Execution Speed</h3>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Instantiation frequency</strong>: How often you create new instances</li>
<li><strong>Method call frequency</strong>: How often you call methods on existing instances</li>
</ol>
<p>These vary independently—you might create instances once and call methods millions of times, or vice versa.</p>
<p>Modern JavaScript engines (V8, SpiderMonkey) are highly optimized:</p>
<ul>
<li>Prototype lookups are highly optimized: inline caching makes class methods fast</li>
<li>Closure captures are optimized: engines only capture variables actually referenced</li>
<li>Closure creation cost: creating functions per instance has overhead</li>
<li>No prototype sharing: more memory pressure on GC</li>
</ul>
<p>When this matters:</p>
<ul>
<li>Hot code paths (game loops, parsers, real-time systems): Classes may be faster</li>
<li>Many short-lived instances: Closure creation overhead accumulates</li>
<li>Normal application code: Difference is negligible (microseconds)</li>
</ul>
<p>IVP insight: when instantiation frequency and method call frequency vary independently, choose based on your bottleneck. Many instances with few calls favors classes (faster instantiation). Few instances with many calls means both perform similarly. Measure if uncertain.</p>
</section>
<section id="serialization-state-persistence" class="level3" data-number="15.4">
<h3 data-number="15.4" class="anchored" data-anchor-id="serialization-state-persistence"><span class="header-section-number">15.4</span> Serialization: State Persistence</h3>
<p>Change drivers:</p>
<ol type="1">
<li><strong>State persistence</strong>: Need to serialize and transfer state</li>
<li><strong>Behavior</strong>: Methods that operate on state</li>
</ol>
<p>These vary independently—you might need to save state to disk or send it over network while keeping behavior local.</p>
<p>Classes separate data from methods naturally:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb34" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb34-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Person {</span>
<span id="cb34-2">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">constructor</span>(name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> age) {</span>
<span id="cb34-3">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb34-4">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">age</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> age<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb34-5">    }</span>
<span id="cb34-6"></span>
<span id="cb34-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">greet</span>() { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Hi, I'm </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">name</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb34-8">}</span>
<span id="cb34-9"></span>
<span id="cb34-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> person <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Person</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Alice'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb34-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> json <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">JSON</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stringify</span>(person)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// {"name":"Alice","age":30}</span></span>
<span id="cb34-12"></span>
<span id="cb34-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Reconstruct with methods</span></span>
<span id="cb34-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> restored <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Object</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">assign</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Person</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">JSON</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">parse</span>(json))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb34-15">restored<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">greet</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Works!</span></span></code></pre></div></div>
<p>Closures cannot be serialized (captured scope is not serializable):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb35" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb35-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePerson</span>(name<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> age) {</span>
<span id="cb35-2">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb35-3">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">greet</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`Hi, I'm </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">${</span>name<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Closure captures 'name'</span></span>
<span id="cb35-4">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb35-5">}</span>
<span id="cb35-6"></span>
<span id="cb35-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> person <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makePerson</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Alice'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb35-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> json <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">JSON</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stringify</span>(person)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// {"greet":"() =&gt; `Hi, I'm ${name}`"} - BROKEN!</span></span>
<span id="cb35-9"></span>
<span id="cb35-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Cannot reconstruct - the closure's captured scope is lost</span></span></code></pre></div></div>
<p>When this matters:</p>
<ul>
<li>Need to persist state: Classes (with manual method reconstruction)</li>
<li>Need to send over network: Classes or plain data objects (not closures)</li>
<li>In-memory only: Closures work fine</li>
</ul>
<p>IVP insight: when state persistence and behavior vary independently, separate data (serializable) from behavior (functions or methods). Classes make this separation natural—state goes to JSON, behavior is reconstructed. Closures conflate the two, making serialization impossible. This independence drives the Command-Query Separation pattern.</p>
</section>
<section id="debugging-stack-traces" class="level3" data-number="15.5">
<h3 data-number="15.5" class="anchored" data-anchor-id="debugging-stack-traces"><span class="header-section-number">15.5</span> Debugging: Stack Traces</h3>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Runtime behavior</strong>: Correctness of code execution</li>
<li><strong>Developer experience</strong>: Debuggability and stack trace clarity</li>
</ol>
<p>These vary independently—code can work correctly but be difficult to debug.</p>
<p>Classes have clear names in stack traces:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb36" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb36-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentProcessor {</span>
<span id="cb36-2">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">process</span>() { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Payment failed'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb36-3">}</span>
<span id="cb36-4"></span>
<span id="cb36-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentProcessor</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb36-6">processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb36-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Error: Payment failed</span></span>
<span id="cb36-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//   at PaymentProcessor.process (file.js:3:15)  &lt;- Clear class name</span></span></code></pre></div></div>
<p>Closures may have anonymous functions:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb37" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb37-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> makeProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb37-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> { <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Payment failed'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> }</span>
<span id="cb37-3">})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb37-4"></span>
<span id="cb37-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> processor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeProcessor</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb37-6">processor<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb37-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Error: Payment failed</span></span>
<span id="cb37-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//   at process (file.js:2:20)  &lt;- Less context</span></span>
<span id="cb37-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//   at Object.process (file.js:2:14)  &lt;- Anonymous</span></span></code></pre></div></div>
<p>Solution: name your closures:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb38" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb38-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> makeProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> ({</span>
<span id="cb38-2">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">processPayment</span>() {  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Named function</span></span>
<span id="cb38-3">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Error</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Payment failed'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb38-4">    }</span>
<span id="cb38-5">})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb38-6"></span>
<span id="cb38-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Error: Payment failed</span></span>
<span id="cb38-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//   at processPayment (file.js:2:33)  &lt;- Clear name!</span></span></code></pre></div></div>
<p>IVP insight: when runtime behavior and developer experience vary independently, naming is a cross-cutting concern. Classes provide names automatically through syntax. Closures require discipline to add names—but when you do, debugging quality is comparable.</p>
</section>
</section>
<section id="concurrency-and-shared-state" class="level2" data-number="16">
<h2 data-number="16" class="anchored" data-anchor-id="concurrency-and-shared-state"><span class="header-section-number">16</span> Concurrency and Shared State</h2>
<p>Change drivers:</p>
<ol type="1">
<li><strong>State evolution</strong>: How data changes over time</li>
<li><strong>Concurrent access</strong>: Multiple threads or processes accessing the same data</li>
</ol>
<p>These vary independently—single-threaded code might become multi-threaded without changing the business logic.</p>
<p>Closures encourage immutability:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb39" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb39-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Closure with immutable state</span></span>
<span id="cb39-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(initial) {</span>
<span id="cb39-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> count <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> initial<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Private, mutable locally</span></span>
<span id="cb39-4"></span>
<span id="cb39-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb39-6">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++</span>count<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb39-7">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> count</span>
<span id="cb39-8">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb39-9">}</span>
<span id="cb39-10"></span>
<span id="cb39-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// No way to share state between instances - naturally isolated</span></span>
<span id="cb39-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> c1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb39-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> c2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb39-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// c1 and c2 cannot interfere with each other</span></span></code></pre></div></div>
<p>Classes can share mutable state:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb40" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb40-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Java: Shared mutable state (dangerous in concurrent contexts)</span></span>
<span id="cb40-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Counter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb40-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">static</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> sharedCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Shared across all instances!</span></span>
<span id="cb40-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> instanceCount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb40-5"></span>
<span id="cb40-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">synchronized</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb40-7">        sharedCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span>      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Race condition if not synchronized!</span></span>
<span id="cb40-8">        instanceCount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb40-9">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb40-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>In concurrent and parallel contexts, we observe different characteristics:</p>
<p><strong>Closures:</strong></p>
<ul>
<li><strong>Naturally isolated</strong>: each closure has its own scope</li>
<li><strong>Encourages immutability</strong>: captured variables can be treated as constants</li>
<li><strong>Easier to reason about</strong>: no shared state by default</li>
<li><strong>Cannot share</strong>: if you need shared state, you need external coordination</li>
</ul>
<p><strong>Classes:</strong></p>
<ul>
<li><strong>Can share state</strong>: static variables allow coordination</li>
<li><strong>Need synchronization</strong>: mutable shared state requires locks or atomics</li>
<li><strong>Harder to reason about</strong>: potential for race conditions</li>
</ul>
<p>Functional style with closures:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb41" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb41-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Immutable approach - return new state instead of mutating</span></span>
<span id="cb41-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">function</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(count) {</span>
<span id="cb41-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> {</span>
<span id="cb41-4">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">increment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(count <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Return new counter</span></span>
<span id="cb41-5">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">getCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> () <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">=&gt;</span> count</span>
<span id="cb41-6">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb41-7">}</span>
<span id="cb41-8"></span>
<span id="cb41-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> c1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">makeCounter</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb41-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> c2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> c1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">increment</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// New counter</span></span>
<span id="cb41-11">c1<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 0 (unchanged)</span></span>
<span id="cb41-12">c2<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCount</span>()<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 1 (new state)</span></span></code></pre></div></div>
<p>IVP insight: when state evolution and concurrent access vary independently, immutable closures provide safety by default—no shared mutable state means no race conditions. Classes with static mutable state require explicit synchronization. The independence means you can add concurrency later without changing single-threaded logic if you use immutable closures.</p>
</section>
<section id="language-design-implications" class="level2" data-number="17">
<h2 data-number="17" class="anchored" data-anchor-id="language-design-implications"><span class="header-section-number">17</span> Language Design Implications</h2>
<p>The “poor man’s” tension reveals deep differences in language philosophy.</p>
<p>Functional languages (Haskell, ML, Scheme):</p>
<ul>
<li>Primary abstraction: functions and closures</li>
<li>Objects: encoded via closures or modules</li>
<li>Strength: compositional, minimal boilerplate, first-class functions</li>
<li>Weakness: type relationships less explicit (unless using algebraic data types)</li>
</ul>
<p>Multi-paradigm languages (JavaScript, Python, Rust):</p>
<ul>
<li>Primary abstraction: both first-class</li>
<li>JavaScript: true closures with mutable capture, prototype-based objects</li>
<li>Python: closures with <code>nonlocal</code> for mutation, class-based OOP</li>
<li>Rust: closures with explicit capture modes (<code>move</code>, borrow), trait-based polymorphism</li>
<li>Strength: choose the right tool for the job</li>
<li>Weakness: more ways to do things means more decisions</li>
</ul>
<p>Change drivers:</p>
<ol type="1">
<li><strong>Language constraints</strong>: what abstractions the language provides as primitives</li>
<li><strong>Problem structure</strong>: what abstractions the problem naturally demands</li>
</ol>
<p>IVP insight on language design: the best language design provides both abstractions as first-class citizens, allowing developers to align their choice with their change drivers. When a language forces you to use only one abstraction, you end up with “poor man’s” implementations of the other.</p>
<p>Modern Java (8+) and C# have converged toward this ideal by adding first-class closures to traditionally class-based languages, though with more ceremony than languages designed for closures from the start.</p>
<p>The “poor man’s” phenomenon emerges when language constraints and problem structure vary independently—you have a problem that demands closures, but your language only provides classes (or vice versa). The best solution is language support for both, letting you choose based on your actual change drivers, not language limitations.</p>
</section>
<section id="the-decision-framework" class="level2" data-number="18">
<h2 data-number="18" class="anchored" data-anchor-id="the-decision-framework"><span class="header-section-number">18</span> The Decision Framework</h2>
<p>Here is a systematic framework for choosing between closures and classes:</p>
<ol type="1">
<li>Do I need behavioral variants?
<ul>
<li>Multiple types implementing same interface: Classes</li>
<li>Single behavior with configuration: Closures</li>
</ul></li>
<li>Do I need type relationships?
<ul>
<li>Inheritance, interfaces, abstract base classes: Classes</li>
<li>Just behavior and state, no hierarchy: Closures</li>
</ul></li>
<li>Do I need polymorphic substitution?
<ul>
<li>Different types used interchangeably: Classes</li>
<li>Always the same type: Closures</li>
</ul></li>
<li>How many methods operate on the state?
<ul>
<li>Multiple methods on shared state: Classes</li>
<li>Single operation or multiple independent operations: Closures</li>
</ul></li>
<li>Is the abstraction domain-significant?
<ul>
<li>Represents a domain entity or concept: Classes</li>
<li>Infrastructure or utility behavior: Closures</li>
</ul></li>
<li>What are your memory constraints?
<ul>
<li>Creating thousands of instances: Classes (shared methods via prototype)</li>
<li>Creating a few instances: Either works (memory difference negligible)</li>
</ul></li>
<li>Do you need serialization?
<ul>
<li>Need to persist or transfer state: Classes or plain data objects (not closures)</li>
<li>In-memory only: Either works</li>
</ul></li>
<li>Do you need dependency staging?
<ul>
<li>Multi-stage configuration: Closures with partial application</li>
<li>All dependencies upfront: Classes with constructor injection</li>
</ul></li>
<li>Is concurrency a concern?
<ul>
<li>Multi-threaded access: Closures with immutability (safer by default)</li>
<li>Single-threaded: Either works</li>
</ul></li>
<li>What does your language encourage?
<ul>
<li>Java, C#: Classes are first-class citizens (closures available but more ceremony)</li>
<li>JavaScript, Python: Both are first-class (choose based on problem)</li>
<li>Haskell, ML: Closures are natural (classes require encoding)</li>
</ul></li>
</ol>
<p>The key insight: do not choose based on dogma. Identify your change drivers, then select the abstraction that respects their independence.</p>
</section>
<section id="the-takeaway" class="level2" data-number="19">
<h2 data-number="19" class="anchored" data-anchor-id="the-takeaway"><span class="header-section-number">19</span> The Takeaway</h2>
<p>“Closures are a poor man’s objects” and “objects are a poor man’s closures” are both correct—in different contexts.</p>
<p>The Independent Variation Principle reveals when each is appropriate:</p>
<blockquote class="blockquote">
<p>When change drivers demand type relationships and behavioral variants, think in objects (implemented via classes, prototypes, and so on).</p>
<p>When change drivers demand stateful behavior without type hierarchy, think in closures (functions capturing context).</p>
</blockquote>
<p>Neither conceptual model is universally superior. Both are essential abstractions that excel in different scenarios.</p>
<p>The next time you model a problem with objects or classes, ask: do I need behavioral variety and type relationships, or am I just bundling state with a single operation?</p>
<p>The next time you model a problem with closures, ask: am I avoiding object-oriented patterns that would make my intent clearer, or would an object with multiple methods be artificial?</p>
<p>The answer guides you to the abstraction that respects your change drivers—and that is when code becomes maintainable, extensible, and genuinely well-designed.</p>
<hr>
</section>
<section id="references" class="level2" data-number="20">
<h2 data-number="20" class="anchored" data-anchor-id="references"><span class="header-section-number">20</span> References</h2>
<p>The opening koan is from:</p>
<p><strong>van Straaten, A. (2003). “RE: What’s so cool about Scheme?”</strong> LL1 mailing list discussion. https://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html</p>
<p>The koan brilliantly captures the paradoxical relationship between closures and objects, inspiring this IVP-based analysis of when each abstraction excels.</p>
<hr>
</section>
<section id="learn-more" class="level2" data-number="21">
<h2 data-number="21" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">21</span> Learn More</h2>
<p>This article applies the Independent Variation Principle framework from:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The IVP paper provides a unified framework for understanding why certain abstractions work and when to apply them.</p>
<hr>


</section>

 ]]></description>
  <category>languages</category>
  <category>architecture</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-12-04-closures-vs-objects-understanding-a-poor-mans-through-the-lens-of-ivp-105j.html</guid>
  <pubDate>Thu, 04 Dec 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Error Handling Through the Lens of the Independent Variation Principle</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-11-30-error-handling-through-the-lens-of-the-principle-of-independent-variation-2p5o.html</link>
  <description><![CDATA[ 





<p>I’ve been thinking about error handling lately—not the syntax debates or “which language does it best” arguments, but something more fundamental. What makes one approach <em>architecturally</em> better than another?</p>
<p>There’s one principle that gives you an objective basis for these decisions: the <strong>Independent Variation Principle (IVP)</strong>. Its structural formulation has four directives: every element has at least one change driver; each element is assigned every change driver whose knowledge it embodies; elements with different change driver assignments belong in distinct units; elements with the same change driver assignment belong in a single unit. Deceptively simple, but it tells you which design is technically superior—though context may still force a trade-off.</p>
<p>Let me show you what I mean by applying it to four error handling strategies.</p>
<section id="the-four-approaches" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-four-approaches"><span class="header-section-number">1</span> The Four Approaches</h2>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Return codes (C-style)</span></span>
<span id="cb1-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> read_file<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">const</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">char</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">char</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span> content<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(!</span>path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(!</span>exists<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Checked exceptions</span></span>
<span id="cb2-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">readFile</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">SecurityException</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// compiler forces you to handle these</span></span>
<span id="cb2-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Unchecked exceptions (Python, C#, Java RuntimeException)</span></span>
<span id="cb3-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> read_file(path):</span>
<span id="cb3-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># might raise FileNotFoundError, PermissionError...</span></span>
<span id="cb3-4">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># signature doesn't tell you</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode rust code-with-copy"><code class="sourceCode rust"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Result monad (Rust, Haskell; available via libraries in Java, C#, Python)</span></span>
<span id="cb4-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">fn</span> read_file(path<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">str</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Result</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">String</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> FileError<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// can't access the value without handling the Result</span></span>
<span id="cb4-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</section>
<section id="what-are-the-change-drivers" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-are-the-change-drivers"><span class="header-section-number">2</span> What Are the Change Drivers?</h2>
<p>IVP starts by asking: what are the <em>independent</em> reasons this code might change?</p>
<p>For error handling, I see three: - <strong>Error types evolve</strong> (new failure modes appear, old ones get removed) - <strong>Error handling logic changes</strong> (different recovery strategies) - <strong>Business logic changes</strong> (nothing to do with errors)</p>
<p>These are genuinely independent. Adding a new error type shouldn’t require touching business logic. Changing how you recover from network failures shouldn’t affect which errors exist.</p>
</section>
<section id="why-error-handling-strategies-must-vary-independently" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="why-error-handling-strategies-must-vary-independently"><span class="header-section-number">3</span> Why Error Handling Strategies Must Vary Independently</h2>
<p>This isn’t abstract. Consider the same business operation—“fetch user profile”—and the different ways you might handle its failure depending on context:</p>
<p><strong>Recovery strategies:</strong> - <strong>Retry with backoff</strong> — transient network failure, try again - <strong>Use cached/stale data</strong> — acceptable degradation - <strong>Return default value</strong> — the show must go on - <strong>Fail fast</strong> — no point continuing if this fails</p>
<p><strong>Observability strategies:</strong> - <strong>Log and continue</strong> — non-critical, just record it - <strong>Alert on-call</strong> — this needs human attention now - <strong>Increment metric</strong> — track for SLO dashboards - <strong>Trace correlation</strong> — attach to distributed trace</p>
<p><strong>Propagation strategies:</strong> - <strong>Absorb</strong> — don’t let callers know - <strong>Transform</strong> — convert to domain-specific error - <strong>Propagate as-is</strong> — let it bubble up - <strong>Circuit break</strong> — stop calling the failing service</p>
<p>In microservices, this gets more interesting. The same downstream failure might require: - <strong>Service A</strong>: retry 3 times, then return cached data (user-facing, latency-sensitive) - <strong>Service B</strong>: fail immediately, dead-letter the message (async job, correctness matters) - <strong>Service C</strong>: log warning, return partial result (aggregator, best-effort)</p>
<p>The business logic—“fetch user profile”—is identical. The error handling varies based on operational context, SLAs, and the role of each service. These concerns change for <em>different reasons</em> and at <em>different times</em>. IVP says: they must be separable.</p>
<p>So how do our four approaches fare?</p>
<table class="caption-top table">
<colgroup>
<col style="width: 13%">
<col style="width: 23%">
<col style="width: 23%">
<col style="width: 26%">
<col style="width: 13%">
</colgroup>
<thead>
<tr class="header">
<th>Change</th>
<th>Return Codes</th>
<th>Checked Exc.</th>
<th>Unchecked Exc.</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Add error type</td>
<td>Touch all callers</td>
<td>Update every <code>throws</code> clause up the stack</td>
<td>Nothing</td>
<td>Compiler warns on incomplete matches</td>
</tr>
<tr class="even">
<td>Remove error type</td>
<td>Silent—constants sit unused</td>
<td>Compilation errors (good!)</td>
<td>Nothing</td>
<td>Compilation errors (good!)</td>
</tr>
<tr class="odd">
<td>Change handling strategy</td>
<td>Scattered across callers</td>
<td>Restructure try-catch blocks</td>
<td>Can centralize</td>
<td>Swap one combinator</td>
</tr>
<tr class="even">
<td>Change business logic</td>
<td>Entangled with error checks</td>
<td>Buried in try blocks</td>
<td>Clean—just change it</td>
<td>Clean—just change it</td>
</tr>
</tbody>
</table>
<p>Let’s examine each change driver in detail.</p>
</section>
<section id="change-driver-1-error-types-evolve" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="change-driver-1-error-types-evolve"><span class="header-section-number">4</span> Change Driver 1: Error Types Evolve</h2>
<p>When you add a new error type, what happens?</p>
<p><strong>Checked exceptions</strong> create <em>coupling</em>—the <code>throws</code> clause is infectious:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// You add DatabaseException to this method...</span></span>
<span id="cb5-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">saveUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>User u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> DatabaseException</span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...and now this method needs updating...</span></span>
<span id="cb5-5"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">processRegistration</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Form f<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> DatabaseException</span>
<span id="cb5-6"></span>
<span id="cb5-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...and this one...</span></span>
<span id="cb5-8"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">handleRequest</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Request</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throws</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> DatabaseException</span>
<span id="cb5-9"></span>
<span id="cb5-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...all the way up the stack</span></span></code></pre></div></div>
<p>I’ve seen teams respond by catching and wrapping at every layer—defeating the whole purpose. Or worse, declaring <code>throws Exception</code> everywhere.</p>
<p><strong>Return codes</strong> fail silently. You add a new constant <code>-3</code>, but existing callers still only check for <code>-1</code> and <code>-2</code>. The new error propagates as garbage data.</p>
<p><strong>Unchecked exceptions</strong> hide the change entirely. Callers don’t know a new exception exists until it crashes at runtime.</p>
<p><strong>Result types</strong> propagate like unchecked exceptions—the <code>?</code> operator passes errors up without signature changes at intermediate layers. But unlike unchecked exceptions, the error is <em>visible in the type</em>. And when you add a new variant, the compiler flags every decision point (where you <code>match</code>), not the entire call chain. Best of both worlds: lightweight propagation, explicit handling.</p>
</section>
<section id="change-driver-2-handling-strategy-changes" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="change-driver-2-handling-strategy-changes"><span class="header-section-number">5</span> Change Driver 2: Handling Strategy Changes</h2>
<p>This is where the differences are starkest. Result types give you <em>combinators</em>—small functions that transform Results without unwrapping them. This lets you plug in different strategies at composition time.</p>
<p><strong>Same business logic, different recovery strategies:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode rust code-with-copy"><code class="sourceCode rust"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 1: Fail fast</span></span>
<span id="cb6-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 2: Return cached data on failure</span></span>
<span id="cb6-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb6-6">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>or_else(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>_<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> get_cached_user(id))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb6-7"></span>
<span id="cb6-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 3: Retry with backoff</span></span>
<span id="cb6-9"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb6-10">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>or_else(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>_<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> sleep(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> fetch_user(id) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>)</span>
<span id="cb6-11">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>or_else(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>_<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> sleep(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> fetch_user(id) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb6-12"></span>
<span id="cb6-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 4: Default value</span></span>
<span id="cb6-14"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb6-15">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>unwrap_or_else(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>_<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">User::</span>anonymous())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div></div>
<p><strong>Same business logic, different observability:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode rust code-with-copy"><code class="sourceCode rust"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Log and continue</span></span>
<span id="cb7-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb7-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>map_err(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">log::warn!</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"fetch failed: {e}"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb7-4"></span>
<span id="cb7-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Increment metric</span></span>
<span id="cb7-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb7-7">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>map_err(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">metrics::</span>increment(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"user_fetch_error"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb7-8"></span>
<span id="cb7-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Alert on-call (for critical paths)</span></span>
<span id="cb7-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb7-11">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>map_err(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">pagerduty::</span>alert(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"user fetch failed"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> e <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span></code></pre></div></div>
<p><strong>Same business logic, different propagation:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode rust code-with-copy"><code class="sourceCode rust"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Absorb error, return partial result</span></span>
<span id="cb8-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> profile <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>ok()</span>
<span id="cb8-3">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>map(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>u<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">Profile::</span>from(u))</span>
<span id="cb8-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>unwrap_or(<span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">Profile::</span>empty())<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb8-5"></span>
<span id="cb8-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Transform to domain error</span></span>
<span id="cb8-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)</span>
<span id="cb8-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>map_err(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span>e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">DomainError::</span>UserUnavailable(e))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span>
<span id="cb8-9"></span>
<span id="cb8-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Circuit breaker pattern</span></span>
<span id="cb8-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> circuit_breaker<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>call(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">||</span> fetch_user(id))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span></span></code></pre></div></div>
<p>The business logic—<code>fetch_user(id)</code>—never changes. The handling strategy is <em>composed around it</em>, not <em>interleaved with it</em>. You can swap strategies without touching the core operation.</p>
<p><strong>Now the same four strategies with exceptions:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 1: Fail fast</span></span>
<span id="cb9-2">User user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// throws, caller deals with it</span></span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 2: Return cached data on failure</span></span>
<span id="cb9-5">User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-7">    user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb9-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-9">    user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCachedUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb9-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 3: Retry with backoff</span></span>
<span id="cb9-13">User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-14"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-16">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-17">        user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb9-18">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-19">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-20">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(++</span>retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-21">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Thread</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sleep</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb9-22">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-23"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb9-24"></span>
<span id="cb9-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Strategy 4: Default value</span></span>
<span id="cb9-26">User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb9-27"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-28">    user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb9-29"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb9-30">    user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> User<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">anonymous</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb9-31"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Each strategy is a <em>different control flow structure</em>. Retry needs a while loop. Fallback needs a try-catch. Default needs a try-catch with assignment. They don’t compose—you rebuild from scratch.</p>
<p><strong>Combining strategies makes it worse</strong> (retry <em>then</em> fallback to cache):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb10-1">User user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-3"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-5">        user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-6">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-7">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-8">        retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb10-9">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-10">            <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-11">                user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getCachedUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-12">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb10-13">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>CacheException ce<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb10-14">                <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">throw</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">UserFetchException</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"all strategies failed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-15">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb10-16">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb10-17">        <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Thread</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sleep</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb10-18">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb10-19"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Compare to Result: <code>fetch_user(id).or_else(retry).or_else(retry).or_else(cache)</code>. The call to <code>fetchUser</code> is untouched in both, but with exceptions it’s buried in 20 lines of nested control flow.</p>
<p><strong>And with return codes</strong> (same strategy):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb11-1">User<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> NULL<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> result<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-3"></span>
<span id="cb11-4"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb11-5">    result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb11-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-7">    retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb11-8">    sleep_ms<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb11-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb11-10"></span>
<span id="cb11-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb11-12">    result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> get_cached_user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb11-13"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb11-14"></span>
<span id="cb11-15"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb11-16">    log_error<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"all strategies failed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb11-17">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> ERR_USER_FETCH<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-18"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Same story: <code>fetch_user</code> is untouched, but buried in conditionals. Every strategy change means rewriting the if-checks around it. And if you forget one check, the error silently propagates as garbage data.</p>
<p><strong>The difference isn’t just syntax.</strong> Result strategies compose <em>linearly</em>—you chain them. Exception strategies nest <em>hierarchically</em>—try-catch inside try-catch. Return code strategies scatter <em>conditionally</em>—if-checks everywhere.</p>
<p>Note what <em>doesn’t</em> change in any approach: the individual operations (<code>fetchUser</code>, <code>getCachedUser</code>) stay the same. The problem is the <em>composition</em>. With exceptions and return codes, how you combine operations is entangled with how you handle their failures. Want to add a third fallback? Restructure the whole block. Want to change retry count? Edit the same code that defines the operation sequence.</p>
<p>With Result, composition and strategy are separate concerns. <code>fetch_user(id).or_else(f).or_else(g)</code> reads as a pipeline where each combinator is independent. Swap <code>.or_else(cache)</code> for <code>.unwrap_or(default)</code> without touching the rest.</p>
</section>
<section id="change-driver-3-business-logic-changes" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="change-driver-3-business-logic-changes"><span class="header-section-number">6</span> Change Driver 3: Business Logic Changes</h2>
<p>What happens when you need to change the core operation itself—say, <code>fetch_user</code> now needs an extra parameter, or you’re replacing it with <code>fetch_user_v2</code>?</p>
<p><strong>Return codes</strong> force you to navigate through error-checking conditionals to find the actual call. The business logic is <em>entangled</em> with error handling:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb12-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Where's the actual operation? Buried here:</span></span>
<span id="cb12-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>retries <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb12-3">    result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span>user<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// &lt;-- find this among the noise</span></span>
<span id="cb12-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-5">    retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++;</span></span>
<span id="cb12-6">    sleep_ms<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> retries<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb12-7"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Checked exceptions</strong> bury your logic in try blocks. Low <em>cohesion</em>—the business operation and its error handling are interleaved:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb13-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb13-2">    user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fetchUser</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// &lt;-- the actual work</span></span>
<span id="cb13-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">break</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb13-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">catch</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">IOException</span> e<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb13-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// 10 lines of recovery logic</span></span>
<span id="cb13-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Unchecked exceptions</strong> and <strong>Result types</strong> both keep business logic clean. The operation stands alone:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode rust code-with-copy"><code class="sourceCode rust"><span id="cb14-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">let</span> user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(id)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">?;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// clear what's happening</span></span></code></pre></div></div>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1">user <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fetch_user(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">id</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># equally clear</span></span></code></pre></div></div>
<p>The difference: with Result, you <em>know</em> error handling exists somewhere in the chain. With unchecked exceptions, you’re trusting that someone, somewhere, handles it.</p>
</section>
<section id="the-scorecard" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-scorecard"><span class="header-section-number">7</span> The Scorecard</h2>
<p>How well does each approach let you vary the three concerns independently?</p>
<table class="caption-top table">
<colgroup>
<col style="width: 26%">
<col style="width: 24%">
<col style="width: 15%">
<col style="width: 19%">
<col style="width: 14%">
</colgroup>
<thead>
<tr class="header">
<th>Change Driver</th>
<th>Return Codes</th>
<th>Checked</th>
<th>Unchecked</th>
<th>Result monad</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Error types evolve</td>
<td>❌ silent failures</td>
<td>❌ infectious signatures</td>
<td>⚠️ invisible</td>
<td>✅ exhaustive matching</td>
</tr>
<tr class="even">
<td>Handling strategy changes</td>
<td>❌ rewrite conditionals</td>
<td>❌ restructure try-catch</td>
<td>⚠️ centralized but implicit</td>
<td>✅ swap combinators</td>
</tr>
<tr class="odd">
<td>Business logic changes</td>
<td>❌ entangled with checks</td>
<td>⚠️ buried in try blocks</td>
<td>✅ clean</td>
<td>✅ clean</td>
</tr>
</tbody>
</table>
</section>
<section id="applying-ivp" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="applying-ivp"><span class="header-section-number">8</span> Applying IVP</h2>
<p>Result types win not because of syntax or fashion, but because they respect how change actually works. Success and failure <em>are</em> independent concerns—they come from different stakeholders, evolve on different timelines, respond to different pressures. IVP says: separate them.</p>
<p>The deeper insight is that IVP is grounded in business reality. Change drivers aren’t technical abstractions—they’re product requirements, compliance updates, operational incidents, scaling demands. The business doesn’t care about your try-catch nesting. It cares that you can add circuit breakers before the next outage, or swap retry policies without a two-week refactor.</p>
<p>The only constant is change. Software that fights this reality accumulates friction. Software that embraces it—by separating what varies independently—stays malleable.</p>
<p>To apply IVP yourself:</p>
<ol type="1">
<li><p><strong>Identify the change drivers.</strong> What are the independent reasons this code might change? Not abstract categories—real forces. Who asks for these changes? How often? On what timeline?</p></li>
<li><p><strong>Trace the coupling.</strong> For each driver, what else has to change? If touching one concern ripples into another, you’ve coupled things that vary independently.</p></li>
<li><p><strong>Check cohesion.</strong> Is related code scattered? If what changes together lives in five different files, you’ve fragmented what should be grouped.</p></li>
<li><p><strong>Compare designs.</strong> The one that minimizes cross-concern coupling while keeping each concern cohesive is what IVP favors. That’s not opinion—it’s the design that will cost less to change.</p></li>
</ol>
<hr>
</section>
<section id="learn-more" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">9</span> Learn More</h2>
<p>This article is based on research from:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The IVP paper explores: - Formal derivation of SOLID principles from IVP - Mathematical framework for coupling and cohesion - The Knowledge Theorem (cohesion ↔︎ domain knowledge equivalence) - Extensions to functional programming, database design, and architectural patterns - Critical evaluation of coupling/cohesion metrics and their limitations</p>
<hr>
<p><em>What error handling strategy did your team land on? Did coupling pain drive that decision?</em></p>


</section>

 ]]></description>
  <category>engineering</category>
  <category>languages</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-11-30-error-handling-through-the-lens-of-the-principle-of-independent-variation-2p5o.html</guid>
  <pubDate>Sun, 30 Nov 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Cohesion Is About Knowledge: Why High Cohesion Makes Code Easier to Understand</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-11-25-cohesion-is-about-knowledge-why-high-cohesion-makes-code-easier-to-understand-11cf.html</link>
  <description><![CDATA[ 





<p>We’ve all heard that “high cohesion” is good. But what does cohesion actually <em>mean</em>?</p>
<p>Most definitions focus on the mechanics: “elements that belong together should be grouped together.” But this raises the question: how do we know what “belongs together”?</p>
<p>The answer lies in understanding cohesion as a <strong>knowledge organization principle</strong>.</p>
<section id="the-knowledge-perspective" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="the-knowledge-perspective"><span class="header-section-number">1</span> The Knowledge Perspective</h2>
<p>Here’s a more fundamental way to think about cohesion:</p>
<blockquote class="blockquote">
<p><strong>Cohesion is about grouping knowledge that changes for the same reason</strong></p>
</blockquote>
<p>Knowledge that varies together should be grouped together. Knowledge that varies independently should be separated.</p>
<p>When you have high cohesion, all the knowledge in a unit changes for <strong>one reason</strong>—driven by one change driver. When you have low cohesion, the knowledge in a unit changes for <strong>multiple independent reasons</strong>—driven by different, unrelated change drivers.</p>
<p>Let me show you what this means in practice.</p>
</section>
<section id="a-tale-of-scattered-knowledge" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="a-tale-of-scattered-knowledge"><span class="header-section-number">2</span> A Tale of Scattered Knowledge</h2>
<p>Consider this typical e-commerce order system:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Order <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">List</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>OrderItem<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> customerId<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> status<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">double</span> totalAmount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-6"></span>
<span id="cb1-7">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">addItem</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Product product<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> quantity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-8">        items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OrderItem</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>product<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> quantity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb1-9">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-10"></span>
<span id="cb1-11">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calculateTotal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-12">        totalAmount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-13">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>OrderItem item <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-14">            totalAmount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+=</span> item<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getPrice</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> item<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">getQuantity</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-15">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-16">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-17"></span>
<span id="cb1-18">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">applyDiscount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> discountCode<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-19">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Apply discount logic</span></span>
<span id="cb1-20">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-21"></span>
<span id="cb1-22">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generateInvoice</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-23">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Generate PDF invoice</span></span>
<span id="cb1-24">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-25"></span>
<span id="cb1-26">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sendConfirmationEmail</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-27">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Email logic</span></span>
<span id="cb1-28">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-29"></span>
<span id="cb1-30">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">updateInventory</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-31">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Inventory update logic</span></span>
<span id="cb1-32">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-33"></span>
<span id="cb1-34">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logToAnalytics</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-35">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Analytics logging</span></span>
<span id="cb1-36">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-37"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>This looks reasonable at first. But let’s analyze the <strong>knowledge</strong> required to understand this class.</p>
</section>
<section id="what-knowledge-do-you-need" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="what-knowledge-do-you-need"><span class="header-section-number">3</span> What Knowledge Do You Need?</h2>
<p>To understand the <code>Order</code> class, you need to know about:</p>
<ol type="1">
<li><strong>Order domain logic</strong> (items, totals, discounts)</li>
<li><strong>PDF generation</strong> (libraries, templates, formatting)</li>
<li><strong>Email systems</strong> (SMTP, templates, recipients)</li>
<li><strong>Inventory management</strong> (stock levels, reservations)</li>
<li><strong>Analytics systems</strong> (tracking, event formats)</li>
</ol>
<p>That’s <strong>five different areas of knowledge</strong>—and they change for <strong>completely different reasons</strong>:</p>
<ul>
<li>Order logic changes when <strong>business rules</strong> change</li>
<li>Invoice generation changes when <strong>document requirements</strong> change</li>
<li>Email changes when <strong>notification preferences</strong> change</li>
<li>Inventory changes when <strong>warehouse systems</strong> change</li>
<li>Analytics changes when <strong>tracking requirements</strong> change</li>
</ul>
<p>A developer working on discount logic shouldn’t need to understand PDF generation. A developer fixing email issues shouldn’t need to understand inventory systems.</p>
<p><strong>This is low cohesion.</strong> The knowledge is scattered across unrelated concerns.</p>
</section>
<section id="the-independent-variation-principle" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="the-independent-variation-principle"><span class="header-section-number">4</span> The Independent Variation Principle</h2>
<p>The <strong>Independent Variation Principle (IVP)</strong> states four directives:</p>
<blockquote class="blockquote">
<p><strong>IVP-1 (Element Admissibility):</strong> every element must be governed by at least one change driver.</p>
<p><strong>IVP-2 (Change Driver Assignment):</strong> assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</p>
<p><strong>IVP-3 (Unit Purity — Separation):</strong> elements governed by different change drivers belong in distinct units.</p>
<p><strong>IVP-4 (Unit Completeness — Unification):</strong> elements governed by the same change driver belong in a single unit.</p>
</blockquote>
<p>IVP provides a precise way to identify low cohesion:</p>
<blockquote class="blockquote">
<p><strong>When a module contains knowledge that varies for independent reasons, cohesion is low</strong></p>
</blockquote>
<section id="what-is-a-change-driver" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="what-is-a-change-driver"><span class="header-section-number">4.1</span> What Is a Change Driver?</h3>
<p>A <strong>change driver</strong> is a reason why code needs to change. The same concept appears in other design principles (Single Responsibility Principle, Common Closure Principle) under different names: “reason to change”, “actor”, “source of change”.</p>
<p>These terms are used interchangeably—they all refer to the same underlying concept.</p>
<p>Change drivers have these characteristics: - <strong>Independent triggers</strong>: They activate for different reasons at different times - <strong>Different stakeholders</strong>: Different people or teams decide when and how each driver triggers - <strong>Distinct knowledge domains</strong>: Each driver requires understanding different areas of expertise</p>
<p>For example: - <strong>Business rule changes</strong> are driven by product managers adjusting pricing, discounts, or validation rules - <strong>Infrastructure changes</strong> are driven by platform engineers optimizing databases or APIs - <strong>UI changes</strong> are driven by designers and frontend teams improving user experience</p>
<p>When multiple independent change drivers affect the same module, that module has low cohesion.</p>
<p>Let’s identify the <strong>independent change drivers</strong> in our <code>Order</code> class:</p>
</section>
<section id="business-rules" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="business-rules"><span class="header-section-number">4.2</span> 1. Business Rules</h3>
<ul>
<li>Discount calculations</li>
<li>Order validation</li>
<li>Tax calculations</li>
<li>Pricing logic</li>
</ul>
<p><strong>Stakeholder:</strong> Product managers, business analysts</p>
</section>
<section id="document-generation" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="document-generation"><span class="header-section-number">4.3</span> 2. Document Generation</h3>
<ul>
<li>PDF formatting</li>
<li>Invoice templates</li>
<li>Receipt layouts</li>
</ul>
<p><strong>Stakeholder:</strong> Design team, legal/compliance</p>
</section>
<section id="communication" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="communication"><span class="header-section-number">4.4</span> 3. Communication</h3>
<ul>
<li>Email templates</li>
<li>Notification timing</li>
<li>Delivery channels (email, SMS, push)</li>
</ul>
<p><strong>Stakeholder:</strong> Marketing, customer service</p>
</section>
<section id="warehouse-operations" class="level3" data-number="4.5">
<h3 data-number="4.5" class="anchored" data-anchor-id="warehouse-operations"><span class="header-section-number">4.5</span> 4. Warehouse Operations</h3>
<ul>
<li>Inventory tracking</li>
<li>Stock reservations</li>
<li>Fulfillment systems</li>
</ul>
<p><strong>Stakeholder:</strong> Logistics team</p>
</section>
<section id="data-analytics" class="level3" data-number="4.6">
<h3 data-number="4.6" class="anchored" data-anchor-id="data-analytics"><span class="header-section-number">4.6</span> 5. Data &amp; Analytics</h3>
<ul>
<li>Event tracking</li>
<li>Metrics collection</li>
<li>Reporting</li>
</ul>
<p><strong>Stakeholder:</strong> Data science team</p>
<p>These are <strong>five independent sources of change</strong>—different stakeholders, different reasons to change, different timelines.</p>
<p>When they’re all mixed in one class, <strong>every change forces you to understand all five concerns</strong>, even if you’re only modifying one.</p>
</section>
</section>
<section id="high-cohesion-grouping-knowledge-by-change-driver" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="high-cohesion-grouping-knowledge-by-change-driver"><span class="header-section-number">5</span> High Cohesion: Grouping Knowledge by Change Driver</h2>
<p>Now let’s reorganize so that each module contains <strong>only knowledge driven by one change driver</strong>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Change Driver 1: Business Rules</span></span>
<span id="cb2-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Contains knowledge that varies when business requirements change</span></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Order <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> OrderId id<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> CustomerId customerId<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">List</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span>OrderItem<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-7">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> Money totalAmount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> OrderStatus status<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-9"></span>
<span id="cb2-10">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">addItem</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Product product<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Quantity quantity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-11">        items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">add</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OrderItem</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>product<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> quantity<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb2-12">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recalculateTotal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-13">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-14"></span>
<span id="cb2-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">applyDiscount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>DiscountCode code<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> DiscountCalculator calculator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-16">        Money discount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> calculator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">calculate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> code<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-17">        totalAmount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> totalAmount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">subtract</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>discount<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-18">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-19"></span>
<span id="cb2-20">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">recalculateTotal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-21">        totalAmount <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> items<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stream</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb2-22">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>item <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-&gt;</span> item<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">subtotal</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">())</span></span>
<span id="cb2-23">            <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reduce</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Money<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ZERO</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Money<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span>add<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-24">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-25"></span>
<span id="cb2-26">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> OrderConfirmed <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">confirm</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-27">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validateCanConfirm</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-28">        status <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> OrderStatus<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">CONFIRMED</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-29">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OrderConfirmed</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-30">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-31"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-32"></span>
<span id="cb2-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Change Driver 2: Document Generation</span></span>
<span id="cb2-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Contains knowledge that varies when document requirements change</span></span>
<span id="cb2-35"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> InvoiceGenerator <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-36">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> PdfEngine pdfEngine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-37">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> InvoiceTemplate template<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-38"></span>
<span id="cb2-39">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> Invoice <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">generate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>Order order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-40">        InvoiceData data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> InvoiceData<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">from</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>order<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-41">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> pdfEngine<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">render</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>template<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-42">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-43"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-44"></span>
<span id="cb2-45"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Change Driver 3: Communication</span></span>
<span id="cb2-46"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Contains knowledge that varies when notification requirements change</span></span>
<span id="cb2-47"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> OrderNotifier <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-48">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> EmailService emailService<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-49">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> NotificationTemplates templates<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-50">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> CustomerRepository customerRepository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-51"></span>
<span id="cb2-52">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">OrderNotifier</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>EmailService emailService<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-53">                        NotificationTemplates templates<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-54">                        CustomerRepository customerRepository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-55">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">emailService</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> emailService<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-56">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">templates</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> templates<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-57">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">customerRepository</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> customerRepository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-58">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-59"></span>
<span id="cb2-60">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">notifyOrderConfirmed</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>OrderConfirmed event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-61">        Customer customer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> customerRepository<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">customerId</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb2-62">        Email email <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> templates<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderConfirmation</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> customer<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-63">        emailService<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>email<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-64">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-65"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-66"></span>
<span id="cb2-67"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Change Driver 4: Warehouse Operations</span></span>
<span id="cb2-68"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Contains knowledge that varies when warehouse systems change</span></span>
<span id="cb2-69"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> InventoryManager <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-70">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> InventoryRepository inventory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-71"></span>
<span id="cb2-72">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reserveStock</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>OrderConfirmed event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-73">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>OrderItem item <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">items</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">())</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-74">            inventory<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">reserve</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>item<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">productId</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(),</span> item<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantity</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">());</span></span>
<span id="cb2-75">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-76">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-77"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-78"></span>
<span id="cb2-79"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Change Driver 5: Data &amp; Analytics</span></span>
<span id="cb2-80"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Contains knowledge that varies when analytics requirements change</span></span>
<span id="cb2-81"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> OrderAnalytics <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-82">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> AnalyticsClient analytics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-83"></span>
<span id="cb2-84">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">trackOrderPlaced</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>OrderConfirmed event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-85">        analytics<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">track</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"order_placed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Map</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">of</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span></span>
<span id="cb2-86">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"order_id"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">orderId</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(),</span></span>
<span id="cb2-87">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"total_amount"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">totalAmount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(),</span></span>
<span id="cb2-88">            <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"item_count"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> event<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">itemCount</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb2-89">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span></span>
<span id="cb2-90">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-91"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Now each class is driven by <strong>exactly one change driver</strong>:</p>
<ul>
<li><code>Order</code> contains knowledge driven by <strong>business rule changes</strong></li>
<li><code>InvoiceGenerator</code> contains knowledge driven by <strong>document requirement changes</strong></li>
<li><code>OrderNotifier</code> contains knowledge driven by <strong>communication requirement changes</strong></li>
<li><code>InventoryManager</code> contains knowledge driven by <strong>warehouse system changes</strong></li>
<li><code>OrderAnalytics</code> contains knowledge driven by <strong>analytics requirement changes</strong></li>
</ul>
<p>This is high cohesion: <strong>one module, one change driver, one cohesive area of knowledge</strong>.</p>
</section>
<section id="the-benefits-of-high-cohesion" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="the-benefits-of-high-cohesion"><span class="header-section-number">6</span> The Benefits of High Cohesion</h2>
<section id="reduced-cognitive-load" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="reduced-cognitive-load"><span class="header-section-number">6.1</span> Reduced Cognitive Load</h3>
<p>When you need to understand discount logic, you <strong>only</strong> need to understand the <code>Order</code> class. You don’t need to know anything about PDFs, emails, or analytics.</p>
<p>When you need to change email templates, you <strong>only</strong> need to understand <code>OrderNotifier</code>. You don’t need to understand order pricing or inventory management.</p>
<p><strong>Each unit requires understanding only one area of knowledge.</strong></p>
</section>
<section id="localized-changes" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="localized-changes"><span class="header-section-number">6.2</span> Localized Changes</h3>
<p>Each change driver affects exactly one module: - Business rules → <code>Order</code> - Document requirements → <code>InvoiceGenerator</code> - Communication needs → <code>OrderNotifier</code> - Warehouse operations → <code>InventoryManager</code> - Analytics tracking → <code>OrderAnalytics</code></p>
<p><strong>Changes are localized to the relevant knowledge area.</strong></p>
</section>
<section id="independent-evolution" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="independent-evolution"><span class="header-section-number">6.3</span> Independent Evolution</h3>
<p>The PDF library can be upgraded without touching order logic. The analytics system can be replaced without touching email code. Order validation can be enhanced without touching inventory management.</p>
<p><strong>Each knowledge area evolves independently.</strong></p>
</section>
</section>
<section id="the-relationship-between-cohesion-knowledge-and-change-drivers" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-relationship-between-cohesion-knowledge-and-change-drivers"><span class="header-section-number">7</span> The Relationship Between Cohesion, Knowledge, and Change Drivers</h2>
<p>Here’s the key insight:</p>
<p><strong>High cohesion = Knowledge driven by one change driver is grouped together</strong></p>
<p><strong>Low cohesion = Knowledge driven by different change drivers is mixed together</strong></p>
<p>Or more precisely:</p>
<blockquote class="blockquote">
<p><strong>Cohesion measures how well a module’s knowledge aligns with a single change driver</strong></p>
</blockquote>
<p>This explains why high cohesion improves maintainability:</p>
<ol type="1">
<li><strong>Easier to understand</strong>: You only need to understand knowledge relevant to one change driver</li>
<li><strong>Easier to change</strong>: When a change driver triggers, you modify exactly one module</li>
<li><strong>Easier to test</strong>: Each module tests knowledge for one change driver in isolation</li>
<li><strong>Easier to parallelize work</strong>: Different teams own different change drivers and their corresponding modules</li>
</ol>
</section>
<section id="how-to-identify-low-cohesion" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="how-to-identify-low-cohesion"><span class="header-section-number">8</span> How to Identify Low Cohesion</h2>
<p>The key is identifying <strong>change drivers</strong>. Ask these questions about your classes/modules:</p>
<section id="what-are-the-change-drivers" class="level3" data-number="8.1">
<h3 data-number="8.1" class="anchored" data-anchor-id="what-are-the-change-drivers"><span class="header-section-number">8.1</span> 1. What are the change drivers?</h3>
<p>What are the different reasons this unit might change? - Business rule changes? - Technology/infrastructure changes? - Performance optimizations? - UI/UX changes? - Compliance/regulatory changes?</p>
<p>If there are multiple <strong>independent</strong> reasons to change, you have multiple change drivers → low cohesion.</p>
</section>
<section id="who-owns-each-change-driver" class="level3" data-number="8.2">
<h3 data-number="8.2" class="anchored" data-anchor-id="who-owns-each-change-driver"><span class="header-section-number">8.2</span> 2. Who owns each change driver?</h3>
<p>For each potential change, who decides when and how it happens? - Product managers (business rules)? - Platform team (infrastructure)? - Frontend team (UI/UX)? - DevOps (performance)? - Data team (analytics)?</p>
<p>Multiple stakeholders = multiple change drivers = low cohesion.</p>
</section>
<section id="what-knowledge-does-each-change-driver-require" class="level3" data-number="8.3">
<h3 data-number="8.3" class="anchored" data-anchor-id="what-knowledge-does-each-change-driver-require"><span class="header-section-number">8.3</span> 3. What knowledge does each change driver require?</h3>
<p>For each change driver, what do you need to understand to make that change? - When business rules change, do you need to understand PDF generation? - When document templates change, do you need to understand order validation? - When analytics requirements change, do you need to understand email delivery?</p>
<p>If one change driver forces you to understand knowledge from other change drivers, they’re inappropriately coupled → low cohesion.</p>
</section>
<section id="do-change-drivers-vary-independently" class="level3" data-number="8.4">
<h3 data-number="8.4" class="anchored" data-anchor-id="do-change-drivers-vary-independently"><span class="header-section-number">8.4</span> 4. Do change drivers vary independently?</h3>
<ul>
<li>Can business rules change without affecting document generation?</li>
<li>Can analytics requirements change without affecting inventory management?</li>
<li>Can notification preferences change without affecting order validation?</li>
</ul>
<p>If these vary independently but are in the same module → low cohesion.</p>
</section>
</section>
<section id="the-decision-framework" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="the-decision-framework"><span class="header-section-number">9</span> The Decision Framework</h2>
<p>When designing or refactoring code:</p>
<ol type="1">
<li><p><strong>Identify change drivers</strong>: What are the independent reasons this code might change?</p></li>
<li><p><strong>Map knowledge to change drivers</strong>: For each change driver, what knowledge varies when that driver triggers?</p>
<ul>
<li>Business rules → domain logic, validation, calculations</li>
<li>Document requirements → templates, formatting, PDF generation</li>
<li>Communication needs → email templates, notification channels</li>
<li>Infrastructure changes → databases, APIs, caching</li>
</ul></li>
<li><p><strong>Check independence</strong>: Do these change drivers vary independently?</p>
<ul>
<li>Different stakeholders?</li>
<li>Different timelines?</li>
<li>Different triggering events?</li>
<li>Can one change without affecting others?</li>
</ul></li>
<li><p><strong>If independent</strong> → Separate them</p>
<ul>
<li>Create one module per change driver</li>
<li>Each module contains only knowledge for its change driver</li>
<li>Use interfaces/events to coordinate between modules</li>
<li>Keep boundaries explicit</li>
</ul></li>
<li><p><strong>If dependent</strong> → Keep them together</p>
<ul>
<li>They represent the same change driver</li>
<li>They always change together</li>
<li>The knowledge forms a cohesive unit</li>
</ul></li>
</ol>
</section>
<section id="real-world-application" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="real-world-application"><span class="header-section-number">10</span> Real-World Application</h2>
<p>This knowledge-based view of cohesion helps explain many design principles:</p>
<section id="single-responsibility-principle" class="level3" data-number="10.1">
<h3 data-number="10.1" class="anchored" data-anchor-id="single-responsibility-principle"><span class="header-section-number">10.1</span> Single Responsibility Principle</h3>
<p>“A class should have only one reason to change” = “A class should be driven by exactly one change driver”</p>
</section>
<section id="separation-of-concerns" class="level3" data-number="10.2">
<h3 data-number="10.2" class="anchored" data-anchor-id="separation-of-concerns"><span class="header-section-number">10.2</span> Separation of Concerns</h3>
<p>“Separate different concerns” = “Separate knowledge driven by different change drivers”</p>
</section>
<section id="interface-segregation" class="level3" data-number="10.3">
<h3 data-number="10.3" class="anchored" data-anchor-id="interface-segregation"><span class="header-section-number">10.3</span> Interface Segregation</h3>
<p>“No client should depend on methods it doesn’t use” = “Don’t force clients to know about irrelevant knowledge”</p>
</section>
<section id="bounded-contexts-ddd" class="level3" data-number="10.4">
<h3 data-number="10.4" class="anchored" data-anchor-id="bounded-contexts-ddd"><span class="header-section-number">10.4</span> Bounded Contexts (DDD)</h3>
<p>“Separate contexts have separate models” = “Separate knowledge domains have separate representations”</p>
</section>
</section>
<section id="the-takeaway" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="the-takeaway"><span class="header-section-number">11</span> The Takeaway</h2>
<p>Stop thinking of cohesion as a vague “things that belong together” principle.</p>
<p>Start thinking of cohesion in terms of <strong>change drivers and knowledge</strong>:</p>
<blockquote class="blockquote">
<p><strong>Group knowledge driven by the same change driver. Separate knowledge driven by different change drivers.</strong></p>
</blockquote>
<p>When you do this: - <strong>Understanding</strong> becomes easier: each module contains knowledge for one change driver - <strong>Changes</strong> become localized: one change driver triggers changes in exactly one module - <strong>Testing</strong> becomes focused: each module tests knowledge for one change driver - <strong>Parallel work</strong> becomes natural: different teams own different change drivers</p>
<p>The next time you’re writing or reviewing code, ask yourself:</p>
<p><strong>“How many independent change drivers affect this module?”</strong></p>
<p>If the answer is more than one, you’ve found low cohesion.</p>
<p>Identify the change drivers. Separate the knowledge. One module per change driver.</p>
<p>Your future self (and your teammates) will thank you.</p>
<hr>
</section>
<section id="learn-more" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">12</span> Learn More</h2>
<p>This article applies insights from:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The IVP paper provides a mathematical framework for understanding when concerns should be separated or unified, offering a principled approach to cohesion.</p>
<hr>
<p><em>How do you identify low cohesion in your codebase? What strategies have worked for improving it? Share your experiences in the comments!</em></p>


</section>

 ]]></description>
  <category>design</category>
  <category>cohesion</category>
  <category>architecture</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-11-25-cohesion-is-about-knowledge-why-high-cohesion-makes-code-easier-to-understand-11cf.html</guid>
  <pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>The Independent Variation Principle as a Thought Framework</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-11-25-the-principle-of-independent-variation-as-a-thought-framework-4aaa.html</link>
  <description><![CDATA[ 





<p>Most developers have encountered design principles like SOLID, DRY, and Separation of Concerns. But have you ever wondered what unifies these principles? Or how to apply them systematically when facing a novel design decision?</p>
<p>The <strong>Independent Variation Principle (IVP)</strong> provides a unifying framework that explains why established design principles work and helps you reason through unfamiliar design challenges.</p>
<p>In this article, I’ll show you how to use IVP as a practical thought framework for making better architectural decisions.</p>
<section id="what-is-ivp" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="what-is-ivp"><span class="header-section-number">1</span> What is IVP?</h2>
<p>IVP can be expressed through three complementary formulations, each offering a different lens for reasoning about design:</p>
<section id="pattern-formulation" class="level3" data-number="1.1">
<h3 data-number="1.1" class="anchored" data-anchor-id="pattern-formulation"><span class="header-section-number">1.1</span> Pattern Formulation</h3>
<blockquote class="blockquote">
<p><strong>Separate elements that vary independently; unify elements that vary dependently.</strong></p>
</blockquote>
<p>This formulation focuses on <em>observable patterns</em>: do elements change together or separately? It’s most useful when you can observe co-change patterns through version control history.</p>
</section>
<section id="causal-formulation" class="level3" data-number="1.2">
<h3 data-number="1.2" class="anchored" data-anchor-id="causal-formulation"><span class="header-section-number">1.2</span> Causal Formulation</h3>
<blockquote class="blockquote">
<p><strong>Separate what varies for different causes; unite what varies for the same cause.</strong></p>
</blockquote>
<p>This formulation emphasizes <em>why</em> variation occurs—the underlying change drivers. It directly connects to terminology from classical principles: what the Single Responsibility Principle calls a “reason to change” is precisely a “cause” or “change driver” in IVP terms.</p>
</section>
<section id="structural-formulation" class="level3" data-number="1.3">
<h3 data-number="1.3" class="anchored" data-anchor-id="structural-formulation"><span class="header-section-number">1.3</span> Structural Formulation</h3>
<blockquote class="blockquote">
<p><strong>Separate elements governed by different change drivers into distinct units; unify elements governed by the same change driver within a single unit.</strong></p>
</blockquote>
<p>This formulation is the most precise and actionable. It explicitly connects the causal perspective (change drivers) to the structural outcome (how elements are grouped into units like classes, modules, or services). This is what IVP fundamentally prescribes: <strong>aligning system decomposition with causal structure</strong>. Concretely, it decomposes into four directives — element admissibility, change driver assignment, unit purity (separation), and unit completeness (unification) — which Step 4 applies.</p>
</section>
<section id="why-three-formulations" class="level3" data-number="1.4">
<h3 data-number="1.4" class="anchored" data-anchor-id="why-three-formulations"><span class="header-section-number">1.4</span> Why Three Formulations?</h3>
<p>These aren’t different principles—they’re complementary angles on the same insight:</p>
<ul>
<li>The <strong>pattern formulation</strong> is intuitive and easily remembered</li>
<li>The <strong>causal formulation</strong> helps identify <em>why</em> elements change</li>
<li>The <strong>structural formulation</strong> provides explicit guidance on <em>how</em> to organize code</li>
</ul>
<p>Use whichever formulation fits your current reasoning context. All three lead to the same architectural decisions.</p>
<p><strong>The core insight:</strong> Systems evade complexity growth when their structure aligns with the structure of change forces acting upon them.</p>
</section>
</section>
<section id="why-ivp-matters" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="why-ivp-matters"><span class="header-section-number">2</span> Why IVP Matters</h2>
<p>When independent concerns are tangled together, changes to one force modifications to the other. This coupling multiplies maintenance costs and increases the risk of unintended side effects.</p>
<p>IVP reveals a fundamental pattern:</p>
<ul>
<li><strong>When independent change drivers are separated → cohesion increases, coupling decreases</strong></li>
<li><strong>When independent change drivers are coupled → cohesion decreases, coupling increases</strong></li>
</ul>
<p>This isn’t just about inheritance vs composition or any single design pattern. IVP provides a systematic method for evaluating <strong>any</strong> design decision.</p>
</section>
<section id="the-ivp-thought-framework-5-steps" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-ivp-thought-framework-5-steps"><span class="header-section-number">3</span> The IVP Thought Framework: 5 Steps</h2>
<p>Here’s how to apply IVP to architectural decisions:</p>
<hr>
<p><strong>📋 Quick Reference: The 5-Step IVP Framework</strong></p>
<ol type="1">
<li><strong>Identify Elements</strong> - What code components are involved?</li>
<li><strong>Identify Change Drivers</strong> - Why would this code change?</li>
<li><strong>Assess Independence</strong> - Do drivers vary for different reasons?</li>
<li><strong>Apply IVP Directives</strong> - Admissibility, assignment, separation, unification</li>
<li><strong>Evaluate Options</strong> - Analyze coupling and cohesion</li>
</ol>
<hr>
<section id="step-1-identify-the-elements" class="level3" data-number="3.1">
<h3 data-number="3.1" class="anchored" data-anchor-id="step-1-identify-the-elements"><span class="header-section-number">3.1</span> Step 1: Identify the Elements</h3>
<p><strong>Elements</strong> are the atomic code components involved in your design decision: classes, functions, modules, files, services, or packages.</p>
<p><strong>Example:</strong> You’re designing a payment processing system. Your elements include: - <code>CreditCardPayment</code> class - <code>PayPalPayment</code> class - <code>TransactionLogger</code> class - <code>FraudDetector</code> class - <code>NotificationService</code> class</p>
</section>
<section id="step-2-identify-the-change-drivers" class="level3" data-number="3.2">
<h3 data-number="3.2" class="anchored" data-anchor-id="step-2-identify-the-change-drivers"><span class="header-section-number">3.2</span> Step 2: Identify the Change Drivers</h3>
<p>This is the most critical step. <strong>Change drivers</strong> (also called “reasons to change” or “concerns”) are the external forces that necessitate modifications.</p>
<p>Ask yourself: - <strong>Why would this code need to change?</strong> - <strong>Who requests these changes?</strong> - <strong>What different concerns are at play?</strong></p>
<p>Change drivers arise from diverse sources: - Business requirements (new features, competitive pressures) - Regulatory compliance (legal obligations, security mandates) - Technology evolution (framework updates, performance optimization) - Stakeholder needs (different users with distinct requirements)</p>
<p><strong>Example:</strong> In the payment system, you identify two change drivers:</p>
<ol type="1">
<li><strong>Payment Method Variety Driver</strong>
<ul>
<li>New payment methods emerge constantly (cryptocurrency, bank transfers, buy-now-pay-later)</li>
<li>Each method has unique validation rules and processing logic</li>
<li>Adding cryptocurrency should not require modifying credit card processing</li>
</ul></li>
<li><strong>Common Payment Infrastructure Driver</strong>
<ul>
<li>Cross-cutting concerns: logging, fraud detection, notifications</li>
<li>These evolve for different reasons: performance, security, observability</li>
<li>Improving fraud detection should not require modifying each payment method</li>
</ul></li>
</ol>
<p><strong>The key question:</strong> Do these drivers vary for the same reason or different reasons?</p>
</section>
<section id="step-3-assess-independence" class="level3" data-number="3.3">
<h3 data-number="3.3" class="anchored" data-anchor-id="step-3-assess-independence"><span class="header-section-number">3.3</span> Step 3: Assess Independence</h3>
<p>Determine whether your identified change drivers are <strong>independent</strong> or <strong>dependent</strong>.</p>
<p><strong>Change drivers are independent when they:</strong> - Serve different stakeholders (end users vs.&nbsp;database administrators) - Change at different rates (volatile UI trends vs.&nbsp;stable business rules) - Respond to different types of requirements (functional vs.&nbsp;performance vs.&nbsp;security) - Require different expertise (domain knowledge vs.&nbsp;infrastructure knowledge) - Operate at different abstraction levels (high-level policies vs.&nbsp;low-level mechanisms)</p>
<p><strong>Change drivers are dependent when they:</strong> - Represent a unified concept (always evolve together) - Respond to the same stakeholder or domain - Always require coordinated changes</p>
<p><strong>Example:</strong> Payment methods and infrastructure are <strong>independent</strong>: - Payment methods change for <strong>business reasons</strong> (new providers, regulations) - Infrastructure changes for <strong>technical reasons</strong> (performance, security) - They serve different stakeholders and require different expertise</p>
</section>
<section id="step-4-apply-ivp-directives" class="level3" data-number="3.4">
<h3 data-number="3.4" class="anchored" data-anchor-id="step-4-apply-ivp-directives"><span class="header-section-number">3.4</span> Step 4: Apply IVP Directives</h3>
<p>The structural formulation decomposes into four directives. The first two govern elements; the last two govern how elements group into units.</p>
<p><strong>IVP-1 — Element Admissibility.</strong> Every element must be governed by at least one change driver. An element with no change driver embodies no knowledge and should be removed.</p>
<p><strong>IVP-2 — Change Driver Assignment.</strong> Assign each element every change driver whose knowledge it embodies. A single-driver element is the design goal; a multi-driver element is legitimate only when it is <em>irreducible</em> — an adapter or boundary that cannot be split without losing its function.</p>
<p><strong>IVP-3 — Unit Purity (Separation).</strong> When change drivers are independent → separate them into different units.</p>
<p>This achieves <strong>low coupling</strong> between domains. Changes to one concern stay confined to its unit without propagating to unrelated concerns.</p>
<p><strong>IVP-4 — Unit Completeness (Unification).</strong> When elements share the same change driver → unify them in the same unit.</p>
<p>This achieves <strong>high cohesion</strong> within units. Related changes stay localized in one cohesive unit, making changes straightforward and complete.</p>
<p><strong>Example application:</strong></p>
<p>Since payment methods and infrastructure are <strong>independent</strong>, we should <strong>separate</strong> them:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Payment methods: domain abstraction (varies independently)</span></span>
<span id="cb1-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> PaymentMethod <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-3">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-4">    PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> CreditCardPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> PaymentMethod <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-8">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* Credit card validation */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* Credit card processing */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-11"></span>
<span id="cb1-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PayPalPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">implements</span> PaymentMethod <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* PayPal validation */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> PaymentResult <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* PayPal processing */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-15"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-16"></span>
<span id="cb1-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Infrastructure services (vary independently)</span></span>
<span id="cb1-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> TransactionLogger <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-19">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> details<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-20"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-21"></span>
<span id="cb1-22"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> FraudDetector <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-23">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">boolean</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">analyze</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PaymentMethod method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-24"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-25"></span>
<span id="cb1-26"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">interface</span> NotificationService <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-27">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> message<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-28"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-29"></span>
<span id="cb1-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Orchestration layer: composes independent concerns</span></span>
<span id="cb1-31"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> PaymentProcessor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-32">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> TransactionLogger logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-33">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> FraudDetector fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-34">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> NotificationService notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-35"></span>
<span id="cb1-36">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">PaymentProcessor</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>TransactionLogger logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-37">                           FraudDetector fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb1-38">                           NotificationService notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-39">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logger</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-40">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fraudDetector</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-41">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">notifier</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb1-42">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-43"></span>
<span id="cb1-44">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PaymentMethod method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-45">        method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-46">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>fraudDetector<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">analyze</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-47">            PaymentResult result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> method<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb1-48">            logger<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">log</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment processed: "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> result<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-49">            notifier<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">send</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment confirmation"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb1-50">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-51">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb1-52"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Benefits of separation:</strong> - ✅ <strong>Independent variation</strong>: Add new payment methods without touching infrastructure - ✅ <strong>High cohesion</strong>: Each class has one responsibility - ✅ <strong>Low coupling</strong>: Payment methods don’t depend on infrastructure details - ✅ <strong>Excellent testability</strong>: Test each concern in isolation</p>
</section>
<section id="step-5-evaluate-design-options" class="level3" data-number="3.5">
<h3 data-number="3.5" class="anchored" data-anchor-id="step-5-evaluate-design-options"><span class="header-section-number">3.5</span> Step 5: Evaluate Design Options</h3>
<p>Compare competing designs by analyzing how they affect coupling and cohesion:</p>
<p><strong>For each design option, ask:</strong></p>
<ol type="1">
<li><strong>Coupling analysis:</strong>
<ul>
<li>How many dependencies exist?</li>
<li>Do changes in one module force changes in another?</li>
<li>Can independent concerns vary without affecting each other?</li>
</ul></li>
<li><strong>Cohesion analysis:</strong>
<ul>
<li>Does each module address a single change driver?</li>
<li>Is related functionality unified in one location?</li>
<li>Can domain experts reason about their concern without understanding unrelated concerns?</li>
</ul></li>
</ol>
<p><strong>Example evaluation:</strong></p>
<p><strong>❌ Inheritance approach</strong> (couples independent drivers):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Payment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Infrastructure mixed with domain interface</span></span>
<span id="cb2-3">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logTransaction</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> details<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectFraud</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-5"></span>
<span id="cb2-6">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">final</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">process</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-7">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-8">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">detectFraud</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-9">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-10">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">logTransaction</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Payment processed"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-11">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-12"></span>
<span id="cb2-13">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">abstract</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-15"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-16"></span>
<span id="cb2-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> CreditCardPayment <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">extends</span> Payment <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-18">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">validate</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-19">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">protected</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">executePayment</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/* ... */</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Inherits all infrastructure methods</span></span>
<span id="cb2-21"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Problems:</strong> - ❌ Infrastructure changes force recompilation of all payment methods - ❌ Template method enforces rigid execution sequence - ❌ Low cohesion: payment logic mixed with infrastructure usage - ❌ Poor testability: cannot isolate payment logic from infrastructure</p>
<p><strong>✅ Composition approach</strong> (separates independent drivers): - Each class has a single responsibility - Infrastructure and payment methods vary independently - Explicit, controllable dependencies - Easy to test each concern in isolation</p>
</section>
</section>
<section id="real-world-application-immutability" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="real-world-application-immutability"><span class="header-section-number">4</span> Real-World Application: Immutability</h2>
<p>Let’s apply the framework to another design decision: mutable vs.&nbsp;immutable data structures.</p>
<section id="step-1-identify-elements" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="step-1-identify-elements"><span class="header-section-number">4.1</span> Step 1: Identify Elements</h3>
<ul>
<li>Data structures representing domain entities (e.g., <code>Customer</code>)</li>
<li>Methods that modify state</li>
<li>Code that accesses data concurrently</li>
</ul>
</section>
<section id="step-2-identify-change-drivers" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="step-2-identify-change-drivers"><span class="header-section-number">4.2</span> Step 2: Identify Change Drivers</h3>
<p>Two independent drivers:</p>
<ol type="1">
<li><p><strong>State Evolution Driver</strong>: Business requirements about what needs to change (updating addresses, incrementing counters)</p></li>
<li><p><strong>Concurrent Access Driver</strong>: Architectural requirements about how many components access data simultaneously (multiple threads, distributed systems)</p></li>
</ol>
</section>
<section id="step-3-assess-independence-1" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="step-3-assess-independence-1"><span class="header-section-number">4.3</span> Step 3: Assess Independence</h3>
<p>These drivers are <strong>independent</strong>: - State evolution responds to business logic requirements - Concurrent access responds to architectural/performance requirements - They serve different concerns and vary for different reasons</p>
</section>
<section id="step-4-apply-ivp-directives-1" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="step-4-apply-ivp-directives-1"><span class="header-section-number">4.4</span> Step 4: Apply IVP Directives</h3>
<p>Since the drivers are independent, IVP-3 (Unit Purity) directs us to <strong>separate</strong> them. Each element is single-driver, so IVP-1 (admissibility) and IVP-2 (assignment) are already satisfied.</p>
<p><strong>❌ Mutable structures</strong> (couple the drivers):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> Customer <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">private</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> address<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb3-3"></span>
<span id="cb3-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">updateAddress</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> newAddress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-5">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">synchronized</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Concurrency concern</span></span>
<span id="cb3-6">            <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">this</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">address</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> newAddress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Business logic concern</span></span>
<span id="cb3-7">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-8">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Problem:</strong> State evolution code must include synchronization logic. Changing concurrency patterns (adding readers, changing threading model) forces modifications to state evolution methods. <strong>Low cohesion</strong>: each method addresses multiple concerns simultaneously.</p>
<p><strong>✅ Immutable structures</strong> (decouple the drivers):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode java code-with-copy"><code class="sourceCode java"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">record</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Customer</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> address<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">public</span> Customer <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">updateAddress</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">String</span> newAddress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-3">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">Customer</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>newAddress<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Pure business logic</span></span>
<span id="cb4-4">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-5"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p><strong>Benefits:</strong> - <strong>State evolution logic</strong> is pure business logic—no synchronization needed - <strong>Concurrent access</strong> is inherently safe—immutable data needs no locks - <strong>High cohesion</strong>: transformation methods focus purely on business semantics - Changes to concurrency patterns don’t affect state transformation code</p>
</section>
<section id="step-5-evaluate" class="level3" data-number="4.5">
<h3 data-number="4.5" class="anchored" data-anchor-id="step-5-evaluate"><span class="header-section-number">4.5</span> Step 5: Evaluate</h3>
<p>Immutability achieves better independent variation for these change drivers, though it comes with trade-offs (performance cost, memory overhead). <strong>IVP doesn’t dictate absolute rules</strong>—it reveals the coupling/cohesion implications, letting you balance them against other concerns.</p>
</section>
</section>
<section id="the-deeper-pattern-coupling-cohesion-reciprocity" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-deeper-pattern-coupling-cohesion-reciprocity"><span class="header-section-number">5</span> The Deeper Pattern: Coupling ↔︎ Cohesion Reciprocity</h2>
<p>IVP reveals a fundamental reciprocal relationship:</p>
<p><strong>Reducing coupling between independent drivers → Increases cohesion within modules</strong></p>
<p><strong>Increasing coupling between independent drivers → Decreases cohesion within modules</strong></p>
<p>This isn’t coincidence—it’s intrinsic to IVP’s directives. When you separate independent concerns: - Each module can focus on one responsibility (high cohesion) - Modules don’t force changes on each other (low coupling)</p>
<p>When you couple independent concerns: - Each module mixes multiple responsibilities (low cohesion) - Changes ripple across module boundaries (high coupling)</p>
</section>
<section id="when-to-use-each-formulation" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="when-to-use-each-formulation"><span class="header-section-number">6</span> When to Use Each Formulation</h2>
<p>IVP’s three formulations serve different reasoning contexts. Choose the lens that best fits your current situation:</p>
<section id="use-the-pattern-formulation-when" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="use-the-pattern-formulation-when"><span class="header-section-number">6.1</span> Use the Pattern Formulation when:</h3>
<ul>
<li>You’re analyzing version control history and co-change patterns</li>
<li>You want to observe which elements change together over time</li>
<li>You’re doing empirical analysis of existing codebases</li>
<li>You need to communicate design concepts in the simplest terms</li>
</ul>
<p><strong>Ask:</strong> “Do these elements change together or separately?”</p>
</section>
<section id="use-the-causal-formulation-when" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="use-the-causal-formulation-when"><span class="header-section-number">6.2</span> Use the Causal Formulation when:</h3>
<ul>
<li>You understand your system’s evolution patterns</li>
<li>You can identify concrete stakeholders and their needs</li>
<li>You’re analyzing why modifications occur</li>
<li>You’re designing for a specific, known context</li>
<li>You need to connect to terminology from SRP and other principles</li>
</ul>
<p><strong>Ask:</strong> “What are the independent reasons this code will change?”</p>
</section>
<section id="use-the-structural-formulation-when" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="use-the-structural-formulation-when"><span class="header-section-number">6.3</span> Use the Structural Formulation when:</h3>
<ul>
<li>You’re making explicit decisions about module boundaries</li>
<li>You need to determine how to group classes into packages</li>
<li>You’re defining service boundaries in microservices</li>
<li>You’re organizing code into architectural layers</li>
<li>You want the most precise, actionable guidance</li>
</ul>
<p><strong>Ask:</strong> “Which change drivers govern these elements, and are they independent?”</p>
</section>
<section id="when-causal-analysis-is-unclear" class="level3" data-number="6.4">
<h3 data-number="6.4" class="anchored" data-anchor-id="when-causal-analysis-is-unclear"><span class="header-section-number">6.4</span> When Causal Analysis is Unclear</h3>
<p>If identifying change drivers proves difficult, fall back to coupling/cohesion analysis: - Evaluate whether a design choice increases or decreases coupling - Assess whether related functionality is unified or scattered - Observe whether modifications to one concern force changes to others</p>
<p><strong>Ask:</strong> “Does this design improve cohesion or reduce coupling?”</p>
<p>All three formulations—and the coupling/cohesion perspective—lead to the same architectural conclusions. Use whichever fits your current reasoning context and available information.</p>
</section>
</section>
<section id="practical-tips-for-applying-ivp" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="practical-tips-for-applying-ivp"><span class="header-section-number">7</span> Practical Tips for Applying IVP</h2>
<section id="study-version-control-history" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="study-version-control-history"><span class="header-section-number">7.1</span> 1. Study Version Control History</h3>
<p>The most reliable way to identify change drivers is examining actual change patterns:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Find files that frequently change together</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> log <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--name-only</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uniq</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-rn</span></span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Analyze commit history for a module</span></span>
<span id="cb5-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">git</span> log <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--oneline</span> path/to/module</span></code></pre></div></div>
<p>Co-change patterns reveal coupled change drivers. Files that change together likely serve the same concern.</p>
</section>
<section id="examine-issue-trackers" class="level3" data-number="7.2">
<h3 data-number="7.2" class="anchored" data-anchor-id="examine-issue-trackers"><span class="header-section-number">7.2</span> 2. Examine Issue Trackers</h3>
<p>Issues are categorized by type (feature, bug, security, performance). This categorization often reveals distinct change drivers: - Feature requests → Domain/business drivers - Performance issues → Infrastructure drivers - Security vulnerabilities → Cross-cutting security driver</p>
</section>
<section id="talk-to-stakeholders" class="level3" data-number="7.3">
<h3 data-number="7.3" class="anchored" data-anchor-id="talk-to-stakeholders"><span class="header-section-number">7.3</span> 3. Talk to Stakeholders</h3>
<p>Different stakeholders represent different change drivers: - Product managers → Business requirements - End users → UX/functional requirements - Operations teams → Performance/reliability requirements - Security teams → Security requirements - Compliance officers → Regulatory requirements</p>
</section>
<section id="look-for-linguistic-boundaries" class="level3" data-number="7.4">
<h3 data-number="7.4" class="anchored" data-anchor-id="look-for-linguistic-boundaries"><span class="header-section-number">7.4</span> 4. Look for Linguistic Boundaries</h3>
<p>Domain-Driven Design’s “ubiquitous language” helps identify domains. When terms have different meanings in different contexts, you’ve found a domain boundary—and likely distinct change drivers.</p>
</section>
<section id="consider-future-evolution" class="level3" data-number="7.5">
<h3 data-number="7.5" class="anchored" data-anchor-id="consider-future-evolution"><span class="header-section-number">7.5</span> 5. Consider Future Evolution</h3>
<p>Ask: “If X changes, what else must change?”</p>
<p>If changing X forces changes to Y, but they represent different concerns, you’ve found coupled independent drivers—an IVP violation.</p>
</section>
</section>
<section id="ivp-explains-other-principles" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="ivp-explains-other-principles"><span class="header-section-number">8</span> IVP Explains Other Principles</h2>
<p>One of IVP’s powers is explaining <strong>why</strong> established principles work:</p>
<section id="single-responsibility-principle-srp" class="level3" data-number="8.1">
<h3 data-number="8.1" class="anchored" data-anchor-id="single-responsibility-principle-srp"><span class="header-section-number">8.1</span> Single Responsibility Principle (SRP)</h3>
<p><em>“A class should have one reason to change”</em></p>
<p>IVP generalization: Separate elements that vary for different reasons. <strong>SRP is IVP applied at the class level.</strong></p>
</section>
<section id="dependency-inversion-principle-dip" class="level3" data-number="8.2">
<h3 data-number="8.2" class="anchored" data-anchor-id="dependency-inversion-principle-dip"><span class="header-section-number">8.2</span> Dependency Inversion Principle (DIP)</h3>
<p><em>“High-level policies should not depend on low-level details”</em></p>
<p>IVP explanation: Business rules and infrastructure technology are independent change drivers. DIP decouples them by introducing abstractions that allow each to vary independently.</p>
</section>
<section id="interface-segregation-principle-isp" class="level3" data-number="8.3">
<h3 data-number="8.3" class="anchored" data-anchor-id="interface-segregation-principle-isp"><span class="header-section-number">8.3</span> Interface Segregation Principle (ISP)</h3>
<p><em>“Clients should not depend on interfaces they don’t use”</em></p>
<p>IVP explanation: A “fat” interface couples multiple independent client needs (change drivers). When one client’s needs evolve, all clients are affected. Segregating interfaces decouples these independent drivers.</p>
</section>
<section id="openclosed-principle-ocp" class="level3" data-number="8.4">
<h3 data-number="8.4" class="anchored" data-anchor-id="openclosed-principle-ocp"><span class="header-section-number">8.4</span> Open/Closed Principle (OCP)</h3>
<p><em>“Open for extension, closed for modification”</em></p>
<p>IVP explanation: Abstractions succeed when they capture the stable intersection of multiple change drivers’ requirements, while implementations vary independently through extension.</p>
</section>
</section>
<section id="limitations-and-context" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="limitations-and-context"><span class="header-section-number">9</span> Limitations and Context</h2>
<p>IVP is powerful, but not absolute:</p>
<section id="ivp-doesnt-dictate-every-decision" class="level3" data-number="9.1">
<h3 data-number="9.1" class="anchored" data-anchor-id="ivp-doesnt-dictate-every-decision"><span class="header-section-number">9.1</span> IVP Doesn’t Dictate Every Decision</h3>
<p>Other concerns may sometimes override pure IVP optimization: - <strong>Performance requirements</strong> (denormalization for speed) - <strong>Security constraints</strong> (defense-in-depth may require duplication) - <strong>Deployment constraints</strong> (organizational boundaries) - <strong>Team structure</strong> (Conway’s Law considerations)</p>
</section>
<section id="identifying-change-drivers-is-hard" class="level3" data-number="9.2">
<h3 data-number="9.2" class="anchored" data-anchor-id="identifying-change-drivers-is-hard"><span class="header-section-number">9.2</span> Identifying Change Drivers is Hard</h3>
<p>This is the most challenging aspect of applying IVP. It requires: - Deep understanding of the domain - Historical analysis of how technology evolved - Empathy for different stakeholder perspectives - Recognition that change drivers aren’t always obvious</p>
<p>When in doubt, examine version history, issue trackers, and migration guides to identify recurring modification patterns.</p>
</section>
<section id="independence-isnt-binary" class="level3" data-number="9.3">
<h3 data-number="9.3" class="anchored" data-anchor-id="independence-isnt-binary"><span class="header-section-number">9.3</span> Independence Isn’t Binary</h3>
<p>Change drivers exist on a spectrum from completely independent to completely dependent. Exercise architectural judgment about the degree of independence.</p>
</section>
</section>
<section id="the-ivp-decision-framework" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="the-ivp-decision-framework"><span class="header-section-number">10</span> The IVP Decision Framework</h2>
<p>When facing any design decision, follow this checklist:</p>
<p><strong>1. Identify change drivers</strong> - What are the reasons this code will change? - Who requests these changes? - What different concerns are at play?</p>
<p><strong>2. Check independence</strong> - Do these drivers vary for different reasons? - Business vs.&nbsp;technical concerns? - Domain vs.&nbsp;infrastructure? - Different stakeholders?</p>
<p><strong>3. If independent → Prefer separation (IVP-3)</strong> - Create interfaces for each driver - Use dependency injection - Keep concerns in separate modules</p>
<p><strong>4. If dependent → Unification is appropriate (IVP-4)</strong> - They represent a unified concept - They always evolve together - Bring related code into one cohesive unit</p>
<p><strong>5. Evaluate trade-offs</strong> - How does each option affect coupling? - How does each option affect cohesion? - Are there overriding performance/security concerns? - What’s the cost of change for each approach?</p>
</section>
<section id="example-applying-ivp-to-database-normalization" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="example-applying-ivp-to-database-normalization"><span class="header-section-number">11</span> Example: Applying IVP to Database Normalization</h2>
<p>Let’s practice the framework one more time.</p>
<section id="step-1-elements" class="level3" data-number="11.1">
<h3 data-number="11.1" class="anchored" data-anchor-id="step-1-elements"><span class="header-section-number">11.1</span> Step 1: Elements</h3>
<ul>
<li>Database tables</li>
<li>Queries that read data</li>
<li>Queries that write data</li>
</ul>
</section>
<section id="step-2-change-drivers" class="level3" data-number="11.2">
<h3 data-number="11.2" class="anchored" data-anchor-id="step-2-change-drivers"><span class="header-section-number">11.2</span> Step 2: Change Drivers</h3>
<ol type="1">
<li><strong>Data Integrity Driver</strong>: Business rules about consistency, correctness, preventing anomalies</li>
<li><strong>Query Performance Driver</strong>: Response time requirements, read/write patterns</li>
<li><strong>Schema Evolution Driver</strong>: Adding fields, changing relationships</li>
</ol>
</section>
<section id="step-3-independence" class="level3" data-number="11.3">
<h3 data-number="11.3" class="anchored" data-anchor-id="step-3-independence"><span class="header-section-number">11.3</span> Step 3: Independence</h3>
<p>These drivers are largely <strong>independent</strong>: - Data integrity responds to business logic correctness concerns - Performance responds to user experience and scale concerns - Schema evolution responds to changing business requirements</p>
</section>
<section id="step-4-apply-ivp" class="level3" data-number="11.4">
<h3 data-number="11.4" class="anchored" data-anchor-id="step-4-apply-ivp"><span class="header-section-number">11.4</span> Step 4: Apply IVP</h3>
<p>This reveals why normalization works (and when it doesn’t):</p>
<p><strong>Normalization</strong> (high cohesion approach): - Groups related data by domain concept - Achieves high cohesion: each table represents one concept - Data integrity and schema evolution benefit - Query performance may suffer (joins required)</p>
<p><strong>Denormalization</strong> (performance optimization): - Couples data from multiple concepts for query speed - Reduces cohesion: tables mix multiple concerns - Query performance benefits - Data integrity and schema evolution become harder</p>
<p><strong>IVP guidance</strong>: Prefer normalization for the identified drivers (integrity, evolution), but consider denormalization when the performance driver dominates (high-traffic read paths, proven bottlenecks).</p>
<p><strong>CQRS/Event Sourcing</strong> (maximum separation): - Separate write models (optimized for integrity) from read models (optimized for performance) - Each model varies independently for its driver - Maximizes independent variation but adds complexity</p>
</section>
</section>
<section id="the-takeaway" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="the-takeaway"><span class="header-section-number">12</span> The Takeaway</h2>
<p>IVP provides a systematic thought framework for architectural decisions:</p>
<ol type="1">
<li><strong>Identify elements</strong> in your design</li>
<li><strong>Identify change drivers</strong> that force modifications</li>
<li><strong>Assess independence</strong> between drivers</li>
<li><strong>Apply IVP directives</strong>: verify admissibility and assignment (IVP-1, IVP-2), then separate by driver (IVP-3) and unify by driver (IVP-4)</li>
<li><strong>Evaluate options</strong> by analyzing coupling and cohesion</li>
</ol>
<p>The core insight is simple but profound:</p>
<blockquote class="blockquote">
<p><strong>Structure your system so independent concerns can vary independently</strong></p>
</blockquote>
<p>When you achieve this, changes stay localized, parallel development becomes possible, cognitive load decreases, and your system becomes genuinely evolvable.</p>
<p>The next time you face a design decision, pause and ask:</p>
<p><strong>“What are the independent change drivers, and does this design separate them?”</strong></p>
<p>If yes, you’re on the right path. If no, IVP shows you where coupling exists and how to reduce it.</p>
<hr>
</section>
<section id="learn-more" class="level2" data-number="13">
<h2 data-number="13" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">13</span> Learn More</h2>
<p>This article is based on research from:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The IVP paper explores this principle in depth, including: - The Knowledge Theorem (cohesion ↔︎ domain knowledge equivalence) - Formal derivation of SOLID principles from IVP - Detailed analysis of architectural patterns through the IVP lens - Critical evaluation of measurement approaches and limitations</p>
<hr>
<p><em>What design decisions have you reconsidered through the lens of independent change drivers? How do you identify change drivers in your systems? Share your experiences in the comments!</em></p>


</section>

 ]]></description>
  <category>design</category>
  <category>architecture</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-11-25-the-principle-of-independent-variation-as-a-thought-framework-4aaa.html</guid>
  <pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>The Unix Philosophy Was Right All Along: An IVP Analysis of 17 Timeless Rules</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-11-25-the-unix-philosophy-was-right-all-along-a-piv-analysis-of-17-timeless-rules-2l4l.html</link>
  <description><![CDATA[ 





<p>For over 50 years, the Unix philosophy has shaped how we build software. Its principles feel <em>right</em> in a way that transcends trends and languages. But why?</p>
<p>In “The Art of Unix Programming,” Eric Raymond distilled Unix wisdom into 17 rules. These aren’t arbitrary guidelines—they’re a coherent system based on one fundamental insight.</p>
<p>That insight is the <strong>Independent Variation Principle (IVP)</strong>.</p>
<p>Let me show you why Unix got it right, and why these rules still matter in 2025.</p>
<section id="what-is-the-unix-philosophy" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="what-is-the-unix-philosophy"><span class="header-section-number">1</span> What Is the Unix Philosophy?</h2>
<p>The Unix philosophy emerged from the design of Unix at Bell Labs in the 1970s. Its core tenets:</p>
<ul>
<li><strong>Write programs that do one thing well</strong></li>
<li><strong>Write programs that work together</strong></li>
<li><strong>Write programs that handle text streams, because that is a universal interface</strong></li>
</ul>
<p>These ideas evolved into 17 specific rules documented in Raymond’s “The Art of Unix Programming” (2003). Each rule captures a different aspect of good design.</p>
<p>But here’s the question: <strong>Why do these rules work?</strong></p>
</section>
<section id="what-is-ivp" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="what-is-ivp"><span class="header-section-number">2</span> What Is IVP?</h2>
<p>The <strong>Independent Variation Principle</strong> states:</p>
<blockquote class="blockquote">
<p><strong>Separate elements governed by different change drivers into distinct units; unify elements governed by the same change driver within a single unit.</strong></p>
</blockquote>
<p>Or more simply:</p>
<blockquote class="blockquote">
<p><strong>Separate what varies for different reasons; unite what varies for the same reason.</strong></p>
</blockquote>
<p>A <strong>change driver</strong> is a force that necessitates modifications: business requirements, user needs, technology evolution, performance constraints, regulatory compliance.</p>
<p><strong>IVP’s insight:</strong> Systems minimize maintenance cost when their structure aligns with the structure of change forces.</p>
<p>The structural formulation makes this checkable as four directives:</p>
<ul>
<li><strong>IVP-1 — Element Admissibility:</strong> every element must be governed by at least one change driver.</li>
<li><strong>IVP-2 — Change Driver Assignment:</strong> assign each element every change driver whose knowledge it embodies; a multi-driver element must be irreducible.</li>
<li><strong>IVP-3 — Unit Purity (Separation):</strong> elements with different driver assignments belong in different units.</li>
<li><strong>IVP-4 — Unit Completeness (Unification):</strong> elements with the same driver assignment belong in the same unit.</li>
</ul>
<p>When independent concerns are coupled, changes ripple unpredictably. When they’re separated, changes are localized.</p>
</section>
<section id="the-problem-why-does-software-rot" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-problem-why-does-software-rot"><span class="header-section-number">3</span> The Problem: Why Does Software Rot?</h2>
<p>Software degrades not because bits decay, but because <strong>reality changes</strong>:</p>
<ul>
<li>Business needs evolve</li>
<li>Technologies advance</li>
<li>Users demand new features</li>
<li>Performance requirements shift</li>
<li>Security threats emerge</li>
<li>Regulations change</li>
</ul>
<p><strong>The challenge:</strong> Structure software so these independent forces don’t interfere with each other.</p>
<p><strong>The Unix solution:</strong> The 17 rules are strategies for decoupling independent change drivers.</p>
<p>Let’s analyze each rule through the IVP lens.</p>
</section>
<section id="the-17-rules-a-ivp-analysis" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="the-17-rules-a-ivp-analysis"><span class="header-section-number">4</span> The 17 Rules: A IVP Analysis</h2>
<section id="rule-of-modularity-write-simple-parts-connected-by-clean-interfaces" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="rule-of-modularity-write-simple-parts-connected-by-clean-interfaces"><span class="header-section-number">4.1</span> 1. Rule of Modularity: Write simple parts connected by clean interfaces</h3>
<p><strong>The Rule:</strong> &gt; Write simple parts connected by clean interfaces.</p>
<p><strong>IVP Analysis:</strong></p>
<p>Modules separate code by <strong>purpose</strong>. Clean interfaces separate <strong>specification</strong> from <strong>implementation</strong>.</p>
<p><strong>Change drivers:</strong> - Module A’s internal logic (varies with A’s requirements) - Module B’s internal logic (varies with B’s requirements) - Interface contract (varies when coordination needs change)</p>
<p>These are <strong>independent</strong>. Module A’s implementation can change without affecting B, as long as the interface remains stable.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Direct application of IVP-3</strong> (Unit Purity — separation)</p>
<p>Modularity achieves <strong>low coupling</strong> by ensuring independent change drivers don’t interfere.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Each tool is a module with a clean interface (stdin/stdout)</span></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> access.log <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ERROR"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wc</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-l</span></span></code></pre></div></div>
<p>Each program varies independently—<code>grep</code>’s pattern matching logic doesn’t affect <code>wc</code>’s counting logic. The interface (text streams) remains stable even as implementations evolve.</p>
<hr>
</section>
<section id="rule-of-clarity-clarity-is-better-than-cleverness" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="rule-of-clarity-clarity-is-better-than-cleverness"><span class="header-section-number">4.2</span> 2. Rule of Clarity: Clarity is better than cleverness</h3>
<p><strong>The Rule:</strong> &gt; Clarity is better than cleverness.</p>
<p><strong>IVP Analysis:</strong></p>
<p>Code has multiple change drivers: 1. <strong>Functional requirements</strong> (what the code does) 2. <strong>Comprehension requirements</strong> (understanding what it does) 3. <strong>Modification requirements</strong> (changing what it does)</p>
<p>Clever code <strong>couples</strong> these drivers: optimizations that serve functional requirements often obscure comprehension, making modifications difficult.</p>
<p>Clear code <strong>decouples</strong> them: the code’s structure directly expresses intent, separating “what it does” from “how to understand it.”</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Optimizes for change driver alignment</strong></p>
<p>Clarity reduces the cognitive load required for the <strong>modification change driver</strong>—the dominant driver in long-lived code.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Clever (couples computation with bit manipulation tricks)</span></span>
<span id="cb2-2"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> isPowerOfTwo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!(</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">));</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Clear (separates intent from implementation)</span></span>
<span id="cb2-5"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> isPowerOfTwo<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> n<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-7">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-9">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-10"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>The clear version explicitly encodes the <strong>domain knowledge</strong> (powers of two are either 1, or repeatedly divisible by 2 until reaching 1), making modification requirements independent of clever optimization.</p>
<hr>
</section>
<section id="rule-of-composition-design-programs-to-be-connected-to-other-programs" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="rule-of-composition-design-programs-to-be-connected-to-other-programs"><span class="header-section-number">4.3</span> 3. Rule of Composition: Design programs to be connected to other programs</h3>
<p><strong>The Rule:</strong> &gt; Design programs to be connected to other programs.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Individual program functionality (varies per program) 2. Workflow requirements (varies with user tasks)</p>
<p>Monolithic programs <strong>couple</strong> these: adding a workflow requires modifying programs.</p>
<p>Composable programs <strong>decouple</strong> these: workflows combine existing programs without modification.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Applies IVP-3 at the system level</strong></p>
<p>Composition achieves <strong>independent variation</strong> of programs and workflows.</p>
<p><strong>Unix example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Workflow: Find largest files</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">du</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-a</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> 10</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Different workflow, same programs</span></span>
<span id="cb3-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">du</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-a</span> /var/log <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> 5</span></code></pre></div></div>
<p>The programs (<code>du</code>, <code>sort</code>, <code>head</code>) vary independently from workflows. New workflows emerge through recombination, not modification.</p>
<hr>
</section>
<section id="rule-of-separation-separate-policy-from-mechanism-separate-interfaces-from-engines" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="rule-of-separation-separate-policy-from-mechanism-separate-interfaces-from-engines"><span class="header-section-number">4.4</span> 4. Rule of Separation: Separate policy from mechanism; separate interfaces from engines</h3>
<p><strong>The Rule:</strong> &gt; Separate policy from mechanism; separate interfaces from engines.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. <strong>Policy</strong> (what decisions to make—business logic) 2. <strong>Mechanism</strong> (how to execute decisions—implementation) 3. <strong>Interface</strong> (how users interact—UX/API) 4. <strong>Engine</strong> (how work is performed—algorithms)</p>
<p>These vary <strong>independently</strong>: - Policies change with business requirements - Mechanisms change with technology evolution - Interfaces change with user needs - Engines change with performance requirements</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Multiple applications of IVP-3</strong></p>
<p>This rule explicitly names four independent change drivers and mandates their separation.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Policy: What to back up (defined in config file)</span></span>
<span id="cb4-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Mechanism: How to back up (rsync)</span></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Interface: Command-line flags</span></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Engine: rsync's delta-transfer algorithm</span></span>
<span id="cb4-5"></span>
<span id="cb4-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rsync</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-av</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--files-from</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>backup-policy.txt /source /dest</span></code></pre></div></div>
<p>You can change the backup policy (edit the file), upgrade rsync’s mechanism (update the binary), improve the interface (write a wrapper), or optimize the engine (compile rsync with new algorithms)—all independently.</p>
<hr>
</section>
<section id="rule-of-simplicity-design-for-simplicity-add-complexity-only-where-you-must" class="level3" data-number="4.5">
<h3 data-number="4.5" class="anchored" data-anchor-id="rule-of-simplicity-design-for-simplicity-add-complexity-only-where-you-must"><span class="header-section-number">4.5</span> 5. Rule of Simplicity: Design for simplicity; add complexity only where you must</h3>
<p><strong>The Rule:</strong> &gt; Design for simplicity; add complexity only where you must.</p>
<p><strong>IVP Analysis:</strong></p>
<p>Complexity couples change drivers. Every added feature increases the dependency surface: - More code means more reasons to change - More interactions mean more coupled change drivers - More abstraction layers mean more places where changes propagate</p>
<p><strong>Simplicity minimizes coupling</strong> by reducing the number of change drivers a component responds to.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Minimizes change driver count</strong></p>
<p>Simplicity is IVP optimization: fewer change drivers = fewer opportunities for coupling.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Complex: Couples multiple change drivers (caching, retry, logging, validation)</span></span>
<span id="cb5-2">Result fetch<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>URL url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Cache cache<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> RetryPolicy retry<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Logger log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> Validator val<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>cache<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>has<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> cache<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>get<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(!</span>val<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>isValid<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>error<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Invalid URL"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> ERROR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-5">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> i <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> retry<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>attempts<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">++)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-6">        Result r <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> httpGet<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-7">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>ok<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span> cache<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>put<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>info<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fetched"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-8">        log<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>warn<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Retry "</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> i<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-9">    <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-10">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> ERROR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb5-11"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-12"></span>
<span id="cb5-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Simple: One change driver (HTTP fetching)</span></span>
<span id="cb5-14">Result fetch<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>URL url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-15">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> httpGet<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>url<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb5-16"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Let composability handle caching, retry, logging separately</span></span></code></pre></div></div>
<p>The simple version has <strong>one change driver</strong> (HTTP protocol changes). Composition handles additional concerns independently.</p>
<hr>
</section>
<section id="rule-of-parsimony-write-a-big-program-only-when-it-is-clear-by-demonstration-that-nothing-else-will-do" class="level3" data-number="4.6">
<h3 data-number="4.6" class="anchored" data-anchor-id="rule-of-parsimony-write-a-big-program-only-when-it-is-clear-by-demonstration-that-nothing-else-will-do"><span class="header-section-number">4.6</span> 6. Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do</h3>
<p><strong>The Rule:</strong> &gt; Write a big program only when it is clear by demonstration that nothing else will do.</p>
<p><strong>IVP Analysis:</strong></p>
<p>A “big program” typically means <strong>many coupled change drivers</strong>: - More features = more business requirements - More features = more user needs - More features = more technical concerns</p>
<p>Large programs <strong>couple</strong> these because everything lives in one codebase with shared dependencies.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Minimizes forced coupling</strong></p>
<p>This rule says: don’t create coupling unless you’ve proven it’s unavoidable.</p>
<p><strong>Unix approach:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Many small programs (independent change drivers)</span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ls</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"\.txt$"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xargs</span> wc <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-l</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span></span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># vs. one big program with coupled change drivers</span></span>
<span id="cb6-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (file listing + pattern matching + counting + sorting all in one binary)</span></span></code></pre></div></div>
<p>Each small program responds to one change driver. The large program couples them all.</p>
<hr>
</section>
<section id="rule-of-transparency-design-for-visibility-to-make-inspection-and-debugging-easier" class="level3" data-number="4.7">
<h3 data-number="4.7" class="anchored" data-anchor-id="rule-of-transparency-design-for-visibility-to-make-inspection-and-debugging-easier"><span class="header-section-number">4.7</span> 7. Rule of Transparency: Design for visibility to make inspection and debugging easier</h3>
<p><strong>The Rule:</strong> &gt; Design for visibility to make inspection and debugging easier.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Program logic (varies with requirements) 2. Debugging requirements (varies with failure modes) 3. Monitoring requirements (varies with operational needs)</p>
<p>Opaque programs <strong>couple</strong> these: adding debugging requires modifying logic.</p>
<p>Transparent programs <strong>decouple</strong> these: state is visible without code changes.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Decouples operation from observation</strong></p>
<p>Transparency lets the debugging change driver vary independently from the logic change driver.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Transparent: intermediate results visible</span></span>
<span id="cb7-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> data.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ERROR"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wc</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-l</span></span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># You can inspect each stage:</span></span>
<span id="cb7-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> data.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Check input</span></span>
<span id="cb7-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> data.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ERROR"</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Check filtering</span></span>
<span id="cb7-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> data.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ERROR"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">wc</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-l</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Check output</span></span></code></pre></div></div>
<p>The logic (grep, wc) varies independently from inspection (you can observe without modifying code).</p>
<hr>
</section>
<section id="rule-of-robustness-robustness-is-the-child-of-transparency-and-simplicity" class="level3" data-number="4.8">
<h3 data-number="4.8" class="anchored" data-anchor-id="rule-of-robustness-robustness-is-the-child-of-transparency-and-simplicity"><span class="header-section-number">4.8</span> 8. Rule of Robustness: Robustness is the child of transparency and simplicity</h3>
<p><strong>The Rule:</strong> &gt; Robustness is the child of transparency and simplicity.</p>
<p><strong>IVP Analysis:</strong></p>
<p>This rule reveals a <strong>dependency relationship</strong> between change drivers: - Simplicity minimizes change drivers - Transparency decouples observation from logic - Together, they minimize <strong>unexpected interactions</strong> between change drivers</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Emergent property of IVP compliance</strong></p>
<p>Robustness emerges when change drivers are properly decoupled—failures in one area don’t cascade to others.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simple + Transparent = Robust</span></span>
<span id="cb8-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">! </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-q</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span> file.txt<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">then</span></span>
<span id="cb8-3">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Pattern not found"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;&amp;</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb8-4">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">exit</span> 1</span>
<span id="cb8-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">fi</span></span></code></pre></div></div>
<p>Simple logic (one grep, one test). Transparent failure (error message to stderr, non-zero exit). Robust: failures are isolated and visible.</p>
<hr>
</section>
<section id="rule-of-representation-fold-knowledge-into-data-so-program-logic-can-be-stupid-and-robust" class="level3" data-number="4.9">
<h3 data-number="4.9" class="anchored" data-anchor-id="rule-of-representation-fold-knowledge-into-data-so-program-logic-can-be-stupid-and-robust"><span class="header-section-number">4.9</span> 9. Rule of Representation: Fold knowledge into data so program logic can be stupid and robust</h3>
<p><strong>The Rule:</strong> &gt; Fold knowledge into data so program logic can be stupid and robust.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Domain knowledge (what the system knows—business rules, configurations) 2. Program logic (how the system operates—algorithms, control flow)</p>
<p>Complex logic <strong>couples</strong> these: domain knowledge is embedded in code, so domain changes require code changes.</p>
<p>Data-driven design <strong>decouples</strong> these: domain knowledge lives in data, logic is generic.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Applies IVP-3 via data/code separation</strong></p>
<p>This is <strong>the Knowledge Theorem</strong> from IVP: cohesion increases when knowledge is explicit and separated by change driver.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Knowledge in data (easily changed without code modification)</span></span>
<span id="cb9-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># File: mime-types.conf</span></span>
<span id="cb9-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">text/html</span>       html htm</span>
<span id="cb9-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">text/plain</span>      txt</span>
<span id="cb9-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">image/jpeg</span>      jpg jpeg</span>
<span id="cb9-6"></span>
<span id="cb9-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generic logic (never changes when new MIME types are added)</span></span>
<span id="cb9-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lookup_mime_type()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">{</span></span>
<span id="cb9-9">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ext</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$1</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb9-10">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-w</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$ext</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> mime-types.conf <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">awk</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{print $1}'</span></span>
<span id="cb9-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Domain knowledge (MIME types) varies independently from program logic (lookup algorithm). Adding MIME types doesn’t require code changes.</p>
<hr>
</section>
<section id="rule-of-least-surprise-in-interface-design-always-do-the-least-surprising-thing" class="level3" data-number="4.10">
<h3 data-number="4.10" class="anchored" data-anchor-id="rule-of-least-surprise-in-interface-design-always-do-the-least-surprising-thing"><span class="header-section-number">4.10</span> 10. Rule of Least Surprise: In interface design, always do the least surprising thing</h3>
<p><strong>The Rule:</strong> &gt; In interface design, always do the least surprising thing.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Interface behavior (how the program responds) 2. User expectations (mental models, conventions)</p>
<p>Surprising interfaces <strong>couple</strong> these: changes to behavior require retraining users, and vice versa.</p>
<p>Unsurprising interfaces <strong>decouple</strong> these: behavior aligns with expectations, so behavior can evolve within expected bounds without retraining.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Minimizes interface change driver coupling</strong></p>
<p>Following conventions separates “what this program does” from “how users expect it to work.”</p>
<p><strong>Unix convention:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Least surprise: all these tools accept stdin and produce stdout</span></span>
<span id="cb10-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> file.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uniq</span></span>
<span id="cb10-3"></span>
<span id="cb10-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Each tool follows the same conventions:</span></span>
<span id="cb10-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - Read from stdin if no file specified</span></span>
<span id="cb10-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - Write to stdout</span></span>
<span id="cb10-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - Errors to stderr</span></span>
<span id="cb10-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># - Exit 0 on success, non-zero on failure</span></span></code></pre></div></div>
<p>Users’ expectations (conventions) vary independently from each tool’s implementation.</p>
<hr>
</section>
<section id="rule-of-silence-when-a-program-has-nothing-surprising-to-say-it-should-say-nothing" class="level3" data-number="4.11">
<h3 data-number="4.11" class="anchored" data-anchor-id="rule-of-silence-when-a-program-has-nothing-surprising-to-say-it-should-say-nothing"><span class="header-section-number">4.11</span> 11. Rule of Silence: When a program has nothing surprising to say, it should say nothing</h3>
<p><strong>The Rule:</strong> &gt; When a program has nothing surprising to say, it should say nothing.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Success path (normal operation) 2. Failure path (error conditions) 3. Monitoring/logging (operational visibility)</p>
<p>Verbose programs <strong>couple</strong> these: normal operation produces output, making it hard to distinguish success from failure.</p>
<p>Silent-on-success programs <strong>decouple</strong> these: output signals exceptions, not normal operation.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Separates signal from noise</strong></p>
<p>Silence maximizes the <strong>independence</strong> of success path from monitoring—you monitor for output, not parse output to find problems.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Silent on success (IVP-compliant)</span></span>
<span id="cb11-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> file.txt backup.txt  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># No output = success</span></span>
<span id="cb11-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$?</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 0</span></span>
<span id="cb11-4"></span>
<span id="cb11-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Verbose on success (couples success/failure with monitoring)</span></span>
<span id="cb11-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cp</span> file.txt backup.txt  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Outputs "Copied successfully"</span></span>
<span id="cb11-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Now you must parse output to determine success</span></span></code></pre></div></div>
<p>In pipelines, silence prevents coupling: <code>cmd1 | cmd2 | cmd3</code> succeeds if there’s no error output.</p>
<hr>
</section>
<section id="rule-of-repair-when-you-must-fail-fail-noisily-and-as-soon-as-possible" class="level3" data-number="4.12">
<h3 data-number="4.12" class="anchored" data-anchor-id="rule-of-repair-when-you-must-fail-fail-noisily-and-as-soon-as-possible"><span class="header-section-number">4.12</span> 12. Rule of Repair: When you must fail, fail noisily and as soon as possible</h3>
<p><strong>The Rule:</strong> &gt; When you must fail, fail noisily and as soon as possible.</p>
<p><strong>IVP Analysis:</strong></p>
<p>This rule complements Rule 11. Together they establish: - <strong>Silence = success</strong> (no change driver is active) - <strong>Noise = failure</strong> (error change driver is active)</p>
<p><strong>Change drivers:</strong> 1. Normal operation (proceeds until failure) 2. Error handling (activates on failure)</p>
<p>Late/silent failures <strong>couple</strong> these: errors propagate, corrupting normal operation.</p>
<p>Early/noisy failures <strong>decouple</strong> these: errors trigger immediate handling, preventing corruption.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Localizes error change driver</strong></p>
<p>Early failure prevents error change drivers from contaminating other change drivers.</p>
<p><strong>Example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb12-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#!/bin/bash</span></span>
<span id="cb12-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">set</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-e</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fail immediately on error</span></span>
<span id="cb12-3"></span>
<span id="cb12-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Each command fails noisily and immediately</span></span>
<span id="cb12-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> /target/dir <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">||</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">exit</span> 1</span>
<span id="cb12-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span> file.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">||</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">exit</span> 1</span>
<span id="cb12-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">process_data</span> data.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">||</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">exit</span> 1</span></code></pre></div></div>
<p>Errors are isolated—a failure in <code>cd</code> doesn’t corrupt <code>process_data</code>.</p>
<hr>
</section>
<section id="rule-of-economy-programmer-time-is-expensive-conserve-it-in-preference-to-machine-time" class="level3" data-number="4.13">
<h3 data-number="4.13" class="anchored" data-anchor-id="rule-of-economy-programmer-time-is-expensive-conserve-it-in-preference-to-machine-time"><span class="header-section-number">4.13</span> 13. Rule of Economy: Programmer time is expensive; conserve it in preference to machine time</h3>
<p><strong>The Rule:</strong> &gt; Programmer time is expensive; conserve it in preference to machine time.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Development cost (programmer time) 2. Runtime cost (machine time)</p>
<p>Premature optimization <strong>couples</strong> these: code becomes harder to understand/modify (increases development cost) to save runtime cost.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Prioritizes dominant change driver</strong></p>
<p>This rule recognizes that <strong>development cost</strong> is the more frequent change driver—code changes more often than performance requirements.</p>
<p>Optimize for the <strong>dominant change driver</strong>.</p>
<p><strong>Unix example:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb13-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Optimized for programmer time (clear, simple)</span></span>
<span id="cb13-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span> . <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-name</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*.txt"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-exec</span> grep <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span> {} <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\;</span></span>
<span id="cb13-3"></span>
<span id="cb13-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Optimized for machine time (complex, faster)</span></span>
<span id="cb13-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span> . <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-name</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*.txt"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-print0</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xargs</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-0</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-P</span> 4 grep <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span></span></code></pre></div></div>
<p>The first version optimizes for clarity (development cost). The second optimizes for performance (machine cost). Unix prefers the first until profiling proves otherwise.</p>
<hr>
</section>
<section id="rule-of-generation-avoid-hand-hacking-write-programs-to-write-programs-when-you-can" class="level3" data-number="4.14">
<h3 data-number="4.14" class="anchored" data-anchor-id="rule-of-generation-avoid-hand-hacking-write-programs-to-write-programs-when-you-can"><span class="header-section-number">4.14</span> 14. Rule of Generation: Avoid hand-hacking; write programs to write programs when you can</h3>
<p><strong>The Rule:</strong> &gt; Avoid hand-hacking; write programs to write programs when you can.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Pattern specification (what to generate) 2. Repetitive implementation (code instances)</p>
<p>Manual coding <strong>couples</strong> these: changing the pattern requires editing every instance.</p>
<p>Code generation <strong>decouples</strong> these: changing the pattern modifies the generator, instances regenerate automatically.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Applies IVP-4</strong> (Unit Completeness — unification)</p>
<p>Generated code varies <strong>dependently</strong>—it should come from one source (the generator).</p>
<p><strong>Unix examples:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate C code from parser specification</span></span>
<span id="cb14-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">yacc</span> grammar.y  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generates parser code</span></span>
<span id="cb14-3"></span>
<span id="cb14-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate config files from templates</span></span>
<span id="cb14-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> host <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> web<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">{</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">..</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">}</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span></span>
<span id="cb14-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sed</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s/HOSTNAME/</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$host</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/g"</span> template.conf <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$host</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">.conf"</span></span>
<span id="cb14-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">done</span></span></code></pre></div></div>
<p>The pattern (grammar, template) varies independently from the instances (generated code, config files).</p>
<hr>
</section>
<section id="rule-of-optimization-prototype-before-polishing.-get-it-working-before-you-optimize-it" class="level3" data-number="4.15">
<h3 data-number="4.15" class="anchored" data-anchor-id="rule-of-optimization-prototype-before-polishing.-get-it-working-before-you-optimize-it"><span class="header-section-number">4.15</span> 15. Rule of Optimization: Prototype before polishing. Get it working before you optimize it</h3>
<p><strong>The Rule:</strong> &gt; Prototype before polishing. Get it working before you optimize it.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Functional correctness (does it work?) 2. Performance characteristics (is it fast?)</p>
<p>Premature optimization <strong>couples</strong> these: optimization complicates correctness.</p>
<p>Sequential development <strong>decouples</strong> these: first solve correctness, then optimize (if needed).</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Sequences change drivers</strong></p>
<p>This rule recognizes that change drivers have <strong>dependencies</strong>: correctness must be solved before performance can be meaningfully addressed.</p>
<p><strong>Workflow:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb15-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1. Prototype (optimize for correctness)</span></span>
<span id="cb15-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span> huge-file.txt <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pattern"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uniq</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span></span>
<span id="cb15-3"></span>
<span id="cb15-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. Measure (is performance a problem?)</span></span>
<span id="cb15-5"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">time</span> ./script.sh  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Takes 2 seconds—acceptable</span></span>
<span id="cb15-6"></span>
<span id="cb15-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 3. Optimize only if needed (if it took 2 hours)</span></span>
<span id="cb15-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Use faster tools, parallelization, etc.</span></span></code></pre></div></div>
<p>Correctness varies independently from performance—solve them in sequence, not simultaneously.</p>
<hr>
</section>
<section id="rule-of-diversity-distrust-all-claims-for-one-true-way" class="level3" data-number="4.16">
<h3 data-number="4.16" class="anchored" data-anchor-id="rule-of-diversity-distrust-all-claims-for-one-true-way"><span class="header-section-number">4.16</span> 16. Rule of Diversity: Distrust all claims for “one true way”</h3>
<p><strong>The Rule:</strong> &gt; Distrust all claims for “one true way”.</p>
<p><strong>IVP Analysis:</strong></p>
<p>Different contexts have <strong>different change drivers</strong>: - Embedded systems: memory/power constraints - Web services: latency/throughput - Scientific computing: numerical accuracy - Databases: consistency/availability</p>
<p>A “one true way” <strong>couples</strong> solutions across contexts with <strong>independent change drivers</strong>.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Recognizes context-dependent change drivers</strong></p>
<p>This rule is meta-IVP: it acknowledges that change driver structure varies by context.</p>
<p><strong>Unix diversity:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb16-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Multiple shells (different user needs)</span></span>
<span id="cb16-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sh</span>, bash, zsh, fish</span>
<span id="cb16-3"></span>
<span id="cb16-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Multiple editors (different workflows)</span></span>
<span id="cb16-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vi</span>, emacs, nano</span>
<span id="cb16-6"></span>
<span id="cb16-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Multiple languages (different problem domains)</span></span>
<span id="cb16-8"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">C,</span> Python, Perl, AWK</span></code></pre></div></div>
<p>Each tool optimizes for <strong>different change drivers</strong>. Forcing “one true shell” would couple independent user needs.</p>
<hr>
</section>
<section id="rule-of-extensibility-design-for-the-future-because-it-will-be-here-sooner-than-you-think" class="level3" data-number="4.17">
<h3 data-number="4.17" class="anchored" data-anchor-id="rule-of-extensibility-design-for-the-future-because-it-will-be-here-sooner-than-you-think"><span class="header-section-number">4.17</span> 17. Rule of Extensibility: Design for the future, because it will be here sooner than you think</h3>
<p><strong>The Rule:</strong> &gt; Design for the future, because it will be here sooner than you think.</p>
<p><strong>IVP Analysis:</strong></p>
<p><strong>Change drivers:</strong> 1. Current requirements (known today) 2. Future requirements (anticipated)</p>
<p>Inflexible design <strong>couples</strong> these: future requirements force rewrites.</p>
<p>Extensible design <strong>decouples</strong> these: new requirements extend existing systems without breaking them.</p>
<p><strong>IVP verdict:</strong> ✅ <strong>Optimizes for unknown future change drivers</strong></p>
<p>Extensibility is IVP applied across time: separate today’s concerns from tomorrow’s.</p>
<p><strong>Unix extensibility mechanisms:</strong></p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb17-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 1. Pipes (extend workflows without modifying programs)</span></span>
<span id="cb17-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ls</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sort</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uniq</span></span>
<span id="cb17-3"></span>
<span id="cb17-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 2. Scripting (extend functionality by combining primitives)</span></span>
<span id="cb17-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> f <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span>.txt<span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">do</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">convert_format</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$f</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">;</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">done</span></span>
<span id="cb17-6"></span>
<span id="cb17-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># 3. Configuration (extend behavior via data)</span></span>
<span id="cb17-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> patterns.txt input.txt</span></code></pre></div></div>
<p>Each mechanism allows <strong>future change drivers</strong> to be accommodated without modifying existing programs.</p>
<hr>
</section>
</section>
<section id="the-pattern-is-clear" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="the-pattern-is-clear"><span class="header-section-number">5</span> The Pattern Is Clear</h2>
<p>All 17 rules serve one purpose: <strong>decouple independent change drivers</strong>.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 15%">
<col style="width: 37%">
<col style="width: 47%">
</colgroup>
<thead>
<tr class="header">
<th>Rule</th>
<th>IVP Principle</th>
<th>What It Decouples</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Modularity</td>
<td>IVP-3: Separate</td>
<td>Module internals from each other</td>
</tr>
<tr class="even">
<td>Clarity</td>
<td>Optimize for dominant driver</td>
<td>Logic from comprehension</td>
</tr>
<tr class="odd">
<td>Composition</td>
<td>IVP-3: Separate</td>
<td>Programs from workflows</td>
</tr>
<tr class="even">
<td>Separation</td>
<td>IVP-3: Separate</td>
<td>Policy/mechanism, interface/engine</td>
</tr>
<tr class="odd">
<td>Simplicity</td>
<td>Minimize drivers</td>
<td>Reduces coupling opportunities</td>
</tr>
<tr class="even">
<td>Parsimony</td>
<td>Minimize forced coupling</td>
<td>Avoids unnecessary shared change drivers</td>
</tr>
<tr class="odd">
<td>Transparency</td>
<td>IVP-3: Separate</td>
<td>Logic from observation</td>
</tr>
<tr class="even">
<td>Robustness</td>
<td>Emergent property</td>
<td>Failure isolation via decoupling</td>
</tr>
<tr class="odd">
<td>Representation</td>
<td>IVP-3: Separate</td>
<td>Knowledge from logic (data/code)</td>
</tr>
<tr class="even">
<td>Least Surprise</td>
<td>Minimize coupling</td>
<td>Behavior from expectations</td>
</tr>
<tr class="odd">
<td>Silence</td>
<td>IVP-3: Separate</td>
<td>Success from monitoring</td>
</tr>
<tr class="even">
<td>Repair</td>
<td>IVP-3: Separate</td>
<td>Errors from normal flow</td>
</tr>
<tr class="odd">
<td>Economy</td>
<td>Prioritize driver</td>
<td>Development cost over runtime cost</td>
</tr>
<tr class="even">
<td>Generation</td>
<td>IVP-4: Unify</td>
<td>Pattern from instances</td>
</tr>
<tr class="odd">
<td>Optimization</td>
<td>Sequence drivers</td>
<td>Correctness before performance</td>
</tr>
<tr class="even">
<td>Diversity</td>
<td>Context-dependent drivers</td>
<td>Solutions across contexts</td>
</tr>
<tr class="odd">
<td>Extensibility</td>
<td>Future drivers</td>
<td>Today’s code from tomorrow’s needs</td>
</tr>
</tbody>
</table>
<p><strong>The Unix philosophy is systematic application of IVP.</strong></p>
</section>
<section id="why-unix-endures" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="why-unix-endures"><span class="header-section-number">6</span> Why Unix Endures</h2>
<p>Unix has outlived countless “next generation” systems because it aligns with <strong>fundamental change forces</strong>:</p>
<section id="text-streams-decouple-programs-from-data-formats" class="level3" data-number="6.1">
<h3 data-number="6.1" class="anchored" data-anchor-id="text-streams-decouple-programs-from-data-formats"><span class="header-section-number">6.1</span> 1. Text Streams Decouple Programs from Data Formats</h3>
<p>Programs don’t need to know about each other’s internal representations—text is the universal interface.</p>
<p><strong>Change driver independence:</strong> Data format changes don’t require modifying programs.</p>
</section>
<section id="small-tools-decouple-concerns" class="level3" data-number="6.2">
<h3 data-number="6.2" class="anchored" data-anchor-id="small-tools-decouple-concerns"><span class="header-section-number">6.2</span> 2. Small Tools Decouple Concerns</h3>
<p>Each tool does one thing, responds to one change driver.</p>
<p><strong>Change driver independence:</strong> Workflow changes don’t require modifying tools.</p>
</section>
<section id="pipes-decouple-composition-from-implementation" class="level3" data-number="6.3">
<h3 data-number="6.3" class="anchored" data-anchor-id="pipes-decouple-composition-from-implementation"><span class="header-section-number">6.3</span> 3. Pipes Decouple Composition from Implementation</h3>
<p>Workflows combine tools without coupling to their implementations.</p>
<p><strong>Change driver independence:</strong> Tool implementations can change without breaking workflows.</p>
</section>
<section id="everything-is-a-file-decouples-programs-from-resources" class="level3" data-number="6.4">
<h3 data-number="6.4" class="anchored" data-anchor-id="everything-is-a-file-decouples-programs-from-resources"><span class="header-section-number">6.4</span> 4. Everything Is a File Decouples Programs from Resources</h3>
<p>Devices, sockets, files—all use the same interface.</p>
<p><strong>Change driver independence:</strong> Resource types can vary independently from programs using them.</p>
<p>These aren’t accidents. They’re <strong>deliberate decoupling strategies</strong>.</p>
</section>
</section>
<section id="the-modern-relevance" class="level2" data-number="7">
<h2 data-number="7" class="anchored" data-anchor-id="the-modern-relevance"><span class="header-section-number">7</span> The Modern Relevance</h2>
<p>“But we’re not writing Unix utilities in 2025!”</p>
<p>True. But the <strong>change drivers</strong> are the same: - Requirements still evolve - Technologies still advance - Teams still need to work in parallel - Code still needs maintenance</p>
<p><strong>IVP explains why Unix principles transfer to modern contexts:</strong></p>
<section id="microservices-rule-of-modularity" class="level3" data-number="7.1">
<h3 data-number="7.1" class="anchored" data-anchor-id="microservices-rule-of-modularity"><span class="header-section-number">7.1</span> Microservices = Rule of Modularity</h3>
<p>Independent services = independent change drivers (team autonomy, deployment independence).</p>
</section>
<section id="apis-text-streams" class="level3" data-number="7.2">
<h3 data-number="7.2" class="anchored" data-anchor-id="apis-text-streams"><span class="header-section-number">7.2</span> APIs = Text Streams</h3>
<p>JSON/HTTP = universal interface, decoupling services from internal representations.</p>
</section>
<section id="containers-rule-of-extensibility" class="level3" data-number="7.3">
<h3 data-number="7.3" class="anchored" data-anchor-id="containers-rule-of-extensibility"><span class="header-section-number">7.3</span> Containers = Rule of Extensibility</h3>
<p>Docker images decouple application code from infrastructure.</p>
</section>
<section id="infrastructure-as-code-rule-of-representation" class="level3" data-number="7.4">
<h3 data-number="7.4" class="anchored" data-anchor-id="infrastructure-as-code-rule-of-representation"><span class="header-section-number">7.4</span> Infrastructure as Code = Rule of Representation</h3>
<p>Configuration as data decouples infrastructure from manual setup.</p>
</section>
<section id="cicd-rule-of-generation" class="level3" data-number="7.5">
<h3 data-number="7.5" class="anchored" data-anchor-id="cicd-rule-of-generation"><span class="header-section-number">7.5</span> CI/CD = Rule of Generation</h3>
<p>Automated pipelines decouple deployment from manual steps.</p>
<p><strong>The principles are timeless because change drivers are timeless.</strong></p>
</section>
</section>
<section id="the-lesson" class="level2" data-number="8">
<h2 data-number="8" class="anchored" data-anchor-id="the-lesson"><span class="header-section-number">8</span> The Lesson</h2>
<p>The Unix philosophy wasn’t arbitrary wisdom from bearded wizards. It was <strong>systematic engineering</strong>:</p>
<ol type="1">
<li>Identify independent change drivers (requirements, technology, users, operations)</li>
<li>Structure systems to decouple them (modularity, composition, interfaces)</li>
<li>Minimize coupling (simplicity, parsimony, separation)</li>
<li>Maximize independence (extensibility, diversity, generation)</li>
</ol>
<p>This is IVP in action.</p>
<p><strong>Unix got it right because it aligned with how software actually changes.</strong></p>
</section>
<section id="applying-unix-ivp-today" class="level2" data-number="9">
<h2 data-number="9" class="anchored" data-anchor-id="applying-unix-ivp-today"><span class="header-section-number">9</span> Applying Unix IVP Today</h2>
<p>Want to write Unix-style code in 2025? Apply IVP:</p>
<section id="identify-your-change-drivers" class="level3" data-number="9.1">
<h3 data-number="9.1" class="anchored" data-anchor-id="identify-your-change-drivers"><span class="header-section-number">9.1</span> 1. Identify Your Change Drivers</h3>
<ul>
<li>What requirements change?</li>
<li>What technologies evolve?</li>
<li>What teams need independence?</li>
<li>What users need flexibility?</li>
</ul>
</section>
<section id="separate-independent-drivers" class="level3" data-number="9.2">
<h3 data-number="9.2" class="anchored" data-anchor-id="separate-independent-drivers"><span class="header-section-number">9.2</span> 2. Separate Independent Drivers</h3>
<ul>
<li>Module per change driver</li>
<li>Interface per coordination need</li>
<li>Data for domain knowledge</li>
<li>Code for logic</li>
</ul>
</section>
<section id="compose-dont-couple" class="level3" data-number="9.3">
<h3 data-number="9.3" class="anchored" data-anchor-id="compose-dont-couple"><span class="header-section-number">9.3</span> 3. Compose, Don’t Couple</h3>
<ul>
<li>Small, focused components</li>
<li>Clean interfaces</li>
<li>Universal data formats</li>
<li>Pipeable workflows</li>
</ul>
</section>
<section id="verify-independence" class="level3" data-number="9.4">
<h3 data-number="9.4" class="anchored" data-anchor-id="verify-independence"><span class="header-section-number">9.4</span> 4. Verify Independence</h3>
<p>Can each concern vary without forcing changes elsewhere? - Yes → ✅ Good separation - No → ❌ Refactor</p>
</section>
</section>
<section id="but-waitdoes-unix-ever-violate-ivp" class="level2" data-number="10">
<h2 data-number="10" class="anchored" data-anchor-id="but-waitdoes-unix-ever-violate-ivp"><span class="header-section-number">10</span> But Wait—Does Unix Ever Violate IVP?</h2>
<p>Fair question. Let’s examine the tensions across all 17 rules:</p>
<section id="text-streams-a-deliberate-coupling" class="level3" data-number="10.1">
<h3 data-number="10.1" class="anchored" data-anchor-id="text-streams-a-deliberate-coupling"><span class="header-section-number">10.1</span> 1. Text Streams: A Deliberate Coupling</h3>
<p><strong>The Unix choice:</strong> Everything communicates via text streams.</p>
<p><strong>IVP tension:</strong> This <strong>couples</strong> performance (binary is faster) with interoperability (need common format).</p>
<p><strong>Why Unix does this:</strong> Text streams are a <strong>strategic coupling</strong>—Unix chose to prioritize the interoperability change driver over the performance change driver. This was the right trade-off for composability, even though it couples data representation.</p>
<p><strong>IVP perspective:</strong> When change drivers conflict, IVP says optimize for the <strong>dominant</strong> driver. Unix correctly identified interoperability as dominant for most tool composition.</p>
</section>
<section id="rule-of-transparency-coupling-implementation-with-observation" class="level3" data-number="10.2">
<h3 data-number="10.2" class="anchored" data-anchor-id="rule-of-transparency-coupling-implementation-with-observation"><span class="header-section-number">10.2</span> 2. Rule of Transparency: Coupling Implementation with Observation</h3>
<p><strong>The Unix choice:</strong> Make internals visible for inspection.</p>
<p><strong>IVP tension:</strong> Transparency can <strong>couple</strong> implementation freedom with observability requirements. When internals are visible, changing them becomes harder because users/tools depend on that visibility.</p>
<p><strong>Why Unix does this:</strong> Debugging and maintenance were dominant change drivers. Implementation flexibility was sacrificed for operational visibility.</p>
<p><strong>IVP perspective:</strong> Context-appropriate trade-off for Unix’s environment (small systems, expert users who need to see inside).</p>
</section>
<section id="rule-of-representation-trading-code-coupling-for-data-coupling" class="level3" data-number="10.3">
<h3 data-number="10.3" class="anchored" data-anchor-id="rule-of-representation-trading-code-coupling-for-data-coupling"><span class="header-section-number">10.3</span> 3. Rule of Representation: Trading Code Coupling for Data Coupling</h3>
<p><strong>The Unix choice:</strong> Put knowledge in data, not code.</p>
<p><strong>IVP tension:</strong> Data schemas can be <strong>harder to change</strong> than code. You trade domain-in-code coupling for domain-in-data-schema coupling. Database migrations, backwards compatibility, parsing logic—data isn’t always more flexible.</p>
<p><strong>Why Unix does this:</strong> For configuration-driven behavior, data changes don’t require recompilation. The trade-off is worth it when domain knowledge changes more frequently than the system itself.</p>
<p><strong>IVP perspective:</strong> Recognizes that <strong>both</strong> approaches have coupling—choose based on which changes more frequently in your context.</p>
</section>
<section id="rule-of-least-surprise-coupling-innovation-to-convention" class="level3" data-number="10.4">
<h3 data-number="10.4" class="anchored" data-anchor-id="rule-of-least-surprise-coupling-innovation-to-convention"><span class="header-section-number">10.4</span> 4. Rule of Least Surprise: Coupling Innovation to Convention</h3>
<p><strong>The Unix choice:</strong> Follow existing conventions.</p>
<p><strong>IVP tension:</strong> This <strong>couples</strong> innovation to backwards compatibility. Better designs that surprise users may be rejected. Progress is constrained by legacy expectations.</p>
<p><strong>Why Unix does this:</strong> User adoption and ecosystem coherence were dominant change drivers. Innovation was sacrificed for compatibility.</p>
<p><strong>IVP perspective:</strong> Network effects matter—a slightly worse standard everyone uses beats a better standard nobody adopts. Context determines whether innovation or compatibility dominates.</p>
</section>
<section id="rule-of-silence-coupling-observability" class="level3" data-number="10.5">
<h3 data-number="10.5" class="anchored" data-anchor-id="rule-of-silence-coupling-observability"><span class="header-section-number">10.5</span> 5. Rule of Silence: Coupling Observability</h3>
<p><strong>The Unix choice:</strong> Silent on success.</p>
<p><strong>IVP tension:</strong> This couples monitoring with error detection—you can’t observe normal operation without modifying the program or using external tools.</p>
<p><strong>Why Unix does this:</strong> Silence decouples success path from failure path, making error detection trivial. The trade-off is reduced visibility into normal operation.</p>
<p><strong>IVP perspective:</strong> This is a <strong>priority decision</strong>—error detection was more important than operational observability in Unix’s context (small systems, expert users). Modern systems with different change drivers (distributed systems, complex deployments) may need different trade-offs.</p>
</section>
<section id="rule-of-repair-fail-fast-coupling-errors-with-termination" class="level3" data-number="10.6">
<h3 data-number="10.6" class="anchored" data-anchor-id="rule-of-repair-fail-fast-coupling-errors-with-termination"><span class="header-section-number">10.6</span> 6. Rule of Repair (Fail Fast): Coupling Errors with Termination</h3>
<p><strong>The Unix choice:</strong> Fail immediately and noisily.</p>
<p><strong>IVP tension:</strong> This <strong>couples</strong> error occurrence with system termination. What about graceful degradation, retries, circuit breakers, or partial failures? Modern resilience patterns conflict with “fail fast.”</p>
<p><strong>Why Unix does this:</strong> In Unix’s context (single-user systems, synchronous operations), immediate failure was clearer than silent corruption. Resilience wasn’t a primary change driver.</p>
<p><strong>IVP perspective:</strong> “Fail fast” optimizes for single-machine reliability. Distributed systems have different change drivers (partial failures are normal) requiring different strategies.</p>
</section>
<section id="economy-rule-explicit-priority-declaration" class="level3" data-number="10.7">
<h3 data-number="10.7" class="anchored" data-anchor-id="economy-rule-explicit-priority-declaration"><span class="header-section-number">10.7</span> 7. Economy Rule: Explicit Priority Declaration</h3>
<p><strong>The Unix choice:</strong> Programmer time &gt; machine time.</p>
<p><strong>IVP tension:</strong> This explicitly accepts coupling development cost with runtime cost, then chooses which to optimize.</p>
<p><strong>Why Unix does this:</strong> It’s not claiming independence—it’s acknowledging these drivers conflict and declaring a priority.</p>
<p><strong>IVP perspective:</strong> ✅ This is actually <strong>good IVP reasoning</strong>—when decoupling is impossible, consciously choose which change driver dominates.</p>
</section>
<section id="rule-of-generation-trading-dry-for-debuggability" class="level3" data-number="10.8">
<h3 data-number="10.8" class="anchored" data-anchor-id="rule-of-generation-trading-dry-for-debuggability"><span class="header-section-number">10.8</span> 8. Rule of Generation: Trading DRY for Debuggability</h3>
<p><strong>The Unix choice:</strong> Generate code from specifications (yacc, lex, etc.).</p>
<p><strong>IVP tension:</strong> Generated code is often <strong>harder to debug</strong>. You couple understanding with knowledge of the generator. When generated code fails, you need to understand both the generator AND the output.</p>
<p><strong>Why Unix does this:</strong> Pattern consistency and avoiding manual repetition were dominant. Debuggability of generated artifacts was sacrificed.</p>
<p><strong>IVP perspective:</strong> Acceptable when the pattern is stable and well-understood (parsers, lexers). Problematic when generators are complex or patterns change frequently.</p>
</section>
<section id="rule-of-optimization-prototyping-can-couple-architecture" class="level3" data-number="10.9">
<h3 data-number="10.9" class="anchored" data-anchor-id="rule-of-optimization-prototyping-can-couple-architecture"><span class="header-section-number">10.9</span> 9. Rule of Optimization: Prototyping Can Couple Architecture</h3>
<p><strong>The Unix choice:</strong> Make it work, then make it fast.</p>
<p><strong>IVP tension:</strong> Prototyping with one architecture, then discovering it can’t meet performance requirements, <strong>couples</strong> initial design decisions to final performance characteristics. Sometimes you need a fundamentally different architecture for performance.</p>
<p><strong>Why Unix does this:</strong> Most problems don’t need exotic architectures. Optimizing the 90% case (prototype is good enough) over the 10% (need complete rewrite for performance).</p>
<p><strong>IVP perspective:</strong> Valid when correctness complexity and performance complexity are independent. Breaks down when performance requires fundamentally different algorithms/architectures (e.g., real-time systems, high-throughput data processing).</p>
</section>
<section id="rule-of-extensibility-coupling-present-simplicity-to-future-flexibility" class="level3" data-number="10.10">
<h3 data-number="10.10" class="anchored" data-anchor-id="rule-of-extensibility-coupling-present-simplicity-to-future-flexibility"><span class="header-section-number">10.10</span> 10. Rule of Extensibility: Coupling Present Simplicity to Future Flexibility</h3>
<p><strong>The Unix choice:</strong> Design for future extensibility.</p>
<p><strong>IVP tension:</strong> Building extensibility mechanisms NOW couples present simplicity with future flexibility. This conflicts with YAGNI (You Aren’t Gonna Need It) and can lead to over-engineering for hypothetical futures.</p>
<p><strong>Why Unix does this:</strong> Unix optimized for long-lived systems where extensibility proved valuable. Many systems lived decades.</p>
<p><strong>IVP perspective:</strong> Context-dependent. Long-lived infrastructure benefits from extensibility. Short-lived applications suffer from over-engineering. The dominant change driver is system lifespan.</p>
</section>
<section id="worse-is-better-strategic-technical-debt" class="level3" data-number="10.11">
<h3 data-number="10.11" class="anchored" data-anchor-id="worse-is-better-strategic-technical-debt"><span class="header-section-number">10.11</span> 11. “Worse is Better”: Strategic Technical Debt</h3>
<p>Unix embraced simplicity over completeness (the “New Jersey style”).</p>
<p><strong>IVP tension:</strong> Accepts incomplete abstractions (technical debt) to ship faster.</p>
<p><strong>Why Unix does this:</strong> Delivery schedule was the dominant change driver over architectural perfection.</p>
<p><strong>IVP perspective:</strong> IVP doesn’t demand perfection—it demands <strong>conscious alignment</strong> with dominant change drivers. Unix made explicit trade-offs.</p>
</section>
<section id="the-key-insight" class="level3" data-number="10.12">
<h3 data-number="10.12" class="anchored" data-anchor-id="the-key-insight"><span class="header-section-number">10.12</span> The Key Insight</h3>
<p>These aren’t IVP violations—they’re <strong>IVP trade-offs</strong>. Unix made conscious decisions about which change drivers to prioritize:</p>
<ol type="1">
<li><strong>Text streams:</strong> Interoperability over performance</li>
<li><strong>Transparency:</strong> Observability over implementation flexibility</li>
<li><strong>Representation (data):</strong> Configuration flexibility over schema stability</li>
<li><strong>Least Surprise:</strong> Adoption/compatibility over innovation</li>
<li><strong>Silence:</strong> Error detection over operational observability</li>
<li><strong>Fail Fast:</strong> Clarity over resilience</li>
<li><strong>Economy:</strong> Development cost over runtime cost</li>
<li><strong>Generation:</strong> DRY/consistency over debuggability</li>
<li><strong>Optimization:</strong> Correctness over performance (initially)</li>
<li><strong>Extensibility:</strong> Future flexibility over present simplicity</li>
<li><strong>Worse is Better:</strong> Delivery over architectural completeness</li>
</ol>
<p><strong>IVP doesn’t claim you can always achieve perfect independence.</strong> It says:</p>
<ol type="1">
<li>Identify independent change drivers</li>
<li>Decouple them when possible</li>
<li>When impossible, <strong>consciously choose</strong> which to optimize for</li>
<li>Make the trade-off explicit</li>
</ol>
<p>Unix did all four. That’s why it endures—not because it avoided all coupling, but because it made <strong>intelligent, context-aware trade-offs</strong> about which couplings to accept.</p>
</section>
<section id="what-this-analysis-reveals" class="level3" data-number="10.13">
<h3 data-number="10.13" class="anchored" data-anchor-id="what-this-analysis-reveals"><span class="header-section-number">10.13</span> What This Analysis Reveals</h3>
<p>This deep dive demonstrates that <strong>IVP is a broadly applicable analytical framework</strong>, not limited to object-oriented design or modern programming paradigms. By applying IVP to Unix philosophy—a system designed in the 1970s for entirely different computing contexts—we can:</p>
<ul>
<li><strong>Validate historical design decisions</strong> by understanding which change drivers they optimized for</li>
<li><strong>Interpret trade-offs</strong> that seemed arbitrary or contradictory by seeing them as conscious prioritizations</li>
<li><strong>Make better decisions today</strong> by understanding when Unix principles apply to modern contexts (same change drivers) and when they don’t (different change drivers)</li>
<li><strong>Extend beyond software</strong> to any domain where change forces interact: organizational design, API versioning, infrastructure architecture, even product strategy</li>
</ul>
<p>IVP provides a <strong>decision-making framework</strong> that works across decades, paradigms, and problem domains because it focuses on the fundamental structure of change forces—which remain constant even as technologies evolve.</p>
</section>
</section>
<section id="the-bottom-line" class="level2" data-number="11">
<h2 data-number="11" class="anchored" data-anchor-id="the-bottom-line"><span class="header-section-number">11</span> The Bottom Line</h2>
<p>The Unix philosophy has one message:</p>
<blockquote class="blockquote">
<p><strong>Structure systems so independent concerns can vary independently.</strong></p>
</blockquote>
<p>That’s IVP.</p>
<p>The 17 rules are strategies for achieving this. They’re not commandments—they’re <strong>implications of IVP</strong> applied to different design dimensions.</p>
<p>When you follow the Unix philosophy, you’re applying IVP, whether you know it or not.</p>
<p>And when you apply IVP consciously, you’ll make the same design decisions Unix pioneers made—because you’re aligning with the same fundamental forces.</p>
<hr>
</section>
<section id="learn-more" class="level2" data-number="12">
<h2 data-number="12" class="anchored" data-anchor-id="learn-more"><span class="header-section-number">12</span> Learn More</h2>
<p>The Independent Variation Principle is introduced in:</p>
<p><strong>Loth, Y. (2025). The Independent Variation Principle. Zenodo.</strong> https://doi.org/10.5281/zenodo.17677316</p>
<p>The paper provides: - Formal derivation of IVP from first principles - The Knowledge Theorem connecting cohesion to domain knowledge - Applications to OOP, FP, databases, and architectures - Rigorous analysis of coupling/cohesion metrics - Extensions beyond software design</p>
<p>Eric Raymond’s “The Art of Unix Programming” remains the definitive guide to Unix philosophy: http://www.catb.org/~esr/writings/taoup/html/</p>
<hr>
<p><em>Do you see the Unix philosophy in your modern codebase? Where are you applying these principles without realizing it? Share your examples in the comments!</em></p>


</section>

 ]]></description>
  <category>systems</category>
  <category>architecture</category>
  <category>theory</category>
  <category>ivp</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-11-25-the-unix-philosophy-was-right-all-along-a-piv-analysis-of-17-timeless-rules-2l4l.html</guid>
  <pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>It’s about time</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2025-04-15-its-about-time-3hj6.html</link>
  <description><![CDATA[ 





<p>Today I remembered an exam question from around 2005 or 2006 for a course taught by Professor Pascal Bouvry at the University of Luxembourg. We had to explain an algorithm to synchronize time between two computers.</p>
<p>Obviously, explaining how the Network Time Protocol (NTP) works would have been the perfect answer. Back then, I wasn’t sure exactly how NTP operated, so I devised my own algorithm. Professor Bouvry deemed it sufficient – good for my grade, but that’s not the point of this post.</p>
<p>Ever since that exam, I’ve been intrigued by the “right” answer and the actual mechanics of NTP, but I never took the time to properly research it. Until today, nearly 20 years later!</p>
<section id="fundamentals-of-ntp-time-synchronization" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="fundamentals-of-ntp-time-synchronization"><span class="header-section-number">1</span> Fundamentals of NTP Time Synchronization</h2>
<p>When a computer A (the client) needs to synchronize its clock with another computer B (the server), whose time is considered accurate, NTP uses a clever exchange of timestamps:</p>
<ul>
<li>The NTP client sends a request packet to an NTP server. This packet includes the client’s current time, known as the originate timestamp (<code>T1</code>).</li>
<li>The NTP server receives the packet at its time, the receive timestamp (<code>T2</code>).</li>
<li>The server processes the request and sends a reply packet back. This packet includes <code>T1</code>, <code>T2</code>, and the server’s time when the reply departs, the transmit timestamp (<code>T3</code>).</li>
<li>The client receives the reply packet at its time, the destination timestamp (<code>T4</code>).</li>
</ul>
<p>Crucially, <code>T1</code> and <code>T4</code> are measured using the client’s clock, while <code>T2</code> and <code>T3</code> are measured using the server’s clock.</p>
<section id="calculating-the-round-trip-delay" class="level3" data-number="1.1">
<h3 data-number="1.1" class="anchored" data-anchor-id="calculating-the-round-trip-delay"><span class="header-section-number">1.1</span> Calculating the round-trip delay</h3>
<p>Using these four timestamps, NTP calculates the round-trip delay: the total time taken for the request to reach the server and the reply to return to the client.</p>
<p><code>Round-trip delay = (T4-T3)+(T2-T1)</code>, which may be rewritten to the standard formula:</p>
<p><code>Round-trip delay = (T4-T1)-(T3-T2)</code>.</p>
<p>Subtracting the server processing time from the total client-side elapsed time gives the time actually spent in network transit (both ways). This calculation accounts for network latency.</p>
<p>Note that the timestamps <code>T1</code> and <code>T4</code> are times measured on the client before correction of its time, and <code>T2</code> and <code>T3</code> are times measured on the server. This explains why the round-trip delay is usually expressed using the second expression supra instead of the first one, as it computes time intervals measured on the server for one interval and on the client for the other interval, then adds both: it logically separates client-side total duration and server-side processing duration</p>
<p>This makes sense, because the time not being synchronised, it could mean that the client has a clock that is ahead of the server’s clock and that <code>T2-T1</code> might be zero or negative, which does not make much sense physically, although it is correct mathematically. To avoid this, we prefer the second expression: the time readings on the client and on the server being a monotonous function means that <code>T4&gt;T1</code> and <code>T3&gt;T2</code> given clocks whose accuracy is higher than respectively the round-trip delay and the time to reply.</p>
</section>
<section id="calculating-the-time-offset" class="level3" data-number="1.2">
<h3 data-number="1.2" class="anchored" data-anchor-id="calculating-the-time-offset"><span class="header-section-number">1.2</span> Calculating the time offset</h3>
<p>The time offset is the difference between the client’s clock and the server’s clock. This is the correction needed for the client’s time.</p>
<p>To calculate this, NTP makes a key assumption: the network path delay is symmetrical (i.e., the time taken for the request to travel client-to-server is the same as the time taken for the reply server-to-client). Let’s call this one-way delay Delay.</p>
<p>We can express the timestamps relative to each other, incorporating the Offset and Delay:</p>
<ul>
<li>Server receives request: <code>T2 ≈ T1 + Offset + Delay</code></li>
<li>Client receives reply: <code>T4 ≈ T3 - Offset + Delay</code> (Offset is subtracted because <code>T4</code> is relative to <code>T3</code> on the server’s timeline, but measured on the client’s potentially offset clock)</li>
</ul>
<p>Rearranging these gives:</p>
<p><code>Offset + Delay ≈ T2-T1</code></p>
<p><code>Offset - Delay ≈ T3-T4</code></p>
<p>Which, by adding these equations, leads to:</p>
<p><code>Offset + Delay + Offset - Delay ≈ T2-T1 + T3-T4</code>, and finally:</p>
<p><code>Offset ≈ [(T2-T1)+(T3-T4)]/2</code>.</p>
<p>The client’s clock needs to be adjusted by adding this calculated Offset.</p>
</section>
<section id="how-synchronization-and-adjustment-actually-happen" class="level3" data-number="1.3">
<h3 data-number="1.3" class="anchored" data-anchor-id="how-synchronization-and-adjustment-actually-happen"><span class="header-section-number">1.3</span> How synchronization and adjustment actually happen</h3>
<p>Calculating the offset is just one part. Real-world NTP clients typically:</p>
<ol type="1">
<li>Query multiple NTP servers to get several time references.</li>
<li>Use statistical algorithms to filter out unreliable servers (outliers) and weigh the remaining sources to determine the most accurate time.</li>
<li>Apply the correction gradually using slewing (adjusting clock speed) for small differences, rather than making abrupt stepping changes (instantaneous jumps). This ensures smoother timekeeping.</li>
<li>Repeat this process periodically to maintain synchronization.</li>
</ol>
</section>
<section id="about-slewing-and-stepping" class="level3" data-number="1.4">
<h3 data-number="1.4" class="anchored" data-anchor-id="about-slewing-and-stepping"><span class="header-section-number">1.4</span> About slewing and stepping</h3>
<p>These are the two main ways an NTP client applies corrections:</p>
<section id="slewing" class="level4" data-number="1.4.1">
<h4 data-number="1.4.1" class="anchored" data-anchor-id="slewing"><span class="header-section-number">1.4.1</span> Slewing</h4>
<p>This involves gradually adjusting the system clock’s effective speed to match the correct time. - If the client clock is behind, the NTP daemon makes the software clock run slightly faster until it catches up. - If the client clock is ahead, it makes the software clock run slightly slower. - <strong>Key Advantage:</strong> Avoids sudden time jumps, which is crucial for applications relying on smoothly progressing time. This is the preferred method for small, ongoing corrections.</p>
</section>
<section id="stepping" class="level4" data-number="1.4.2">
<h4 data-number="1.4.2" class="anchored" data-anchor-id="stepping"><span class="header-section-number">1.4.2</span> Stepping</h4>
<p>This involves an instantaneous jump in the system clock to the correct time. - Used for large initial corrections or when the time difference is too significant to slew quickly. - <strong>Potential Disadvantage:</strong> Can cause time to appear to stand still or even go backward, potentially disrupting applications.</p>
<p>How Slewing Works: It’s usually not the physical hardware clock frequency that changes. Instead, the operating system kernel adjusts how it interprets ticks from the hardware timer to maintain the <em>software clock</em>. The kernel applies a small correction factor, effectively making the software clock run slightly faster or slower. This is often managed via system calls like <code>adjtimex</code> (on Linux), controlled by the NTP daemon.</p>
</section>
<section id="consequences-of-slewing-and-stepping" class="level4" data-number="1.4.3">
<h4 data-number="1.4.3" class="anchored" data-anchor-id="consequences-of-slewing-and-stepping"><span class="header-section-number">1.4.3</span> Consequences of slewing and stepping</h4>
<ul>
<li>Slewing: Adjusts the rate of the clock. Time continues to move forward monotonically. Slewing itself does not cause time to go backward, which is a vital guarantee for many applications. Intervals measured during a slew will still have positive durations (though slightly inaccurate relative to true elapsed time).</li>
<li>Stepping: Involves an instant jump. If the clock is stepped backward, applications measuring time across that jump could read a negative or zero time interval if they rely on the system’s wall-clock time.</li>
</ul>
</section>
</section>
</section>
<section id="practical-tip" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="practical-tip"><span class="header-section-number">2</span> Practical tip</h2>
<p>If you configure only one NTP server on your client, it will only attempt to synchronize with that single server. While NTP can work this way, it’s not ideal:</p>
<ul>
<li><strong>Single point of failure:</strong> If that server is down or inaccurate, your synchronization fails.</li>
<li><strong>No cross-checking:</strong> The client cannot perform the sophisticated filtering and selection algorithms that compare multiple sources to improve accuracy and reliability.</li>
</ul>
<p><strong>Best practice:</strong> Configure at least 3-4 diverse and reliable NTP servers.</p>
</section>
<section id="consequence-for-application-developers-wall-clocks-vs.-monotonic-clocks" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="consequence-for-application-developers-wall-clocks-vs.-monotonic-clocks"><span class="header-section-number">3</span> Consequence for Application Developers: Wall Clocks vs.&nbsp;Monotonic Clocks</h2>
<p>While NTP slewing avoids making time go backward, developers must understand the type of clock their application uses, especially for measuring durations:</p>
<ul>
<li><strong>Wall-Clock Time (or Real-Time Clock):</strong> This is the actual time of day (e.g., <code>14:30:15 Apr 15, 2025</code>). It’s subject to adjustments by NTP (slewing and stepping), time zone changes, and Daylight Saving Time. <strong>Using wall-clock time to measure intervals is unreliable</strong> because it can jump forward or backward unexpectedly.</li>
<li><strong>Monotonic Clock:</strong> This clock measures time from an arbitrary fixed point (like system boot). It is <strong>guaranteed to only move forward</strong> (monotonically increasing) and is <strong>not affected by wall-clock adjustments</strong> (NTP, DST, etc.).</li>
</ul>
<p><strong>Guideline:</strong> Applications should always use a monotonic clock whenever they need to reliably measure time durations, intervals, or timeouts.</p>
<ul>
<li><strong>Well-behaved applications</strong> use monotonic clock APIs provided by the OS or platform (e.g., <code>CLOCK_MONOTONIC</code> in POSIX/Linux, <code>System.Diagnostics.Stopwatch</code> or <code>Environment.TickCount64</code> in .NET, <code>time.monotonic()</code> in Python). This avoids issues with wall-clock adjustments entirely.</li>
<li><strong>Less robust applications</strong> might incorrectly use the wall-clock time for intervals. These are vulnerable to errors (like negative durations) if a clock step occurs. Slewing reduces the risk compared to stepping, but using a monotonic clock is the correct fix.</li>
</ul>
</section>
<section id="measuring-time-intervals-on-the-jvm" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="measuring-time-intervals-on-the-jvm"><span class="header-section-number">4</span> Measuring time intervals on the JVM</h2>
<p>Java provides access to a monotonic clock source via <a href="https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/System.html#nanoTime()"><code>System.nanoTime()</code></a>.</p>
<section id="system.nanotime" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="system.nanotime"><span class="header-section-number">4.1</span> <code>System.nanoTime()</code></h3>
<ul>
<li>Returns the current value of the system’s high-resolution timer in nanoseconds.</li>
<li>Provides nanosecond precision (accuracy depends on the underlying OS/hardware).</li>
<li><strong>Crucially, it is monotonic.</strong> Values only increase, based on an arbitrary origin.</li>
<li><strong>Not affected by adjustments to the system’s wall-clock time.</strong></li>
<li><strong>Purpose-built for measuring elapsed time intervals reliably.</strong></li>
</ul>
</section>
<section id="comparison-with-system.currenttimemillis" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="comparison-with-system.currenttimemillis"><span class="header-section-number">4.2</span> Comparison with <a href="https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/System.html#currentTimeMillis()"><code>System.currentTimeMillis()</code></a></h3>
<ul>
<li>Returns wall-clock time (milliseconds since the Unix epoch).</li>
<li><strong>This method is not monotonic.</strong> Its value can decrease if the system clock is adjusted backward.</li>
<li><strong>Should not be used</strong> for measuring time intervals where monotonicity is required.</li>
</ul>
</section>
<section id="java-code-example-for-measuring-a-time-interval" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="java-code-example-for-measuring-a-time-interval"><span class="header-section-number">4.3</span> Java code example for measuring a time interval</h3>
<pre><code>final long startTime = System.nanoTime();

// ... perform the operation you want to time ...

final long endTime = System.nanoTime();

final long durationNanos = endTime - startTime;
final double durationSeconds = durationNanos / 1_000_000_000.0;

System.out.println("Operation took: " + durationNanos + " nanoseconds (" + durationSeconds + " seconds)");</code></pre>
<p><strong>Note:</strong> we do not care about the actual values returned by <code>System.nanoTime()</code> - there is no meaning to give to a single reading. The value lies in the difference between two readings.</p>
<p>So, after nearly two decades, it’s about time I dig into time synchronization. It’s a fascinating blend of timestamping, network assumptions, and careful clock management, with important implications for how we write reliable software.</p>
</section>
</section>
<section id="references" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="references"><span class="header-section-number">5</span> References</h2>
<ul>
<li>NTP On-Wire Protocol: https://datatracker.ietf.org/doc/html/rfc5905#section-8</li>
<li>Java API docs: https://docs.oracle.com/en/java/javase/23/docs/api/index.html</li>
</ul>


</section>

 ]]></description>
  <category>systems</category>
  <category>languages</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2025-04-15-its-about-time-3hj6.html</guid>
  <pubDate>Tue, 15 Apr 2025 00:00:00 GMT</pubDate>
</item>
<item>
  <title>An exercise in semantics - Method vs Function</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-06-01-an-exercise-in-semantics-method-vs-function-23gn.html</link>
  <description><![CDATA[ 





<p>In the programming terminology, we often encounter the terms <em>method</em> and <em>function</em>. Let’s engage in an exercise in semantics, broadening our understanding to consider the contextual nuances that shape both terms.</p>
<p>In many programming languages, such as JavaScript or Python, modules or namespaces provide a structural framework for organising code and enforcing encapsulation. Within these constructs, functions can be grouped together, forming cohesive units of functionality within a specific context. It is within this context that we propose a reevaluation of terminology. ## TL;DR In OOP, a <em>method</em> is a function that is associated with an object.</p>
<p>In a more general form: In programming, a <em>method</em> is a function that is related to a context and whose visibility/accessibility is restricted by that context, where <em>context</em>, <em>relation to the context</em> and <em>visibility/accessibility restriction</em> all depend on the specific programming language considered.</p>
<section id="introduction" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="introduction"><span class="header-section-number">1</span> Introduction</h2>
<p>The terms <em>method</em> and <em>function</em> are often used interchangeably, but there are key differences between them, especially in object-oriented programming (OOP). The following sections provide a detailed comparison.</p>
</section>
<section id="function" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="function"><span class="header-section-number">2</span> Function</h2>
<ul>
<li><p><strong>Definition</strong>: A function is a block of code designed to perform a specific task. It is defined independently and can be called with parameters to execute its task.</p></li>
<li><p><strong>Context</strong>: Functions are not inherently associated with any object. They can be standalone or part of a module.</p></li>
<li><p><strong>Usage</strong>: Functions are used to encapsulate reusable code and can be called from anywhere in the program if they are in scope.</p></li>
<li><p><strong>Syntax Example</strong> (in Python):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> add(param1, param2):</span>
<span id="cb1-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># function body</span></span>
<span id="cb1-3">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> param1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> param2</span></code></pre></div></div></li>
</ul>
</section>
<section id="method" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="method"><span class="header-section-number">3</span> Method</h2>
<ul>
<li><p><strong>Definition</strong>: A method is a function that is associated with an object. In OOP, methods define the behaviours of an object and can operate on data contained within the object (its attributes).</p></li>
<li><p><strong>Context</strong>: Methods are defined within a class and must be called on an instance of that class (or the class itself for class methods).</p></li>
<li><p><strong>Usage</strong>: Methods are used to manipulate the data of an object and to perform operations related to that object. They can access and modify the object’s state.</p></li>
<li><p><strong>Syntax Example</strong> (in Python):</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MyClass:</span>
<span id="cb2-2">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> add(<span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">self</span>, param1, param2):</span>
<span id="cb2-3">        <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># method body</span></span>
<span id="cb2-4">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> param1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> param2</span>
<span id="cb2-5"></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Creating an instance of MyClass</span></span>
<span id="cb2-7">obj <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MyClass()</span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calling the add method on the object</span></span>
<span id="cb2-9">result <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> obj.add(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div></li>
</ul>
</section>
<section id="key-differences" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="key-differences"><span class="header-section-number">4</span> Key Differences</h2>
<ol type="1">
<li><strong>Association</strong>:
<ul>
<li><strong>Function</strong>: Independent, not tied to any object.</li>
<li><strong>Method</strong>: Bound to an object (instance method) or a class (class method/static method).</li>
</ul></li>
<li><strong>Self Parameter (Python Specific)</strong>:
<ul>
<li><strong>Function</strong>: No implicit parameter.</li>
<li><strong>Method</strong>: The first parameter is typically <code>self</code> for instance methods, which refers to the instance of the class.</li>
</ul></li>
<li><strong>Calling</strong>:
<ul>
<li><strong>Function</strong>: Called directly by its name (if in scope) or via module reference.</li>
<li><strong>Method</strong>: Called on an instance or class.</li>
</ul></li>
<li><strong>Scope</strong>:
<ul>
<li><strong>Function</strong>: Can be globally scoped or limited to a specific module.</li>
<li><strong>Method</strong>: Scoped within the class definition and often interacts with the instance’s attributes and other methods. ## The case of static methods in Java</li>
</ul></li>
</ol>
<p>Given the definition of a method provided supra, one may wonder why static methods in Java should be called <em>method</em> instead of <em>function</em>: static methods are indeed not linked to an object.</p>
<p>In Java, static methods are linked to a class rather than an instance of the class, but they are still considered methods for several reasons rooted in object-oriented programming principles and terminology:</p>
<section id="context-and-namespace" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="context-and-namespace"><span class="header-section-number">4.1</span> 1. <strong>Context and Namespace</strong></h3>
<ul>
<li><strong>Class Context</strong>: Static methods belong to the class’s namespace and are defined within the class body. Even though they do not operate on an instance of the class, their definition within the class ties them to the class’s scope.</li>
<li><strong>Encapsulation</strong>: By being part of the class, static methods help encapsulate functionality that is logically related to the class but does not require access to instance-specific data.</li>
</ul>
</section>
<section id="access-and-usage" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="access-and-usage"><span class="header-section-number">4.2</span> 2. <strong>Access and Usage</strong></h3>
<ul>
<li><strong>Access</strong>: Static methods are called using the class name, reflecting their association with the class. This usage pattern reinforces their identity as methods within the class. Private static methods may be called from non-static methods of the same class, reinforcing the conceptual link between a static method and instances of its containing class.</li>
<li><strong>Functionality</strong>: Static methods can access other static methods and static variables of the class. This capability aligns with the class-level context and differentiates them from standalone functions.</li>
</ul>
</section>
<section id="terminological-consistency" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="terminological-consistency"><span class="header-section-number">4.3</span> 3. <strong>Terminological Consistency</strong></h3>
<ul>
<li><strong>Method</strong>: In OOP, the term <em>method</em> is used to describe functions that are defined within a class, regardless of whether they operate on instances or not. This convention maintains consistency in terminology.</li>
<li><strong>Class Methods</strong>: Similarly, class methods are also considered methods because they are associated with the class and can access class-level data and methods. Static methods fit this conceptual framework.</li>
</ul>
</section>
<section id="example-to-illustrate-the-concept" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="example-to-illustrate-the-concept"><span class="header-section-number">4.4</span> Example to Illustrate the Concept</h3>
<p>Here’s a Python example to illustrate how static methods fit within a class:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">class</span> MathUtility:</span>
<span id="cb3-2">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># A static method</span></span>
<span id="cb3-3">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@staticmethod</span></span>
<span id="cb3-4">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> add(a, b):</span>
<span id="cb3-5">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> b</span>
<span id="cb3-6"></span>
<span id="cb3-7">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Another static method</span></span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">@staticmethod</span></span>
<span id="cb3-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> subtract(a, b):</span>
<span id="cb3-10">        <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> a <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> b</span>
<span id="cb3-11"></span>
<span id="cb3-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Calling static methods using the class name</span></span>
<span id="cb3-13">result1 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MathUtility.add(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb3-14">result2 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> MathUtility.subtract(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb3-15"></span>
<span id="cb3-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(result1)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Output: 8</span></span>
<span id="cb3-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(result2)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Output: 6</span></span></code></pre></div></div>
<p>Thus, even though static methods do not operate on instances, their definition within a class and their role in encapsulating class-related functionality justify their classification as methods rather than standalone functions.</p>
</section>
</section>
<section id="my-opinion" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="my-opinion"><span class="header-section-number">5</span> My opinion</h2>
<p>I would argue that the link to an object or a class may be a bit too restrictive, when using the term <em>method</em>.</p>
<p>Consider expanding the context beyond objects and classes to include modules or namespaces. In many languages, modules or namespaces provide a way to group related functions and restrict their visibility from outside contexts. This grouping can enforce encapsulation and modularity in a manner similar to classes.</p>
<p>The key is understanding that what distinguishes a <em>method</em> from any other kind of function is the relation to some context as well as a visibility/accessibility specific to that context.</p>
<p><code>Note that I do not further define what the kind of the relation should be, given that it may differ with many languages, and given that any further specification may not be general enough to be compatible with the constructs of all existing or future languages.</code></p>
<p>For instance, in JavaScript or Python, functions defined within a module or namespace can be considered methods of that module if they are meant to operate within its context. These functions might not belong to a specific object or class, but they are still tied to the module’s scope and restricted in their visibility and access.</p>
<p>Therefore, it might be appropriate to use the term <em>method</em> instead of <em>function</em> in such contexts. The essential characteristics that differentiate methods from functions—namely, the contextual association and restricted visibility—are present, but at the level of a module or namespace rather than an individual object or class.</p>
<p>By broadening our perspective, we can recognise that methods do not need to be limited to the traditional object-oriented paradigm. Instead, they can exist within any structured context that enforces scope and encapsulation, whether it be a class, module, or namespace.</p>
</section>
<section id="summary" class="level2" data-number="6">
<h2 data-number="6" class="anchored" data-anchor-id="summary"><span class="header-section-number">6</span> Summary</h2>
<p>While, by definition, as methods are a special kind of function, both functions and methods perform similar roles by encapsulating code for reuse, methods are functions that live inside objects and are meant to operate on the data contained within those objects. Functions are more general-purpose and not tied to any particular data structure.</p>


</section>

 ]]></description>
  <category>engineering</category>
  <category>theory</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-06-01-an-exercise-in-semantics-method-vs-function-23gn.html</guid>
  <pubDate>Sat, 01 Jun 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Understanding database indexes - A simple analogy</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-05-29-understanding-database-indexes-a-simple-analogy-36be.html</link>
  <description><![CDATA[ 





<section id="tldr" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="tldr"><span class="header-section-number">1</span> TL;DR</h2>
<p>Think of how a DB index works as how a dictionary works: how it allows you to quickly find any word’s definition.</p>
</section>
<section id="introduction" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="introduction"><span class="header-section-number">2</span> Introduction</h2>
<p>When diving into the world of databases, one of the key concepts you’ll encounter is the database index. To make this idea more relatable, let’s compare it to something children learn to use at about ages from 7 to 9 and which we all know well—a word definition dictionary.</p>
<p>By the end of this post, you’ll see how this familiar tool can help you understand all types of database indexes.</p>
</section>
<section id="the-dictionary-analogy" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="the-dictionary-analogy"><span class="header-section-number">3</span> The Dictionary Analogy</h2>
<p>Think about a dictionary for a moment. When you need to find the definition of a word, you don’t start reading from the first page, hoping to stumble upon it. Instead, you take advantage of the dictionary’s organisation. Here’s how it works:</p>
<ol type="1">
<li><strong>Alphabetical Order</strong>: Words in a dictionary are sorted alphabetically. This sorting is crucial because it allows you to quickly jump to the section where the word should be.</li>
<li><strong>Index at the Top of the Page</strong>: Each page in the dictionary typically shows the first and last word on that page, giving you a quick reference to know if the word you’re looking for might be on that page.</li>
<li><strong>Quick Lookup</strong>: With this structure, you can find a word and its definition in seconds rather than minutes.</li>
</ol>
<section id="what-if-words-were-not-sorted" class="level3" data-number="3.1">
<h3 data-number="3.1" class="anchored" data-anchor-id="what-if-words-were-not-sorted"><span class="header-section-number">3.1</span> What If Words Were Not Sorted?</h3>
<section id="linear-search" class="level4" data-number="3.1.1">
<h4 data-number="3.1.1" class="anchored" data-anchor-id="linear-search"><span class="header-section-number">3.1.1</span> Linear search</h4>
<p>Imagine if the words in the dictionary were not sorted alphabetically. You’d have to start at the beginning and check each word one by one until you find the one you’re looking for. This method is called a <strong>linear search</strong>.</p>
<ol type="1">
<li>Start at the first word.</li>
<li>Check if it’s the word you need.</li>
<li>If not, move to the next word.</li>
<li>Repeat until you find the word.</li>
</ol>
<p>In the worst-case scenario, if the word you’re searching for is the last word in the dictionary, you would have to check all 5,000 words. Therefore, the maximum number of operations in the case of the linear search is 5,000. #### Other search strategies With other search strategies, like choosing a random word and repeating until you have picked the right one, the number of operations may be asymptotically infinite.</p>
<p>If you decided to choose a random word from the list of words that you have not picked yet, the maximum number of operations would be 5000, but you would also have to maintain a list of the words you already picked. This would neither be efficient in time nor in space (memory). ### Operations in a Sorted Dictionary</p>
<p>Let’s consider a dictionary with 5,000 words sorted alphabetically.</p>
<p>Because the words are sorted alphabetically, you can employ a <strong>binary search</strong> to find a word. Binary search is an efficient algorithm that repeatedly divides the search interval in half:</p>
<ol type="1">
<li>Start by looking at the middle word of the dictionary.</li>
<li>If the word you’re looking for comes before the middle word, narrow your search to the first half of the dictionary.</li>
<li>If the word comes after the middle word, narrow your search to the second half.</li>
<li>Repeat this process until you find the word.</li>
</ol>
<p>In a binary search, each step cuts the number of possible locations in half. Therefore, the maximum number of steps (or operations) needed is the logarithm of the number of words to the base 2, denoted as <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><mi>g</mi><msub><mo>⁡</mo><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mn>5000</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">log⁡_{2}(5000)</annotation></semantics></math>.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><mi>g</mi><msub><mo>⁡</mo><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mn>5000</mn><mo stretchy="false" form="postfix">)</mo><mo>≈</mo><mn>12.29</mn></mrow><annotation encoding="application/x-tex">
log⁡_{2}(5000) ≈ 12.29
</annotation></semantics></math></p>
<p>This means you can find any word in approximately 13 operations at most.</p>
<p><strong>Notes:</strong> - As we know the first letter of the word we search, we usually already approximate the position of the word when opening the dictionary: obviously, no need to start looking in the middle of the dictionary for a word starting with letter “c”. This usually allows us to remove a few search steps, reducing further the maximum number of steps to find a word to less than 12 in the case of a dictionary with 5000 words. - As the number of words in the dictionary increases, the gains increase as well because of the logarithmic scale, which increases at a slower rate than the size of the dictionary (compare <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math> to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><mi>g</mi><msub><mo>⁡</mo><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">log⁡_{2}(n)</annotation></semantics></math>). The gains provided by an index become greater as the number of entries grows. This is a key insight to understanding why queries on large tables (&gt;&gt; 100k rows) are still extremely fast despite the huge amount of data: <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><mi>g</mi><msub><mo>⁡</mo><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><msup><mn>10</mn><mn>5</mn></msup><mo stretchy="false" form="postfix">)</mo><mo>≈</mo><mn>16.61</mn></mrow><annotation encoding="application/x-tex">log⁡_{2}(10^5) ≈ 16.61</annotation></semantics></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>l</mi><mi>o</mi><mi>g</mi><msub><mo>⁡</mo><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><msup><mn>10</mn><mn>9</mn></msup><mo stretchy="false" form="postfix">)</mo><mo>≈</mo><mn>29.9</mn></mrow><annotation encoding="application/x-tex">log⁡_{2}(10^9) ≈ 29.9</annotation></semantics></math>.</p>
</section>
</section>
<section id="comparison" class="level3" data-number="3.2">
<h3 data-number="3.2" class="anchored" data-anchor-id="comparison"><span class="header-section-number">3.2</span> Comparison</h3>
<ul>
<li><strong>Sorted Dictionary (Binary Search)</strong>: Approximately 13 operations.</li>
<li><strong>Unsorted Dictionary (Linear Search)</strong>: Up to 5,000 operations.</li>
</ul>
<p>Now, let’s translate this process to the realm of databases. ## Translating to Databases</p>
</section>
<section id="what-is-a-database-index" class="level3" data-number="3.3">
<h3 data-number="3.3" class="anchored" data-anchor-id="what-is-a-database-index"><span class="header-section-number">3.3</span> What is a Database Index?</h3>
<p>A database index works similarly to the sorted dictionary, making it faster to find specific data in a database. Here’s how the analogy fits:</p>
<ul>
<li><strong>Sorted Order</strong>: Just like the words in a dictionary, data in an index is sorted in a specific order. This might be alphabetical, numerical, or based on another attribute.</li>
<li><strong>Index Entries</strong>: In a database, an index contains entries that are analogous to dictionary entries. Each entry in the index contains a key (like the word in a dictionary) and a reference to the actual data (like the definition in a dictionary).</li>
<li><strong>Efficient Lookup</strong>: When you search for data, the database uses the index to quickly locate the information, much like you use the dictionary’s alphabetical order to find a word.</li>
</ul>
<p>Using an index in a database is akin to using a binary search in a sorted dictionary—it’s efficient and significantly reduces the number of operations required to find the desired data. Without an index, the database would need to perform a linear search, scanning each row until it finds the matching data, which is far less efficient.</p>
<p><strong>Note:</strong> - This shows that a dictionary actually is an index. ### Types of Database Indexes</p>
<p>Let’s generalise this concept to different types of database indexes:</p>
<ol type="1">
<li><strong>B-Tree Indexes</strong>:
<ul>
<li><strong>How It Works</strong>: Similar to the alphabetical sorting in a dictionary, B-Tree indexes keep data sorted in a balanced tree structure. This ensures that the database can quickly navigate through the data to find what you need.</li>
<li><strong>Use Case</strong>: Ideal for range queries and when you need to sort data.</li>
</ul></li>
<li><strong>Hash Indexes</strong>:
<ul>
<li><strong>How It Works</strong>: Instead of sorting data, hash indexes use a hash function to distribute data evenly across a set of buckets. Think of it like using a special code to find the word directly rather than flipping through pages.</li>
<li><strong>Use Case</strong>: Perfect for exact match queries, where you need to find a specific entry quickly.</li>
</ul></li>
<li><strong>Bitmap Indexes</strong>:
<ul>
<li><strong>How It Works</strong>: Bitmap indexes use bitmaps (arrays of bits) to represent the presence of a value or combination of values. It’s like having multiple dictionaries where each dictionary represents a specific attribute of the words.</li>
<li><strong>Use Case</strong>: Useful in data warehousing for complex queries involving multiple attributes.</li>
</ul></li>
<li><strong>Full-Text Indexes</strong>:
<ul>
<li><strong>How It Works</strong>: These indexes are designed to handle full-text search capabilities. They index words and phrases, much like a detailed glossary or concordance.</li>
<li><strong>Use Case</strong>: Great for applications requiring search within large text fields, like articles or books.</li>
</ul></li>
</ol>
</section>
<section id="why-are-indexes-important" class="level3" data-number="3.4">
<h3 data-number="3.4" class="anchored" data-anchor-id="why-are-indexes-important"><span class="header-section-number">3.4</span> Why Are Indexes Important?</h3>
<p>Just as you wouldn’t want to read a dictionary cover to cover to find a word, you don’t want your database to scan through every record to find a piece of data. Indexes improve the efficiency and performance of your database queries, ensuring that information can be retrieved quickly and efficiently.</p>
<p>Without indexes, there is no magic: the database is forced systematically read each entry one by one until it finds a hit, potentially the last entry. This not only takes more time, it also consumes more CPU time and requires more I/O operations. ### Conclusion</p>
<p>A database index, much like a dictionary, is an essential tool for efficient information retrieval. Whether you’re using a B-Tree index, a hash index, a bitmap index, or a full-text index, the underlying principle remains the same: organising data in a way that makes it easy to find. By understanding this concept through the familiar analogy of a dictionary, you can better appreciate how indexes optimise database performance and make data retrieval a breeze.</p>


</section>
</section>

 ]]></description>
  <category>data</category>
  <category>engineering</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-05-29-understanding-database-indexes-a-simple-analogy-36be.html</guid>
  <pubDate>Wed, 29 May 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Understanding Certificates in the Digital World</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-05-28-understanding-certificates-in-the-digital-world-1bn6.html</link>
  <description><![CDATA[ 





<section id="tldr" class="level3" data-number="0.1">
<h3 data-number="0.1" class="anchored" data-anchor-id="tldr"><span class="header-section-number">0.1</span> TL;DR</h3>
<p>Digital certificates are the digital counterpart to physical ID cards or passports.</p>
<p>Their trustworthiness and validity stems from the reliability and credibility of the issuing entity (the CA, respectively the government).</p>
</section>
<section id="intro" class="level3" data-number="0.2">
<h3 data-number="0.2" class="anchored" data-anchor-id="intro"><span class="header-section-number">0.2</span> Intro</h3>
<p>In our increasingly digital world, ensuring security and authenticity online is more crucial than ever. Whether you’re shopping online, accessing your bank account, or simply browsing the web, the need for secure communication and trust in the entities you interact with cannot be overstated. This is where digital certificates come into play. Much like an ID card verifies your identity in the physical world, a digital certificate verifies identities and secures communications in the digital realm.</p>
<p>Let’s dive into what digital certificates are and how they function similarly to ID cards.</p>
</section>
<section id="what-is-a-digital-certificate" class="level3" data-number="0.3">
<h3 data-number="0.3" class="anchored" data-anchor-id="what-is-a-digital-certificate"><span class="header-section-number">0.3</span> What is a Digital Certificate?</h3>
<p>A digital certificate is a digital document used to authenticate the identity of an entity and establish secure communications. Entities can include websites, individuals, devices, or software. Think of it as a virtual passport that confirms the legitimacy of the entity and contributes to ensure that any data transmitted between you and the entity is secure (the certificate alone is not enough, the communication protocol is important as well).</p>
</section>
<section id="contents-of-a-digital-certificate" class="level3" data-number="0.4">
<h3 data-number="0.4" class="anchored" data-anchor-id="contents-of-a-digital-certificate"><span class="header-section-number">0.4</span> Contents of a Digital Certificate</h3>
<ol type="1">
<li><strong>Entity Information</strong>:
<ul>
<li><strong>Subject</strong>: The entity the certificate is issued to. For example, in an SSL/TLS certificate for a website, the subject is typically the domain name of the website.</li>
<li><strong>Issuer</strong>: The entity that issued the certificate. This is usually a Certificate Authority (CA).</li>
<li><strong>Serial Number</strong>: A unique identifier assigned by the issuer to the certificate.</li>
<li><strong>Validity Period</strong>: The period during which the certificate is considered valid, including a start date and an expiration date.</li>
</ul></li>
<li><strong>Public Key</strong>:
<ul>
<li>The public key of the entity, used for encryption, digital signatures, or both. This key is mathematically linked to a private key held by the entity.</li>
</ul></li>
<li><strong>Digital Signature</strong>:
<ul>
<li>A digital signature created by the issuer using its private key. It ensures the integrity and authenticity of the certificate. If the signature can be verified using the issuer’s public key, the certificate is considered valid.</li>
</ul></li>
<li><strong>Certificate Extensions</strong>:
<ul>
<li><strong>Key Usage</strong>: Specifies the cryptographic operations that the public key can be used for, such as encryption, digital signatures, or both.</li>
<li><strong>Subject Alternative Name (SAN)</strong>: Additional identities for which the certificate is valid, such as alternative domain names for a website.</li>
<li><strong>Basic Constraints</strong>: Specifies whether the certificate can be used as a Certificate Authority to issue other certificates.</li>
<li><strong>Extended Key Usage</strong>: Further specifies the purposes for which the public key can be used, such as client authentication, server authentication, or code signing.</li>
</ul></li>
</ol>
<blockquote class="blockquote">
<p><strong>Notes</strong> 1. A certificate is meant to be shared with other entities, which is why… 2. The private key is <em>not</em> part of the certificate. 3. The CA itself may be authenticated by another CA, which might as well be authenticated by another one and so on, until the root CA is attained: this is the CA trust chain.</p>
</blockquote>
</section>
<section id="how-does-an-id-card-work" class="level3" data-number="0.5">
<h3 data-number="0.5" class="anchored" data-anchor-id="how-does-an-id-card-work"><span class="header-section-number">0.5</span> How Does an ID Card Work?</h3>
<ol type="1">
<li><strong>Issuance of ID Card</strong>:
<ul>
<li>An individual provides personal information and undergoes identity verification by a relevant authority, such as a government agency or employer, to obtain an ID card.</li>
<li>The authority verifies the identity of the requester and issues the ID card containing their personal details and photograph.</li>
</ul></li>
<li><strong>Authentication and Identity Verification</strong>:
<ul>
<li>When presenting the ID card, the information on the card is compared with the individual presenting it to verify their identity.</li>
<li>This authentication process ensures that the person holding the ID card is indeed the legitimate cardholder and is authorised to access the services or privileges associated with the card.</li>
</ul></li>
<li><strong>Access to Privileges and Services</strong>:
<ul>
<li>ID cards grant access to various privileges and services based on the authority associated with the card. For example, a driver’s license grants the holder the privilege to operate a motor vehicle.</li>
<li>By presenting the ID card, individuals can access these privileges and services, ensuring that only authorised individuals benefit from them.</li>
</ul></li>
</ol>
</section>
<section id="how-does-a-digital-certificate-work" class="level3" data-number="0.6">
<h3 data-number="0.6" class="anchored" data-anchor-id="how-does-a-digital-certificate-work"><span class="header-section-number">0.6</span> How Does a Digital Certificate Work?</h3>
<ol type="1">
<li><p><strong>Certificate Issuance</strong>: An entity generates a public-private key pair and submits a certificate signing request (CSR) to a Certificate Authority (CA). The CA verifies the identity of the requester and issues a digital certificate containing the public key.</p></li>
<li><p><strong>Authentication and Secure Communication</strong>:</p>
<ul>
<li><strong>Websites</strong>: Your browser requests the site’s digital certificate and verifies it, ensuring you are communicating with the legitimate site.</li>
<li><strong>Emails</strong>: Email clients can use certificates to encrypt and sign emails, ensuring confidentiality and authenticity.</li>
<li><strong>Software</strong>: Developers sign their software with certificates to prove that it has not been tampered with.</li>
<li><strong>Individuals</strong>: Digital certificates can authenticate individuals for access to secure systems or documents.</li>
</ul></li>
</ol>
</section>
<section id="types-of-digital-certificates" class="level3" data-number="0.7">
<h3 data-number="0.7" class="anchored" data-anchor-id="types-of-digital-certificates"><span class="header-section-number">0.7</span> Types of Digital Certificates</h3>
<p>There are different times of digital certificates which serve different purposes:</p>
<ol type="1">
<li><strong>SSL/TLS Certificates</strong>: Secure communications between browsers and websites.</li>
<li><strong>Client Certificates</strong>: Authenticate users or devices to a server.</li>
<li><strong>Code Signing Certificates</strong>: Verify the identity of the software publisher and ensure the integrity of the software.</li>
<li><strong>Email Certificates (S/MIME Certificates)</strong>: Secure email communications by encrypting and signing emails.</li>
<li><strong>Document Signing Certificates</strong>: Digitally sign documents to ensure their authenticity and integrity.</li>
<li><strong>Root and Intermediate Certificates</strong>: Form the foundation of trust in the PKI hierarchy, used by Certificate Authorities to issue end-entity certificates.</li>
</ol>
<blockquote class="blockquote">
<p><strong>Types of government-issued IDs</strong> Governments typically issue various types of identification documents to their citizens, residents, and other individuals. These IDs serve different purposes and may vary depending on the country and its regulations. Here are some common types of IDs issued by governments: 1. <strong>National Identity Cards (NIC)</strong>: - National identity cards are government-issued documents that serve as official proof of identity for citizens or residents. They typically include the individual’s name, photograph, date of birth, and sometimes other identifying information such as address or identification number. 2. <strong>Passports</strong>: - Passports are travel documents issued by governments to their citizens for international travel. They contain personal information about the passport holder, including their photograph, nationality, date of birth, and passport number. 3. <strong>Driver’s Licenses</strong>: - Driver’s licenses are issued by government agencies to individuals who have passed the required tests to operate motor vehicles legally. In addition to serving as proof of identity, driver’s licenses also indicate the holder’s authorisation to drive specific types of vehicles. 4. <strong>Social Security Cards</strong>: - Social Security cards are issued in some countries to individuals who have registered for government social security programs. They typically contain a unique identification number assigned to the individual for tracking purposes. 5. <strong>Residence Permits</strong>: - Residence permits are issued to non-citizen residents by governments to legally reside in a country for a specified period. These documents typically include the individual’s name, photograph, and information about their immigration status. 6. <strong>Voter ID Cards</strong>: - Voter ID cards are issued to eligible voters by election authorities to facilitate voting in elections. They serve as proof of identity and eligibility to vote. 7. <strong>Military IDs</strong>: - Military identification cards are issued to members of the armed forces and their dependent. They serve as proof of military affiliation and may grant access to military facilities and services. 8. <strong>Government Employee IDs</strong>: - Government employee IDs are issued to individuals employed by government agencies. They serve as proof of employment and may grant access to government facilities and services.</p>
<p>These are just a few examples of the types of IDs that governments commonly issue. The &gt; specific types and requirements for obtaining them vary by country and jurisdiction.</p>
</blockquote>
</section>
<section id="digital-certificates-vs.-id-cards-the-similarities" class="level3" data-number="0.8">
<h3 data-number="0.8" class="anchored" data-anchor-id="digital-certificates-vs.-id-cards-the-similarities"><span class="header-section-number">0.8</span> Digital Certificates vs.&nbsp;ID Cards: The Similarities</h3>
<p>Usually, the government trusts local authorities (municipality) to authenticate a person and to make the ID request. The government then creates the ID, which is then handed to the person by the requesting local authority. The role of the government is similar to the role of a CA.</p>
<p>People and organisations usually trust the government-delivered ID: sometimes, this is even mandated by law. This trust in the government is what makes this system robust - whether one likes the government or not.</p>
<ol type="1">
<li><strong>Identity Verification</strong>:
<ul>
<li><strong>ID Card</strong>: Confirms your identity with personal details and a photograph, typically issued by a government or other trusted entity.</li>
<li><strong>Digital Certificate</strong>: Confirms the identity of an entity, typically issued by a trusted CA after verifying the entity’s credentials.</li>
</ul></li>
<li><strong>Trust</strong>:
<ul>
<li><strong>ID Card</strong>: We trust ID cards because they are issued by recognised authorities like governments.</li>
<li><strong>Digital Certificate</strong>: We trust digital certificates because they are issued by recognised CAs, which follow rigorous verification processes.</li>
</ul></li>
<li><strong>Authentication</strong>:
<ul>
<li><strong>ID Card</strong>: Used to prove your identity when accessing restricted areas, conducting transactions, or during identification checks.</li>
<li><strong>Digital Certificate</strong>: Used to prove the identity of an entity, ensuring secure and authenticated communications.</li>
</ul></li>
<li><strong>Security Features</strong>:
<ul>
<li><strong>ID Card</strong>: Contains physical security features like holograms, watermarks, and micro-printing to prevent forgery.</li>
<li><strong>Digital Certificate</strong>: Contains cryptographic elements like public keys and digital signatures to prevent tampering and ensure authenticity.</li>
</ul></li>
<li><strong>Validity period:</strong>
<ul>
<li><strong>ID Card</strong>: Has an expiration date.</li>
<li><strong>Digital Certificate</strong>: Has a limited validity period which specifies the time frame during which it is considered valid and trustworthy. After the expiration date, the certificate is no longer considered valid, and relying parties should not trust it for secure communications.</li>
</ul></li>
<li><strong>Renewal Process:</strong>
<ul>
<li><strong>ID Card</strong>: Must be renewed before it expires. Renewal typically involves obtaining a new ID from the issuing government and only using the new one (in some countries, authorities may even require that old IDs are given back to the government).</li>
<li><strong>Digital Certificate</strong>: Must be renew by their holders before they expire to ensure uninterrupted secure communication. Renewal typically involves obtaining a new certificate from the issuing Certificate Authority (CA) and replacing the old certificate with the new one.</li>
</ul></li>
<li><strong>Types:</strong>
<ul>
<li><strong>ID Card:</strong> Various types of IDs are issued by governments and are used for different purposes.</li>
<li><strong>Digital Certificate:</strong> Various types of digital certificates are used for different purposes.</li>
</ul></li>
</ol>
</section>
<section id="practical-examples-of-digital-certificates-in-use" class="level3" data-number="0.9">
<h3 data-number="0.9" class="anchored" data-anchor-id="practical-examples-of-digital-certificates-in-use"><span class="header-section-number">0.9</span> Practical Examples of Digital Certificates in Use</h3>
<ol type="1">
<li><p><strong>Secure Web Browsing</strong>: When you visit a website starting with <code>https://</code>, the communication protocol and the site’s digital certificate ensure that your communication with the site is encrypted and secure, protecting sensitive information like passwords and credit card numbers.</p></li>
<li><p><strong>Email Security</strong>: Digital certificates can secure email communications by encrypting emails and enabling digital signatures, ensuring that your emails are confidential and authenticated.</p></li>
<li><p><strong>Software Integrity</strong>: Developers use digital certificates to sign software, ensuring users that the software has not been tampered with and is from a legitimate source.</p></li>
<li><p><strong>Individual Authentication</strong>: Organisations issue digital certificates to employees, enabling secure access to corporate systems and data. These certificates ensure that only authorised individuals can access sensitive information.</p></li>
<li><p><strong>Document Signing</strong>: Digital certificates are used to sign electronic documents, providing a digital equivalent of a handwritten signature and ensuring the document’s integrity and authenticity.</p></li>
</ol>
</section>
<section id="conclusion" class="level3" data-number="0.10">
<h3 data-number="0.10" class="anchored" data-anchor-id="conclusion"><span class="header-section-number">0.10</span> Conclusion</h3>
<p>Digital certificates play a vital role in maintaining trust and security in the digital world, much like ID cards do in the physical world. They verify the identities of entities, establish secure communications, and ensure data integrity. By understanding how digital certificates function and their similarities to ID cards, we can better appreciate the underlying mechanisms that keep our online interactions safe and trustworthy. So next time you encounter a digital certificate, you’ll know that it is hard at work, verifying identities and securing your digital environment.</p>


</section>

 ]]></description>
  <category>systems</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-05-28-understanding-certificates-in-the-digital-world-1bn6.html</guid>
  <pubDate>Tue, 28 May 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>File Locking (and the JVM)</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-01-12-file-locking-and-the-jvm-56ll.html</link>
  <description><![CDATA[ 





<p>I originally posted this on 2010/07/23 on my personal blog.</p>
<hr>
<p>File locks control access to a file or a range of bytes within a file. This is necessary in situations where multiple simultaneously executing programs need to modify the same file.</p>
<p>File locking functionalities are provided within the NIO API, or more specifically in the <code>java.nio.channels</code> package.</p>
<p>The two most important classes for file locking are <code>java.nio.channels.FileChannel</code> and <code>java.nio.channels.FileLock</code>.</p>
<p>Several methods provide file locking:</p>
<pre><code>FileLock FileChannel.lock()
FileLock FileChannel.lock(long position, long size, boolean shared)
FileLock FileChannel.tryLock()
FileLock FileChannel.tryLock(long position, long size, boolean shared)</code></pre>
<p><code>lock()</code> acquires an exclusive lock on the entire file, and blocks until the lock is acquired, <code>tryLock()</code> is identical but returns <code>null</code> if the lock cannot be acquired. The methods with parameters lock only regions of a file, the shared parameter is <code>true</code> for a shared lock and <code>false</code> for an exclusive lock.</p>
<p>A shared lock prevents other concurrently-running programs from acquiring an overlapping exclusive lock, but does allow them to acquire overlapping shared locks. An exclusive lock prevents other programs from acquiring an overlapping lock of either type.</p>
<p>Once you don’t need the lock anymore, release it with <code>FileLock.release()</code>.</p>
<p>That seems to be a great solution, but there are limitations, related to the operating system the JVM runs on:</p>
<ul>
<li>Some systems only provide advisory file locking: applications that don’t acquire locks may still write the file.</li>
<li>Some systems make it impossible to lock a file and map it into memory. On those, you won’t be able to use a <code>MappedByteBuffer</code> to access file.</li>
<li>File locks are held by the Java Virtual Machine, not by individual programs. Two programs in the same JVM won’t be able to simultaneously acquire a lock on the same file.</li>
<li>Opening multiple channels on the same locked file should be avoided, as on some systems, closing a channel on a file releases all locks on the file held by the same JVM.</li>
<li>On networked file systems, file locking should be avoided – or at least, relying on file locking mechanisms should be avoided, as it’s dependent on the networked file system implementation.</li>
</ul>



 ]]></description>
  <category>languages</category>
  <category>systems</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-01-12-file-locking-and-the-jvm-56ll.html</guid>
  <pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Installing Archlinux with software raid1, encrypted filesystem and LVM2</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-01-12-installing-archlinux-with-software-raid1-encrypted-filesystem-and-lvm2-hei.html</link>
  <description><![CDATA[ 





<p>I wrote that article for my personal blog 2010-08-01, so it may be a bit outdated, yet the info might still be useful, so here it is.</p>
<p>I have not tested this setup with a recently, so please be aware that the described steps may not work with an up-to-date ArchLinux version.</p>
<hr>
<p>On the web, you’ll find how to setup <a href="https://archlinux.org/">ArchLinux</a> with <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a>, or with <a href="https://en.wikipedia.org/wiki/RAID">RAID</a>, or with encryption, but not with the combination of these three technologies. This article explains the different steps I took to setup these three technologies with <a href="https://archlinux.org/">ArchLinux</a>.</p>
<section id="required-skills" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="required-skills"><span class="header-section-number">1</span> Required skills</h2>
<p>Sound understanding of Linux (<a href="https://archlinux.org/">ArchLinux</a> specifics may be useful…) and <a href="https://en.wikipedia.org/wiki/RAID">RAID</a>, <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM2</a>, partitioning, encryption.</p>
</section>
<section id="the-story" class="level2" data-number="2">
<h2 data-number="2" class="anchored" data-anchor-id="the-story"><span class="header-section-number">2</span> The story</h2>
<p>During the last days I reinstalled my server (AMD x86_64), which runs several <a href="https://www.virtualbox.org/">VirtualBox</a> VMs, with <a href="https://archlinux.org/">ArchLinux</a>.</p>
<p>It’s a simple PC with 3 hard drives: one for the OS and two 500GB drives which hold my data and VMs.</p>
<p>Here’s the detail of my hard disk setup:</p>
<ul>
<li>The OS hard drive: This one is encrypted using LUKS and then runs <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a> for the partitioning. There are 2 primary partitions: one for /boot, not encrypted, and one which contains the encrypted <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a> partitions. Thus, the root partition is encrypted and on <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a>, which needs specific setup in Grub.</li>
<li>The 2 data hard drives: These are <a href="https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_1">raid-1</a> (simple duplication), the raid array is encrypted, and the partitioning is done using <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a>. The array only contains 1 single primary partition, spanning the whole space and containing the <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a> partitions.</li>
</ul>
<p>I never dared install <a href="https://archlinux.org/">ArchLinux</a> on top of this setup before (so I ran my server using <a href="https://www.opensuse.org/">openSUSE</a>, and recently <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a>), because of the not so user friendly <a href="https://archlinux.org/">ArchLinux</a> install software. I added encryption to my setup when I installed <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a>, using the Fedora installer Anaconda. But some days ago, as I encountered several issues using <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a>, I decided to give <a href="https://archlinux.org/">ArchLinux</a> a try. Please note that I was really surprised by the <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a> release (it’s quite slick and very stable), but <a href="https://archlinux.org/">ArchLinux</a> (the control I have over it and the gargantuous software collection it provides) is better suited to my advanced needs. More precisely, in <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a>, I’ve found nothing as easy as <code>netcfg</code> to setup my network interfaces like I wanted (quite complicated, not explained here). So here are the steps:</p>
</section>
<section id="hard-drive-setup" class="level2" data-number="3">
<h2 data-number="3" class="anchored" data-anchor-id="hard-drive-setup"><span class="header-section-number">3</span> Hard drive setup</h2>
<p>Setup the hard drives (partitioning, RAID-1 and LVM2) with the <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a> installer Anaconda. Simply put in the <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a> install disk and make a simple install with the correct disk setup you need. The installed OS will be of no use, the purpose here is to setup the disks, not the OS. The <a href="https://fedoraproject.org/">Fedora</a> <a href="https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/13/">13</a> install software is very easy to use, as the hard drive setup is visual. <a href="https://www.opensuse.org/">openSUSE</a> may be OK as well, as <a href="https://yast.opensuse.org/">Yast</a> is visual and easy to use as well.</p>
</section>
<section id="archlinux-installation" class="level2" data-number="4">
<h2 data-number="4" class="anchored" data-anchor-id="archlinux-installation"><span class="header-section-number">4</span> <a href="https://archlinux.org/">ArchLinux</a> installation</h2>
<p>Boot using the <a href="https://archlinux.org/">ArchLinux</a> <a href="https://archlinux.org/download/">Install CD</a>. Choose the correct keymap for your PC:</p>
<pre><code>km</code></pre>
<p>Load the encryption, <a href="https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_1">raid1</a> and LVM modules:</p>
<pre><code>modprobe dm-crypt
modprobe dm-mod
modprobe raid1</code></pre>
<p>Assemble the raid (as it was created with the Fedora 13 installer, there is no need to create it):</p>
<pre><code>mdadm -A /dev/md0 /dev/sdc1 /dev/sdb1</code></pre>
<p>Setup encryption on the OS hard drive and the data array (again, as the encrypted drives already exist, there is no need to create them, simply open them with your passphrases):</p>
<pre><code>cryptsetup luksOpen /dev/sda2 system
cryptsetup luksOpen /dev/md0 data</code></pre>
<p>Scan for <a href="https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux)">LVM</a> volume groups and keep them in memory:</p>
<pre><code>vgscan
vgchange -ay</code></pre>
<p>Then run the <a href="https://archlinux.org/">ArchLinux</a> install software:</p>
<pre><code>/arch/setup</code></pre>
<p>Configure your installation (use the existing partitions!) until when packages were installed. Immediately after package installation, change to another terminal with the key combination <code>CTRL-ALT-F2</code>, and login as root. Now, replace the <code>mdadm.conf</code> file by the one corresponding to your setup (this step is needed, as this file is used to generate the initrd image with <code>mkinitcpio</code>):</p>
<pre><code>rm /mnt/etc/mdadm.conf
mdadm --examine --scan &gt;&gt; /mnt/etc/mdadm.conf</code></pre>
<p>Come back to the install software with the key combination <code>CTRL-ALT-F1</code>. Now, in the install software, edit your configuration files:</p>
<section id="rc.conf" class="level3" data-number="4.1">
<h3 data-number="4.1" class="anchored" data-anchor-id="rc.conf"><span class="header-section-number">4.1</span> <code>rc.conf</code></h3>
<pre><code>USELVM=yes
KEYMAP=be-latin1</code></pre>
<p>You may replace <code>be-latin1</code> with your keymap.</p>
</section>
<section id="mkinitcpio.conf" class="level3" data-number="4.2">
<h3 data-number="4.2" class="anchored" data-anchor-id="mkinitcpio.conf"><span class="header-section-number">4.2</span> <code>mkinitcpio.conf</code></h3>
<pre><code>MODULES=(... dm-mod dm-crypt aes_x86_64 raid1 ...)
HOOKS=(... mdadm keymap encrypt lvm2 filesystems...)</code></pre>
<p>The order in the <code>HOOKS</code> array is very important:</p>
<ul>
<li><code>keymap</code> permits to set the keymap before the encryption password for the drives is required.</li>
<li><code>encrypt</code> is necessary to decrypt the drives, which allows content access to <code>lvm2</code></li>
<li><code>lvm2</code> provides partitions, which are needed to mount the filesystems</li>
</ul>
<p>I think the <code>mdadm</code> hook is not needed, as the root partition is not on top of a raid. But if it was, it would be required! Based on your setup (lvm2 over encryption over raid, encryption of single lvm2 drives,…), the order may change, so your understanding of how these technologies are set up on your drives really is relevant.</p>
</section>
<section id="locale.gen" class="level3" data-number="4.3">
<h3 data-number="4.3" class="anchored" data-anchor-id="locale.gen"><span class="header-section-number">4.3</span> <code>locale.gen</code></h3>
<p>Remove the leading dashes (<code>#</code>) in front of your locale.</p>
</section>
<section id="pacman.conf" class="level3" data-number="4.4">
<h3 data-number="4.4" class="anchored" data-anchor-id="pacman.conf"><span class="header-section-number">4.4</span> <code>pacman.conf</code></h3>
<p>Strictly speaking, this is not needed at all for this setup, but I can’t imagine using <a href="https://archlinux.org/">ArchLinux</a> without this repository, so I always enable it:</p>
<pre><code>[archlinuxfr]
Server = http://repo.archlinux.fr/x86_64</code></pre>
<p>Now validate your config files. The system launches <code>mkinitcpio</code>, which generates <code>initrd</code> images. Now edit your <code>menu.lst</code> file. Add <code>cryptdevice=/dev/sda2:vg_system</code> to the kernel line (adapt it to your config, replace <code>sda2</code> by your encrypted partition and <code>vg_system</code> by your LVM2 volume group’s name). Following are my configurations:</p>
<pre><code># (0) Arch Linux
title  Arch Linux
root   (hd0,0)
kernel /vmlinuz26 root=/dev/mapper/vg_system-root cryptdevice=/dev/sda2:vg_system ro
initrd /kernel26.img

# (1) Arch Linux
title  Arch Linux Fallback
root   (hd0,0)
kernel /vmlinuz26 root=/dev/mapper/vg_system-root cryptdevice=/dev/sda2:vg_system ro
initrd /kernel26-fallback.img</code></pre>
<p>Save the file, install <code>grub</code> to your MBR. Now, to automatically mount the encrypted data partitions (those on the raid1), the system must know your passphrase. That’s the purpose of the <code>/etc/crypttab</code> file.</p>
<pre><code>nano /mnt/etc/crypttab</code></pre>
<p>Add the line:</p>
<pre><code>data /dev/md0 PASSPHRASE</code></pre>
<pre><code>The device `/dev/md0` should be the same as the one in `/etc/mdadm.conf`.
Replace `PASSPHRASE` with the one you chose for your system.
Make sure `/etc/crypttab` is only readable by root, or maybe someone else may read your passphrase!</code></pre>
<p>The use of <code>/etc/crypttab</code> conveniently avoids asking the user for two passphrases, one for the OS encrypted drive and one for the data encrypted drive. At boot, you enter your OS-encrypted-partition passphrase, and then the system reads <code>/etc/crypttab</code> to decrypt the data-encrypted-partition.</p>
</section>
</section>
<section id="enjoy" class="level2" data-number="5">
<h2 data-number="5" class="anchored" data-anchor-id="enjoy"><span class="header-section-number">5</span> Enjoy!</h2>
<p>Now, if everything went fine, you may reboot and enjoy using your fresh <a href="https://archlinux.org/">ArchLinux</a> system.</p>
<p>Should there be some steps you don’t understand or with errors, feel free to leave a comment, I’ll do the corrections.</p>


</section>

 ]]></description>
  <category>systems</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-01-12-installing-archlinux-with-software-raid1-encrypted-filesystem-and-lvm2-hei.html</guid>
  <pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Stressnet</title>
  <link>https://yannickloth.github.io/independentvariation/posts/2024-01-12-stressnet-4n15.html</link>
  <description><![CDATA[ 





<p>This is a post from my personal blog, more than a decade ago. Though it contains the source code retrieved from that time, I have not tried to build and run it. I publish it for informational and archival purposes only.</p>
<hr>
<p>The <em>Development of an application framework to test intrusion detection systems</em> was the subject of my internship (3rd year Industrial Engineering in Applied Computer Sciences, <a href="http://www.uni.lu">University of Luxembourg</a>) from February 2005 to June 2005 at the <a href="http://www.rma.ac.be">Royal Military Academy</a> (RMA) in Brussels, Belgium.</p>
<p>The main goal was to develop an application (called <em>stressnet</em>) and the scripts that go with it, on a x86-compatible computer with Linux 2.6. The application has be able to read packets from <code>tcpdump</code>-formatted files and to send them with a reliable bitrate over the network.</p>
<p><em>stressnet</em> is a general purpose packet generator, which should achieve to reach high bitrates reliably (this means if a user asks to send packets with 150Mbit/s, it should be close to this value, not for example 100Mbit/s or 200 Mbit/s). Actually, the relative bitrate error rises till 0.001 for bitrates to 100Mbit/s and till 0.01 for bitrates around 150Mbit/s, which is a quite good result and sufficiently precise for the expected use of Stressnet.</p>
<p>Once this application was developed, some tests were done to show how to use this framework and to show how to interpret the results.</p>
<p>The IDS which we tested was the Open Source software IDS <a href="https://www.snort.org/">Snort</a>. Of course one can test other intrusion detection systems, <a href="https://www.snort.org/">Snort</a> has only been chosen because it is popular and because there was another research concerning <a href="https://www.snort.org/">Snort</a> at the RMA.</p>
<ul>
<li>University of Luxembourg: <a href="http://www.uni.lu">http://www.uni.lu</a></li>
<li>Royal Military Academy of Belgium: <a href="http://www.rma.ac.be">http://www.rma.ac.be</a></li>
<li>Snort: <a href="http://www.snort.org">http://www.snort.org</a></li>
</ul>
<section id="files" class="level2" data-number="1">
<h2 data-number="1" class="anchored" data-anchor-id="files"><span class="header-section-number">1</span> Files</h2>
<ul>
<li><a href="https://raw.githubusercontent.com/yannickloth/stressnet/main/presentation.pdf">Presentation slides</a></li>
<li><a href="https://raw.githubusercontent.com/yannickloth/stressnet/7af6dc75f38cc6703886ba25fc674ec3759c7399/RAPPORT_FINAL.pdf">Final report</a></li>
<li><a href="https://github.com/yannickloth/stressnet">Source code</a></li>
</ul>


</section>

 ]]></description>
  <category>systems</category>
  <guid>https://yannickloth.github.io/independentvariation/posts/2024-01-12-stressnet-4n15.html</guid>
  <pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
