H.5 Dependencies
A shared repository makes an edge easy to draw. It does not decide whether the edge is supported, which compatibility promise it carries, or who will remove it. Dependency design starts with those contracts and then chooses graph and tooling controls that can enforce them.
Turn Reuse Into A Supported Contract
H.5.1 Shared Components distinguishes a maintained internal product from code that merely happens to be reachable. Intended consumers, supported surfaces, stewardship, stability, and retirement make reuse explicit. H.5.2 Dependency Boundaries then turns architectural intent into allowed directions, public surfaces, forbidden edges, cycle policy, and high-influence boundaries. Visibility, linters, architecture tests, and graph queries each enforce a part of that model; none is also a source-access policy.1
H.5.3 Compatibility Contracts states which old and new consumers can coexist and who absorbs a change. This is the contract needed to choose between live-at-head source evolution, compatible interfaces, published versions, and temporary multiple versions. It owns supported source and dependency surfaces; H.11.4 Runtime Compatibility owns skew among independently running versions, environments, and stored data.
Join Several Dependency Systems Deliberately
H.5.4 Polyglot Dependencies treats Maven, npm, pip, Go, Cargo, CMake, Bazel, and their lock or registry state as cooperating authorities rather than one imaginary universal solver. H.5.5 Generated Interfaces applies the same contract discipline to schemas, generators, checked-in or build-time output, IDEs, and consumers. The generated file is evidence of the interface, not its only owner.
Finally, H.5.6 Dependency Intake governs the decision to admit third-party code. Source, integrity, maintenance, license, vulnerability, provenance, availability, update ownership, and retirement all belong in that decision. Only after intake does graph policy decide where the dependency may be used. H.9.4 Supply Chain then maintains security and compliance trust in accepted inputs and produced artifacts rather than reopening the intake decision.
Treat dependency management as a chain of explicit decisions: what is a supported component, which edges are allowed, what compatibility is promised, which resolver owns state, how interfaces are generated, and whether an external input may enter the graph at all.
Footnotes
-
Managing dependency graph in a large codebase — graph-policy enforcement and dependency-boundary trade-offs ↩
Sections in this chapter · 6
Treat reused code as a maintained internal product with named consumers, support, compatibility, and retirement.
Make public surfaces, allowed direction, forbidden edges, cycles, influence, and graph hygiene executable.
Define source, API, schema, and dependency compatibility, who absorbs change, and when a supported surface may retire.
Govern resolvers, versions, lock state, registries, and coexistence across Bazel and ecosystem-native systems.
Govern generated APIs as contracts among schemas, generators, outputs, IDEs, build actions, and consumers.
Decide whether and how a dependency enters, updates, receives patches, or leaves using maintenance, license, provenance, and availability evidence.