Skip to main content

Sign in to CleanKata

Track your progress, earn XP, and unlock every lesson.

By signing in you agree to our Terms of Use and Privacy Policy.

Clean Architecture70 XP7 min

Component Cohesion: The Common Reuse Principle

Don't force users of a component to depend on things they don't need — depending on a component means depending on everything it contains.

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.

🔧 Some exercises may still have errors. If something seems wrong, use the Feedback button (bottom-right of the page) to report it — it helps us fix it fast.

Hint: CRP says: don't put classes in a component if users of the component don't need all the classes.

✗ Your version