skip to content

How does the Reuse/Release Equivalence Principle (REP) interact with the Common Closure Principle (CCP) and the Common Reuse Principle (CRP), and what goes wrong when a team over-applies REP?

level: seniorimportance: should knowfreq 26%

answer

  1. triangle: REP + CCP include, CRP excludes
  2. CCP = SRP for components (co-change)
  3. CRP = ISP for components (don't depend on unused)
  4. edges = cost of abandoning the opposite corner
  5. early = developability/CCP; mature = reuse/REP+CRP

basics

~20 s

REP, CCP and CRP pull in different directions. REP and CCP push components larger (releasable, coherent, co-changing); CRP pushes smaller (don't force consumers to depend on things they don't use). You pick a spot on that triangle that suits the project's current stage, then revisit it.

solid answer

~40 s

Martin's three cohesion principles form a tension diagram. **REP** (granule of reuse = granule of release) and **CCP** (classes that change for the same reasons and at the same times belong together) both argue for *inclusion* — bigger components. **CRP** (don't force users of a component to depend on things they don't need) argues for *exclusion* — smaller components. Ignore CRP and you get needless releases and bloated dependency closures; ignore REP/CCP and one change requires many coordinated releases and consumers face a huge graph. The right position depends on maturity: early projects sit near CCP (developability — make change cheap), mature ones drift toward REP/CRP (reusability). Over-applying REP alone produces "we publish everything" — heavy release ceremony, versioning overhead, diamond conflicts, and multi-component lockstep releases for a single logical feature.

go deeper

for a junior

Name the three principles and their one-line meanings, and say they conflict: two push components bigger, one pushes them smaller.

for a middle

Explain each edge of the tension diagram — who suffers when you abandon REP, CCP or CRP — with a concrete symptom for each.

for a senior

Add the maturity argument (developability → reusability), how to decide boundaries from co-change and co-use evidence, and the concrete failure modes of over-splitting: lockstep releases, diamond conflicts, semver corrosion.

for a principal

Frame it as an evolving portfolio decision tied to team topology, release cadence, tooling maturity and cost of coordination; connect the cohesion choices to the coupling principles (ADP/SDP/SAP) that govern the resulting dependency graph.

## The three principles, defined Robert C. Martin's **component cohesion** principles answer: *which classes belong in which component?* (A **component** = the unit of deployment/distribution: jar, npm package, wheel, module.) - **REP — Reuse/Release Equivalence Principle.** "The granule of reuse is the granule of release." Whatever is reused must be released as a versioned artifact with release notes; therefore the contents share a version, a cadence and a theme. *Direction: include things that are reused together.* - **CCP — Common Closure Principle.** "Gather into a component those classes that change for the same reasons and at the same times; separate those that change for different reasons." It is the Single Responsibility Principle at component scale, and it's about **maintainability**: if a change is confined to one component, you rebuild, retest and redeploy one thing. *Direction: include things that co-change.* - **CRP — Common Reuse Principle.** "Don't force users of a component to depend on things they don't need." It's the Interface Segregation Principle at component scale, and it's fundamentally a statement about what to **exclude**: classes not reused together should not be bundled together, because a dependency on a component is a dependency on *all* of it — including its transitive dependencies, and including the obligation to revalidate/redeploy when any part changes. *Direction: exclude things not reused together.* ## The tension diagram Picture a triangle with REP, CCP and CRP at the corners. Each **edge** describes the cost of ignoring the opposite corner: - **Abandon REP** (only CCP + CRP): components are cohesive and lean, but reuse is unmanaged — no versions, no release notes, consumers can't pin or upgrade deliberately. Reusers suffer. - **Abandon CCP** (only REP + CRP): components are releasable and lean, but a single logical change scatters across many components — many builds, many releases, many redeployments, dependency-ordered rollouts. Maintainers suffer. - **Abandon CRP** (only REP + CCP): components are releasable and coherent-by-change, but too inclusive — consumers depend on code they never use, inherit its transitive dependencies, and get dragged through unrelated releases and revalidation. Consumers suffer. You cannot sit at all three corners simultaneously; you choose a position on the triangle, and — critically — **the right position moves over a project's lifetime**. ## The maturity argument Early in a project, nobody is reusing your components yet; what matters is **developability** — the ability to change things fast without ceremony. That pulls toward the CCP corner: larger, co-changing components, few release boundaries, minimal versioning overhead. As the system matures and real external consumers appear, **reusability** matters more, pulling toward REP/CRP: firmer boundaries, versioned releases, leaner dependencies. Treating the triangle as a fixed answer rather than a moving position is a common mistake in both directions. ## What over-applying REP looks like REP taken alone says "if it's reused, release it" — a team can over-read that as "release everything, as finely as possible". Symptoms: 1. **Release ceremony dominates.** Each component needs a build pipeline, version policy, changelog, owner, publish step, and an upgrade decision at every consumer. Multiply by dozens and engineering time goes into version wrangling. 2. **Lockstep multi-release changes.** A single feature touching three fine-grained components requires releasing them in dependency order and threading versions through — with CCP violated, the "one change, one release" property is lost. 3. **Diamond dependency conflicts.** Deep graphs mean two paths often demand incompatible versions of a shared transitive component. Resolution ranges from annoying (version pinning, overrides) to impossible without a coordinated re-release. 4. **Version-number theatre.** Teams start bumping versions with no meaningful change, or ship changes labelled PATCH to avoid the migration burden — which corrodes the semver signal REP depends on. 5. **Stale consumers.** With too many things to upgrade, consumers freeze versions and drift, defeating the fix-distribution benefit that motivated releasing in the first place. ## What over-applying REP's *inclusion* side looks like (the opposite failure) Read the other way — "put everything reusable behind one releasable artifact" — REP without CRP produces the fat `common`/`utils` component: everyone depends on everything, unrelated churn is broadcast, dependency closures balloon, and any consumer must revalidate on every release. This is precisely the failure CRP exists to prevent. ## Navigating in practice - **Use evidence for the boundary**: consumer usage clusters (CRP signal), co-change history from version control (CCP signal), and whether there is a real cross-boundary consumer at all (REP signal). - **CCP and CRP conflict is normal.** Code that co-changes is not always code that is co-used. When they disagree, ask who pays: if maintainers change it constantly and there's one consumer, favour CCP; if there are many independent consumers with disjoint usage, favour CRP. - **Re-evaluate on a cadence.** Component boundaries are not permanent; expect to split and merge as consumer patterns and churn change. - **Cohesion principles don't stand alone.** They pair with the coupling principles — ADP (no dependency cycles between components), SDP (depend in the direction of stability), SAP (stable components should be abstract) — which constrain the *graph* the cohesion principles' boundaries create.

  • CCP says group classes that change together; CRP says split classes that aren't used together. What do you do when a set of classes co-changes but is used by disjoint consumers?
    Decide by who bears the cost and how often. If the code churns heavily and there are few consumers, keeping it together (CCP) avoids constant multi-component releases. If consumers are many and independent, splitting (CRP) avoids broadcasting churn and bloated dependency closures — you then pay coordination cost on the maintainer side, often mitigated by keeping the split components in one repository so co-changes are still one commit, even if they are several releases.
  • How does a project's position on the REP/CCP/CRP triangle change over time?
    Young projects favour developability: fewer, larger components near the CCP corner, minimal release ceremony, because no external consumers exist yet. As real consumers appear and the code stabilises, the balance shifts toward REP and CRP — firmer versioned boundaries, leaner components, explicit compatibility promises. The mistake is freezing an early-stage structure long after the consumer base has grown, or imposing mature-stage release ceremony on code nobody reuses yet.
  • The cohesion principles decide component contents. What decides how components may depend on each other?
    The three component *coupling* principles: ADP (Acyclic Dependencies — no cycles in the component graph, or you get the 'morning-after syndrome' where nothing can be built or released independently), SDP (Stable Dependencies — depend in the direction of greater stability, so volatile components point at stable ones), and SAP (Stable Abstractions — a stable component should be abstract enough to be extended without modification). Cohesion sets the nodes; coupling constrains the edges.

Think of packing tools into toolboxes. REP says a toolbox must be a real, labelled, closable box you can hand to someone (not loose tools). CCP says put together the tools you always end up replacing on the same job. CRP says don't make a plumber carry the electrician's tools just to get a wrench. One box can't satisfy all three; you choose, and you repack as the jobs change.

saying these in an interview costs you the question

  • "Follow all three principles fully" — they are mutually exclusive at the extremes; you choose a position on the triangle.
  • "CRP is just CCP restated" — CCP is about co-change (maintainability, inclusion); CRP is about co-use (consumer burden, exclusion).
  • "CRP means avoid unused classes for binary size" — the deeper costs are transitive dependencies, forced revalidation and redeployment on unrelated releases.
  • "The right component structure is decided once, up front" — the optimal position shifts as the project matures and consumers appear.
  • "More, smaller components is always better architecture" — over-splitting causes lockstep releases, diamond conflicts and version-management overhead.
  • "REP is about code reuse quality" — REP is about the release relationship; it says nothing about whether the code is good.

context