Skip to main content

Public access and forbidden dependencies

What This Concept Is​

A boundary rule declares which dependencies are permitted, at a specified level of abstraction. Direct access to another owner's private implementation and transitive dependence on an entire capability are different questions. The first protects an interface; the second excludes a dependency chain altogether.

Why It Matters Here​

A package diagram cannot enforce a boundary. But an incorrectly chosen enforcement rule can prohibit legitimate encapsulation and encourage blanket exceptions. Define what the rule means before picking a tool or splitting a service.

Concrete Example​

Checkout calls billing.api, which calls billing.storage. The direct cross-owner edge targets a public API, so the private-access rule passes. Billing's internal storage access also passes. If a separate rule says checkout must never transitively depend on billing.storage, the two-edge path violates it. That rule is usually too strong for this facade design; it is appropriate only when the intent is to exclude that dependency entirely.

Now change checkout to call billing.storage directly. Private access fails even if no explicit forbidden pair was configured. Both outputs are useful, but neither should be silently substituted for the other. A public flag documents permission under this model; it is not authentication or authorization.

Common Confusion / Misconception​

Moving files into folders does not hide shared tables or internal objects. A facade that returns a mutable persistence entity can expose storage semantics without a forbidden import. A green import graph therefore supports a narrow structural claim, not complete domain independence.

How To Use It​

Inventory code units, owners and public surfaces. Mark direct dependencies with evidence from source or an extractor. Choose separate policies for private access, transitive prohibitions and owner cycles. For each exception name the exact edge, owner, reason and removal condition; avoid disabling a whole category to make one build green.

Check Yourself​

Why may an API legally reach private storage on behalf of its callers? When would a transitive prohibition be appropriate? What dependency could a shared table create without an import?

Mini Drill or Application​

Draw checkout, billing.api, billing.storage and reporting. Predict direct violations before running the lab. Add a reporting helper that imports billing.storage and show why a direct-only checkout prohibition misses the path. Repair the actual design intent rather than adding a broad exemption.

Read This Only If Stuck​

Fundamentals of Software Architecture — modularity and components. Import Linter forbidden contracts documents direct/indirect and descendant behavior. The lab uses exact node names and no package-descendant expansion; do not assume these are identical tool semantics.