Pattern · seen in 1 breakdown across 1 company

Compile-Time Boundary Enforcement

Definition

Declare an architectural boundary as data, then enforce it with automated checks that fail the build — or flag the violation in development — whenever code crosses it. The boundary becomes real the day it is declared, not the day the underlying systems are actually separated: developers hit violations at their desks, CI blocks new coupling from landing, and existing violations are converted into an explicit, annotated backlog that must reach zero before the physical separation can proceed.

The pattern's power is temporal. Long-running migrations — splitting a database, extracting a service, partitioning a module — take months or years, and during that window the codebase keeps changing under the migration's feet. Enforcement at development time freezes the boundary's erosion: the migration can only move forward, because regressions are build failures rather than operational surprises discovered after data has moved.

Static checks cannot see everything — dynamically constructed queries, runtime reflection, and cross-cutting transactions evade them — so mature implementations pair the compile-time check with a sampled runtime check in production that maps where the boundary is actually crossed, feeding the burndown list.

When it applies

01Splitting a database, monolith, or module estate where the separation will take months and the code keeps evolving meanwhile
02Enforcing ownership or dependency boundaries between teams sharing one codebase
03Preventing regression during any long-running migration whose invariant can be expressed as 'this code must not reference that'

Tradeoffs

Exemption annotations institutionalize debt: the checker stops new violations but cannot burn down old ones — that remains sustained human work the tool merely makes visible
Static analysis misses runtime-constructed access; a production-side sampled check is usually needed to close the gap
The tool enforces whatever boundary was declared — a wrong domain decomposition gets enforced just as rigorously as a right one

The same move, 1 ways

Every row is a production system that bet on this pattern — the note says how, in that system's own terms.

GitHub
The GitHub Blog
2021
GitHub's query linter turns an architectural intention (these tables will live apart) into a failing test at the developer's desk, years before the tables actually move. The transaction linter extends the same enforcement to production under sampling, catching what static analysis of queries can't see. The boundary is real from the day it's declared, not the day it's deployed. Read the breakdown →

Problems this pattern answers

The walls where its breakdowns live — each opens the cross-company comparison.