Why this matters
The Common Reuse Principle (CRP) tells us which classes not to put together in a component: don't force users of a component to depend on things they don't need. If a component contains class A and class B, a user who only needs class A must still depend on class B. When class B changes — even if the user never calls it — that user must revalidate and potentially redeploy their software.
CRP is the component-level equivalent of ISP. Both say the same thing at different scales: don't couple consumers to things they don't use. The practical discipline is to ensure that every class in a component is inseparable from the others — that users of the component genuinely need all of the classes it contains. When a class is "almost always used" alongside certain other classes, that's a CRP signal to bundle them; when a class is "sometimes useful" alongside an unrelated class, that's a CRP signal to separate them.
The problem
A containers package that includes GraphTraversal forces all consumers — even those using only List — to install heavy graph dependencies and retest when graph code changes.
Bad
# containers/ package bundles basic collections with a heavy graph algorithm
# list_impl.py — simple linked list
# map_impl.py — hash map
# queue_impl.py — FIFO queue
# graph_traversal.py — BFS/DFS, requires networkx (heavy dep!)
# A service that only needs List must install networkx.
# When graph_traversal.py changes, that service must re-validate
# its code — even though it never touches graph traversal.
// @company/containers bundles simple collections with heavy graph utilities
// packages/containers/src/
// LinkedList.ts — basic linked list
// HashMap.ts — hash map
// Queue.ts — FIFO queue
// GraphTraversal.ts — BFS/DFS (pulls in "graphlib" — heavy peer dep)
// A service using only LinkedList must list graphlib as a peer dependency
// and re-run tests every time GraphTraversal is modified.
The solution
GraphTraversal lives in its own package. Services that need only basic collections depend on containers — no graphlib, no graph churn.
Good
# containers/ — basic collections only
# list_impl.py
# map_impl.py
# queue_impl.py
# graph_algorithms/ — separate package, separate release cadence
# graph_traversal.py # requires networkx — only installed by graph users
# Services needing only List depend on "containers" — no networkx, no graph churn.
# Services needing BFS also depend on "graph_algorithms" — explicit, intentional.
// @company/containers — LinkedList, HashMap, Queue only
// @company/graph-algorithms — GraphTraversal, requires graphlib
// A service using LinkedList:
// import { LinkedList } from "@company/containers"; // no graphlib
// A service needing BFS:
// import { bfs } from "@company/graph-algorithms"; // explicit opt-in
Key takeaway
CRP says: don't put classes in a component if users of the component don't need all the classes. Depending on a component means depending on everything it contains — so everything in a component should be inseparable.