In Robert C. Martin's component-cohesion tension diagram, the Common Reuse Principle (CRP) pulls against the Reuse/Release Equivalence Principle (REP) and the Common Closure Principle (CCP). Explain the tension and how you would choose a position for a given project.
answer
- Triangle: REP + CCP group, CRP splits
- Drop CCP → too many components change per change
- Drop CRP → too many unneeded releases for consumers
- Drop REP → unversioned, hard to reuse
- Young → CCP; mature/shared → REP+CRP, migrate via aggregator
basics
~20 sREP and CCP make components bigger (easier to reuse and to change in one place); CRP makes them smaller (consumers shouldn't carry what they don't use). You can't maximise all three, so you pick a point: young projects lean CCP, mature shared libraries lean REP and CRP.
solid answer
~50 sMartin draws the three cohesion principles as a triangle. REP (a component must be a coherently versioned, released whole) and CCP (put classes that change together in one component) are inclusive forces that grow components; CRP is exclusive and shrinks them. Each edge names the cost of abandoning the opposite vertex: give up REP and reuse becomes unsafe and undiscoverable; give up CCP and a single change ripples across many components and releases; give up CRP and consumers are flooded with releases and dependencies they never needed. The position is not fixed. Early in a project, developability dominates: sit near CCP, accept fat components, few artifacts, fast change. As consumers multiply and the code stabilises, the cost of irrelevant releases dominates and you migrate toward REP plus CRP, splitting along observed joint-usage lines. Treat the component boundary as a variable to be re-tuned, not a one-time decision.
go deeper
Say that REP and CCP make components bigger, CRP makes them smaller, and that you can't have all three at once. One sentence per vertex is enough.
Name each edge's penalty correctly, and give the lifecycle rule: developability early (CCP), reusability later (REP+CRP).
Add the decision inputs — consumer count, change distribution, release cost, build topology — and describe the migration mechanics (aggregator artifact, deprecation window).
Treat it as portfolio governance: an artifact-count budget, ownership and deprecation policy, interaction with ADP/SDP/SAP, and a scheduled review of boundaries as the system's consumer base and change profile evolve.
## The three vertices - **REP — Reuse/Release Equivalence Principle:** "The granule of reuse is the granule of release." To be reusable, a component must be tracked by a release process: a version number, release notes, a documented public surface, a compatibility promise. Consequence: things you want reused together must be released together, which *groups* classes into larger components. - **CCP — Common Closure Principle:** "Gather into components those classes that change for the same reasons and at the same times." This is SRP for components. It minimises the number of components a maintainer must modify, revalidate and release for one requirement change — which also *groups* classes into larger components. - **CRP — Common Reuse Principle:** "Don't force users of a component to depend on things they don't need." This is ISP for components. It *splits* components. ## The tension diagram Draw a triangle with REP, CCP, CRP at the vertices. Each **edge** is labelled with the price you pay for ignoring the vertex opposite it: - Focus on **REP + CRP** (ignore CCP): components are small, well-versioned and lean for consumers — but a single requirement change now touches many components, so **too many components change** for one change, and every change means multiple coordinated releases. - Focus on **REP + CCP** (ignore CRP): components are big, coherent and stable to release — but consumers get dragged along, so there are **too many unneeded releases** for them to absorb. - Focus on **CCP + CRP** (ignore REP): boundaries are pragmatic for both change and usage — but nothing is properly versioned or released, so the components are **hard to reuse**: no version guarantees, no notes, no compatibility promise. Where your architecture sits inside the triangle *is* your component strategy. Sitting exactly at a vertex is always wrong; you are choosing which of the three costs you can currently afford. ## Choosing a position: the lifecycle argument Martin's key observation is that the right position **moves over time**. **Early project / few or no external consumers.** Developability dominates. Nobody is reusing your components yet and requirements churn weekly. Sit near **CCP**: fewer, fatter components; a change lands in one artifact; you avoid the coordination tax of splitting. CRP violations are cheap because there are barely any consumers to inconvenience. **Mature project / many consumers / stable code.** Reusability dominates. Now every irrelevant release costs N teams their integration time, and the dependency closure is bloating everyone's builds. Drift toward **REP + CRP**: split along real joint-usage lines, publish per-capability artifacts, take semantic versioning seriously. **The migration is the hard part** and should be planned, not improvised: 1. Gather evidence: which consumers use which classes (build-graph analysis, import scanning, telemetry on published API usage). 2. Cluster by observed joint usage, not by aesthetic taxonomy. 3. Split physically, then keep the **old artifact as a thin aggregator** that depends on the new ones and re-exports, so nothing breaks on day one. 4. Deprecate the aggregator with a stated window; migrate consumers; delete. ## Additional inputs to the decision - **Consumer count and diversity.** One consumer: CRP is nearly irrelevant. Fifty consumers using disjoint slices: CRP dominates. - **Change frequency and its distribution.** If change is concentrated in one cluster, splitting that cluster out protects everyone else. - **Release cost per consumer.** Regulated or certified environments make each irrelevant release very expensive, so CRP's weight goes up. - **Build topology.** A monorepo with atomic builds erases most of CRP's cost; independent repos with published artifacts maximise it. - **Artifact-count budget.** Every published component has fixed overhead: pipeline, ownership, docs, deprecation policy. Beyond some count, coordination cost outweighs the CRP savings. - **Coupling principles interact.** Splitting to satisfy CRP adds edges to the component graph; you must still satisfy ADP (no cycles) and SDP/SAP (depend in the direction of stability). A careless CRP split can create a cycle between the two new components — which usually means you split along the wrong seam, or need to extract a shared abstraction component. ## Interview framing "There's no optimum, only a chosen trade-off. Grouping forces — REP and CCP — make components bigger for maintainer and versioning convenience; CRP is the only splitting force and it protects consumers. Which cost you can afford depends on how many consumers you have and how expensive their integration is, and that changes as the system matures — so I treat component boundaries as reviewable, with a migration path via an aggregator artifact rather than a big-bang split."
- What is the specific penalty for sitting at the REP+CRP edge and ignoring CCP?Too many components change for a single requirement change. One logical change fans out into edits, version bumps and coordinated releases across many artifacts, multiplying release-management and integration work — and often forcing lockstep versioning that defeats the point of separate artifacts.
- How do you split a fat component without breaking existing consumers?Extract the new components, then republish the original artifact as a thin aggregator that depends on and re-exports them, so existing coordinates keep working. Announce a deprecation window, help consumers migrate to the specific artifacts, then retire the aggregator.
- Can a CRP-driven split create a problem with other component principles?Yes — it can introduce a cycle between the two new components, violating the Acyclic Dependencies Principle, and it can point a stable component at a volatile one, violating the Stable Dependencies Principle. Both usually indicate the seam was wrong; the fix is to extract the genuinely shared abstraction into a third, more stable component.
Packing for a shared expedition. One giant crate is easy to load and easy to update (CCP and REP), but everyone hauls everyone's gear (CRP violation). One crate per item means nobody carries dead weight, but every packing change means opening twenty crates and coordinating twenty labels.
saying these in an interview costs you the question
- Presenting the three principles as compatible rules to satisfy simultaneously rather than as competing forces.
- Claiming the correct component granularity is fixed and can be decided once, up front.
- Splitting a young, fast-churning codebase into many published artifacts "for reuse" before any second consumer exists.
- Naming CRP as a grouping force, or REP/CCP as splitting forces.
- Doing a big-bang artifact split with no aggregator or deprecation path for existing consumers.