A1.02 · Pragmatic, revisited · dive 3
Orthogonality and blast radius
Two components are orthogonal when changing one does not change the other — so a change stays contained, and a contained change is one a reviewer can hold in their head.
The Pragmatic Programmer argued that orthogonal systems are easier to change and test. For an agent it sharpens: orthogonality bounds a change's blast radius, and a bounded blast radius is the difference between a diff a human can review and one they cannot. Switch the wiring, then read the blast set of changing one surface.
Change one surface · watch what it can break
What orthogonality actually is
Orthogonality is a borrowed word: two axes are orthogonal when moving along one does not move you along the other. In software, two components are orthogonal when changing one does not change the other. The way to get there is information hiding — a component depends on another's facade, a stable interface, and never on its internals. Then the internals can change underneath, and the callers do not notice.
The opposite is coupling: one component reaches into another's internals, so a change to those internals ripples outward. The reach of that ripple has a name — the blast radius — and it is the set of modules a change can affect: the changed module, plus everything that depends on it, transitively. Orthogonality is what keeps that set small.
- orthogonality
- Independent components — each changeable without rippling into the others, because each depends on a facade, not on another's internals.
- blast radius
- The set of modules a change can affect: the changed module plus everything that depends on it, transitively.
- facade
- A stable interface a surface depends on, so its internals can change without touching its callers.
- agent-era reading
- A reviewer holds a bounded amount in mind. A small blast radius makes a diff that fits that bound — reviewable, acceptable. Coupling unbounds the radius and the agent's diff becomes unreviewable, however correct each line looks.
Orthogonality is the third re-weighted principle, and the one that ties the module together: DRY gives a fact one home, Design by Contract gives a unit a precise spec, and orthogonality keeps those units independent — so a change to one stays a change to one.
The consequence: a reviewable diff
An agent will produce a change that is locally correct — each line defensible — and still hand you a diff you cannot accept, because the change touched a coupled module and the ripple reached six others. The acceptance question is not “is this line right?” but “can I see everything this change can break?” That second question is the blast radius, and orthogonality is the lever on it.
The direct radius is the changed module plus everything coupled to it. For a module coupled to c others, that is 1 + c — the module itself, plus the c that can break with it. Step the slider: the radius is the count, and the diff is acceptable only while that count still fits in a review. The orthogonal case is c = 0: radius 1, a change that is only itself.
The blast-radius bill · move the slider
Orthogonality is not tidiness. It is the property that keeps an agent's diff inside what a human can review.
Five surfaces, one facade on the Portal
The Portal — the learning platform this course builds — has five surfaces: the store, the event-sourced events engine, the web app on Phoenix, the Telegram bot, and the student dashboard. The orthogonal wiring is the one the hero shows: each surface depends on the events facade, events depends on the store, and no surface reaches into another surface's internals. A change to the dashboard touches the dashboard alone. Its blast radius is one.
Couple them — let the bot read the web's internals, the dashboard read the bot's — and a change to one surface now risks the others, so its diff can no longer be reviewed in isolation. The repair is not cleverness; it is naming each surface's facade and pointing every caller, agent included, at the facade rather than at the internals behind it.
# Orthogonal: every surface depends on the events facade — not on each other. # A change inside one surface stays inside it; its blast radius is one. events |> events_facade() # web/, bot/, dashboard/ all derive from the same facade # Coupled: a surface reaches past the facade into another surface's internals. # Now a change inside web can break bot and dashboard — the radius is three. web_internal_state |> read_directly() # bot/, dashboard/ reach into web/ (a coupling)
The facades above are conceptual — the point is the shape of the dependency, not a module name. The Portal's surface design is taught in the companion Functional Programming in Elixir course.
The principle
Orthogonal components change without rippling into each other. A change to one stays a change to one, because each depends on a facade, not on another's internals.
On the Portal
Each surface sits behind the events facade. A change to one surface keeps its blast radius to one — a diff a reviewer can accept without tracing the whole system.
A bounded blast radius is the property that makes an agent's surface change ownable: one diff, one surface, nothing else to trace.
Recap — why the module holds together
A1.02 re-read three Pragmatic principles for the agent era, and they stack into one answer. DRY gives a fact one authoritative home, so generation cannot quietly fork the truth. Design by contract gives a unit a precise pre/post/invariant specification, so an agent has something exact to implement against and you have something exact to accept against. Orthogonality keeps those units independent, so a change to one stays a bounded, reviewable diff.
Read in order, they are a progression from knowledge to specification to structure: a fact has one home; a unit has one contract; a change has one bounded blast radius. Together they are why an agent's work stays ownable — one authority to point at, one contract to accept against, one bounded diff to review. The next chapters turn that ownability into a workflow: decomposition, the roadmap, and the spec the agent is briefed from.
A1.02 closes here. From the module hub, the course moves from why these principles are re-weighted to how the workflow puts them to work — starting with decomposition in A2.
References
Primary sources for orthogonality, modularity, and information hiding, and where this connects in the course.
Sources
- Hunt & Thomas — The Pragmatic Programmer — “Orthogonality”: independent components that change without rippling.
- Parnas, D.L. — On the Criteria To Be Used in Decomposing Systems into Modules — information hiding: hide each design decision behind a stable interface (CACM, 1972).
- Meyer, B. — Object-Oriented Software Construction — the modularity criteria: decomposability, composability, and continuity.
Related in this course
- A1.02 · Pragmatic Programming, revisited — the module hub.
- A1.02.1 · The single source of truth — knowledge has one home.
- A1.02.2 · Design by contract — a unit has a precise spec.
- A1.01.3 · Thin slices — sizing a change so its diff stays reviewable.
- A1 · Why an agile agent workflow