What are the three component cohesion principles (REP, CCP, CRP) described by Robert C. Martin, and what does each one say about which code belongs together in a releasable component?
answer
- REP = granule of reuse == granule of release
- CCP = SRP for components (change together)
- CRP = ISP for components (don't drag along)
- REP/CCP inclusive, CRP exclusive → tension triangle
- Position shifts as project matures
basics
~20 sREP: things released together should be usable together. CCP: put classes that change for the same reason in the same component. CRP: don't force users to depend on code they never use. Together they decide component contents.
solid answer
~60 sA "component" is the smallest unit you can independently release and deploy — a library, package, jar/wheel/npm module, or a service artifact. Martin's three cohesion principles answer "which classes go inside one component?". - **REP (Reuse/Release Equivalence Principle)**: the granule of reuse is the granule of release. If you want people to reuse code, you must release it as a versioned, documented, tracked unit, and everything in it must make sense together to a single audience. - **CCP (Common Closure Principle)**: gather into a component the classes that change for the same reasons at the same times; separate those that change for different reasons. This is the SRP applied at component scale, and it minimises how many components a typical change touches. - **CRP (Common Reuse Principle)**: don't force users of a component to depend on things they don't need. Classes that are always reused together belong together; classes reused separately belong apart. This is ISP at component scale. REP and CCP push components to be bigger; CRP pushes them to be smaller — hence the tension triangle.
go deeper
Name all three, expand each acronym, and give the one-line meaning: release-as-a-unit, change-together, used-together.
Map CCP→SRP and CRP→ISP, and explain the concrete cost each avoids (release churn vs. spurious rebuilds/redeploys of unaffected consumers).
Lead with the tension triangle: REP+CCP are inclusive, CRP is exclusive, so you pick a position; give a real example of splitting or merging a package because the position moved.
Frame it as an economic trade-off between developability and reusability that shifts with organisational maturity, and connect it to release cadence, versioning policy, team ownership boundaries and the coupling principles (ADP/SDP/SAP).
## What a "component" means here In this vocabulary a **component** is *the smallest unit that can be independently released and deployed*. Concretely: a `.jar`, a `.dll`, an npm package, a Python wheel, a Go module, a NuGet package, a shared library, or — at bigger grain — a deployable service. The key property is not physical file format but **independent release with a version number**. Everything below is about deciding *which classes/files live inside one such unit*. Cohesion here means **"belonging together"**, and Robert C. Martin ("Uncle Bob") formulated three principles that answer that question. They come from *Agile Software Development* (2002) and *Clean Architecture* (2017). --- ## 1. REP — Reuse/Release Equivalence Principle > *"The granule of reuse is the granule of release."* If you want other people (or other teams, or your own other projects) to **reuse** your code, that code must be **released**: given a version number, published to some repository, accompanied by release notes describing what changed, and tracked over time so consumers can decide when to upgrade. Two consequences: - **You cannot reuse something smaller than what you release.** If a library is released as one versioned artifact, consumers take all of it or none of it. So the artifact's contents must form a coherent, explainable whole — "a theme, a purpose, a story" — otherwise the release notes make no sense ("v2.4: added an HTTP retry policy and a matrix determinant solver" is a smell). - **Release infrastructure is a first-class requirement**, not paperwork. No version numbers, no changelog, no notifications → no safe reuse, because a consumer can never tell whether upgrading will break them. REP is weakly stated (it says what happens when you get it wrong, more than what to do), but violating it is glaring: consumers get surprised by breaking changes, or a "utils" grab-bag forces everyone to re-qualify unrelated code on every release. --- ## 2. CCP — Common Closure Principle > *"Gather into components those classes that change for the same reasons and at the same times. Separate those classes that change for different reasons and at different times."* This is the **Single Responsibility Principle raised to component scale**. SRP says a class should have one reason to change; CCP says a *component* should have one reason to change. The motivation is **maintenance economics**, not elegance. When a requirement changes, you would much rather have that change confined to **one** component — which means one artifact to re-validate, re-version, re-release, and redeploy — than smeared across seven. Every extra component touched by a typical change multiplies build/test/release/redeploy work and the chance of a version-skew mistake. CCP also connects to the **Open/Closed Principle**: since you can't make code closed against *all* changes, you choose which changes to be closed against. CCP groups things so that the classes *not* closed against the same kind of change sit together, so the leakage is contained inside one component's boundary. Practical signal: look at your version-control history. If two files almost always change in the same commit, CCP says they probably belong in the same component. If a component's files never change together, it is probably two components. --- ## 3. CRP — Common Reuse Principle > *"Don't force users of a component to depend on things they don't need."* This is the **Interface Segregation Principle raised to component scale**. Classes that are almost always used together should live together; classes that are used independently should be split apart. The cost CRP protects you from is the cost of a **dependency you didn't want**. When component A depends on component B, A depends on *all of B* — including the parts A never calls. If an unused class in B changes, B gets a new version; A's team then has to (at minimum) revalidate, recompile, retest and redeploy A, even though nothing A uses actually changed. On a strongly-versioned platform it can be worse: transitive constraints, diamond conflicts, larger binaries, extra transitive third-party dependencies, and a bigger attack surface from code you never execute. So CRP is as much about **what to keep OUT** of a component as about what to put in. Its stronger reading: *an unnecessary dependency edge is a real, recurring cost — pay attention to which classes drag which other classes along.* --- ## The tension between them - **REP and CCP are inclusive**: they make components larger (more reusable stories together; more change-mates together). - **CRP is exclusive**: it makes components smaller (throw out anything not reused together). A good architect deliberately sits somewhere inside that triangle and **moves over time**: | You over-emphasise… | You suffer… | |---|---| | REP + CCP (ignore CRP) | consumers get too many spurious releases/rebuilds from changes they don't care about | | REP + CRP (ignore CCP) | one requirement change hits many components — release/deploy churn | | CCP + CRP (ignore REP) | fine-grained, well-factored components that are hard for anyone else to consume safely | Early in a project, developability dominates — CCP wins, components are coarse, reuse is secondary. As a system matures and outside consumers appear, the pressure moves toward REP/CRP and components get split. **The partitioning is expected to change with the project's maturity — it is not a one-time decision.** --- ## Common confusions to avoid - These are **cohesion** principles (what goes inside a component). The separate **coupling** principles — ADP (no dependency cycles), SDP (depend in the direction of stability), SAP (stable components should be abstract) — govern the edges *between* components. Interviewers often check that you don't mix the two families. - Cohesion here is *not* the classic LCOM-style intra-class cohesion metric; it's about change and reuse patterns of whole artifacts. - "Component" is not necessarily "microservice", though the principles apply to service boundaries too.
- Which of the three principles corresponds to SRP and which to ISP, applied at component scale?CCP is SRP at component scale — one reason to change per component. CRP is ISP at component scale — don't make clients depend on parts they don't use. REP has no direct class-level twin; it's about release/versioning discipline.
- How would you use version-control history to test whether a component satisfies CCP?Compute co-change: how often do files inside the component change in the same commit/PR, and how often does a single change span multiple components? High intra-component co-change and low cross-component fan-out means CCP is being honoured; the reverse suggests you split along the wrong seam.
- Do these principles apply to microservices?Yes — a service is a component that is independently releasable, so CCP argues against a service boundary that every feature change has to cross, and CRP argues against a shared 'common' library that couples every service to every other service's release cadence.
Think of packing suitcases for a trip. REP: each suitcase must be a sensible, labelled kit somebody could pick up and use ("ski gear v2"), not random objects. CCP: things you'll repack together — all the ski clothing — go in one case, so a change of plan opens one case, not five. CRP: don't stuff the beach umbrella into the ski case, or everyone who borrows the ski case has to lug the umbrella and re-check the case every time the umbrella changes.
saying these in an interview costs you the question
- Naming ADP/SDP/SAP (the coupling principles) when asked about cohesion
- Saying CCP means 'group by technical layer' or 'group by class type' rather than by reason-to-change
- Claiming the three principles can all be maximised at once — they are in explicit tension
- Treating REP as merely 'write a README'; it is about versioned, tracked releases that make reuse safe
- Asserting the ideal component partitioning is fixed once at design time