Abstraction-Barrier Code Review¶
Code review — instantiates Representation-Independent Interface Contract
A code review read through a single lens — is anything here reaching past a component's public surface into its internals? — that sends reach-throughs back before the coupling hardens.
An Abstraction-Barrier Code Review is an ordinary code review narrowed to one question: does this change respect the abstraction barrier, or does it reach past a component's published surface to depend on how that component happens to work today? Its distinctive contribution is human judgment about intent — deciding whether a dependency is a fair reading of the contract or an accident of the current representation — which no compiler flags, because the code compiles perfectly either way. Where an Opaque Type or Module Boundary enforces hiding mechanically and a Representation Leakage Probe detects leaks automatically, this mechanism is the social line of defense that catches the coupling those miss and rules on the cases they cannot.
Example¶
A pull request in a web backend adds a feature that iterates the result of getUsers() and treats the first entry as the most recently created account — quietly relying on the fact that the current implementation returns rows in insertion order from a hash map. The reviewer flags it. The contract of getUsers() promises the set of users, not an order; the ordering is an artifact of today's storage. It works now, but the day someone swaps the map, adds a cache, or shards the table, the feature breaks silently and far from this diff.
The reviewer requires an explicit sortBy(createdAt) — making the dependency legitimate and visible — or, if creation-order really should be part of the promise, a deliberate change to the contract rather than a silent lean on the representation. The reach-through is stopped at review time, where it costs a comment, rather than after a storage change turns it into a production incident nobody can trace. This is precisely the accretion Hyrum's Law describes: with enough clients, every observable behavior eventually gets depended on unless someone holds the line.[1]
How it works¶
- Locate the barrier for each touched component: what is public contract versus internal representation.
- Trace each new client dependency and ask the defining question — is this part of the promised contract, or an accident of the current internals?
- Check the producer side isn't newly exposing internals: returning a mutable internal collection, leaking a private type, widening visibility "just for now."
- Record recurring reach-throughs so the barrier can be made explicit (a contract clause, an opaque type) and the same leak designed out rather than re-caught.
The judgment call in step two — is this fair to depend on? — is the human core; the rest is discipline around it.
Tuning parameters¶
- Barrier strictness — how puritanically reach-throughs are rejected. Strict protects re-representation freedom but slows delivery and can read as pedantry.
- Review scope — every change versus only diffs that cross known-fragile boundaries. Targeting the risky seams spends scarce reviewer attention where it pays.
- Checklist versus judgment — how much rides on a fixed leak-pattern checklist versus reviewer intuition. Checklists scale and train juniors; intuition catches the novel leak no list anticipated.
- Enforcement teeth — advisory comment versus merge-blocking. Blocking holds the line but adds friction and can be waived under deadline.
- Feedback into design — whether caught reach-throughs feed back into making the boundary mechanical, so the review stops re-catching the same class of leak.
When it helps, and when it misleads¶
Its strength is reasoning the machines can't: it is the only mechanism here that weighs intent and judges behavior that is technically observable but not promised. Its failure modes are human. Reviewer fatigue and inconsistency mean the barrier is only as strong as the most lenient reviewer on a busy afternoon; it scales poorly and is the first thing waived when a release is late; and it can ossify into nitpicking that blocks legitimate change under the banner of "abstraction." The classic misuse is the rubber stamp — approving to unblock a teammate while the reach-through slips through — or, inversely, invoking "abstraction" to justify a rejection already decided on other grounds. The discipline that keeps it honest is to pair it with mechanical enforcement (opaque types, leakage probes) so the review spends itself on judgment rather than detection, and to record each ruling so the boundary is defined once, not re-argued every pull request.
How it implements the components¶
This mechanism supplies the human enforcement and inventory side of the archetype:
client_dependency_inventory— the review traces and records what each client actually depends on, separating promised contract from incidental reliance.representation_hiding_boundary— it holds the boundary socially, rejecting changes that reach across it in either direction.observable_leakage_watchlist— it works from a running list of known leak patterns (order reliance, mutable returns, widened visibility) to scan each diff against.
It does not state the contract being protected (the Design-by-Contract Clause and Interface Definition Language do), enforce hiding at the language level (the Opaque Type or Module Boundary), or detect leaks automatically (the Representation Leakage Probe). Its opaque-type and probe siblings provide the mechanical counterparts to the same boundary it guards by hand.
Related¶
- Instantiates: Representation-Independent Interface Contract — it defends the boundary the other mechanisms declare and test.
- Consumes: Interface Definition Language and the declared boundary tell the reviewer what is public versus internal.
- Sibling mechanisms: Opaque Type or Module Boundary · Representation Leakage Probe · Design-by-Contract Clause · Interface Definition Language · Black-Box Contract Test Suite · Semantic Versioning and Deprecation Gate
Notes¶
This is a backstop, not a barrier. Because detection rides on human attention, it is strongest when the boundary is also enforced mechanically — the review then handles the judgment calls machines can't, instead of being the sole thing standing between a client and a component's internals. As the only line of defense it will eventually fail under load; that failure is a signal to make the barrier mechanical, not to review harder.
References¶
[1] Hyrum's Law — "with a sufficient number of users of an interface, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody." It names exactly the drift this review resists, and complements Parnas's older principle of information hiding, which prescribes putting likely-to-change decisions behind a stable interface in the first place. ↩