Package Principles are six design principles formulated by Robert C. Martin (Uncle Bob) that guide how to organize classes into packages (components) and manage dependencies between them. Three principles address package cohesion (what goes inside packages), and three address package coupling (relationships between packages).

Overview

Cohesion PrinciplesCoupling Principles
REP: Reuse-Release EquivalenceADP: Acyclic Dependencies
CRP: Common ReuseSDP: Stable Dependencies
CCP: Common ClosureSAP: Stable Abstractions

In this context, a “package” is a binary deliverable like a .jar, .dll, or npm package—a deployable unit of code, not just a namespace or folder.

Package Cohesion Principles

These principles determine what classes belong together in a package.

REP: Reuse-Release Equivalence Principle

“The granule of reuse is the granule of release.”

Meaning: Anything that is reused must be released and tracked with version numbers.

Key Points:

  • Reusable components require formal release tracking and versioning
  • Users must be able to depend on specific versions
  • The package author must provide notification of changes, support, and documentation
  • Classes grouped together should make sense from a reuser’s perspective

Implications:

  • If classes are reused together, they should be released together
  • Random collections of unrelated classes don’t make good packages
  • Packages should have clear, cohesive purposes that users can understand

CRP: Common Reuse Principle

“The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.”

Meaning: Group classes that tend to be reused together; don’t force users to depend on things they don’t use.

Key Points:

  • Classes with tight interdependencies belong in the same package
  • Container classes and their iterators should be together
  • Don’t include classes that aren’t typically used with the others

Example:

// GOOD: Related classes together
package collections {
  class ArrayList
  class ArrayListIterator
  class LinkedList
  class LinkedListIterator
}

// BAD: Unrelated classes forced together
package utils {
  class EmailValidator
  class ArrayList
  class DateFormatter
}

Implication: CRP tells us which classes should NOT be together—those that aren’t reused together.

CCP: Common Closure Principle

“The classes in a component should be closed together against the same kinds of changes. A change that affects a component affects all the classes in that component and no other components.”

Meaning: Group classes that change for the same reasons and at the same times.

Key Points:

  • This is the Single Responsibility Principle applied to packages
  • If a change is needed, it should ideally affect only one package
  • Reduces release overhead—fewer packages need redeployment
  • Classes that change together belong together

Example:

// GOOD: Payment-related changes affect one package
package payment {
  class PaymentProcessor
  class PaymentValidator
  class PaymentReceipt
}

// BAD: Payment logic scattered across packages
package validation { PaymentValidator }
package processing { PaymentProcessor }
package receipts { PaymentReceipt }

The Tension Diagram

These three principles create competing forces:

          REP
         /   \
        /     \
       /       \
     CCP ───── CRP
  • REP and CCP are inclusive: They make packages larger by grouping classes
  • CRP is exclusive: It makes packages smaller by removing unrelated classes

The Tension:

  • Maximizing CRP and CCP leads to many small packages
  • REP adds overhead for managing many releases
  • Early in development, favor CCP (developability over reuse)
  • As a system matures and is reused, shift toward REP and CRP

Uncle Bob advises focusing on CCP in early development because developability is more important than reuse at that stage.

Package Coupling Principles

These principles govern dependencies between packages.

ADP: Acyclic Dependencies Principle

“Allow no cycles in the component dependency graph.”

Meaning: The dependency structure must be a Directed Acyclic Graph (DAG)—no circular dependencies.

The Problem with Cycles:

// BAD: Circular dependency
Package A → Package B → Package C → Package A

When packages form cycles:

  • Changes in one package ripple through the entire cycle
  • Testing requires all packages in the cycle
  • Independent deployment becomes impossible
  • Build order becomes undefined

Breaking Cycles:

  1. Introduce an abstraction: Create a new package with an interface that both depend on
// Instead of A ↔ B
// Create: A → IService ← B
  1. Use Dependency Inversion: Make the lower-level module depend on an abstraction owned by the higher-level module

  2. Event-driven communication: Replace direct calls with events or messages

SDP: Stable Dependencies Principle

“Depend in the direction of stability.”

Meaning: A package should only depend on packages that are more stable than itself.

Measuring Stability:

  • Fan-in (Ca - Afferent Coupling): Incoming dependencies—how many packages depend on this one
  • Fan-out (Ce - Efferent Coupling): Outgoing dependencies—how many packages this one depends on

Instability Metric:

I = Ce / (Ca + Ce)

I = 0: Maximally stable (many depend on it, hard to change)
I = 1: Maximally unstable (nothing depends on it, easy to change)

Key Insight: Stable packages should never depend on unstable ones. Dependencies should point toward stability.

Example:

// GOOD: Unstable depends on stable
UI Layer (I=1) → Business Logic (I=0.3) → Core Domain (I=0)

// BAD: Stable depends on unstable
Core Domain (I=0) → UI Utilities (I=1)

Practical Application:

  • UI frameworks (volatile) should depend on core business logic (stable)
  • Core domain should have few or no outgoing dependencies
  • Adapters and plugins should be unstable; what they adapt to should be stable

SAP: Stable Abstractions Principle

“A component should be as abstract as it is stable.”

Meaning: Stable packages should be abstract so they can be extended. Unstable packages should be concrete so they can be easily modified.

The Problem:

  • A stable, concrete package becomes rigid—hard to extend without modification
  • It violates the Closed Principle

Abstractness Metric:

A = Na / Nc

Na = Number of abstract classes/interfaces in package
Nc = Total number of classes in package

A = 0: Completely concrete
A = 1: Completely abstract

The Main Sequence:

Plot packages on an I vs A graph:

    A (Abstractness)
    1 |  Zone of
      |  Uselessness    *
      |              *
  0.5 |           *  <- Main Sequence (ideal)
      |        *
      |     *
    0 +--*-----------------
      0    0.5    1   I (Instability)
  • Zone of Pain (I=0, A=0): Stable and concrete—rigid, hard to change
  • Zone of Uselessness (I=1, A=1): Unstable and abstract—no one implements it
  • Main Sequence: The ideal diagonal line where I + A ≈ 1

Distance from Main Sequence:

D = |A + I - 1|

D = 0: On the main sequence (ideal)
D = 1: As far from ideal as possible

Example:

// GOOD: Stable package is abstract
namespace Core.Abstractions  // I≈0, A≈1
{
    public interface INotificationService { }
    public interface IPaymentGateway { }
}
 
// Unstable packages are concrete
namespace Infrastructure.Email  // I≈1, A≈0
{
    public class SmtpNotificationService : INotificationService { }
}

How the Principles Work Together

Dependency Direction

The healthiest architecture flows from unstable → stable → abstract:

┌─────────────────┐
│ UI, Adapters    │  Unstable, Concrete (I≈1, A≈0)
│ (outer layers)  │
└────────┬────────┘
         │ depends on
         ▼
┌─────────────────┐
│ Application     │  Middle stability
│ Services        │
└────────┬────────┘
         │ depends on
         ▼
┌─────────────────┐
│ Core Domain     │  Stable, Abstract (I≈0, A≈1)
│ (abstractions)  │
└─────────────────┘

Combined Effect

PrinciplePurposeAction
ADPEliminate cyclesIntroduce abstractions or event-driven communication
SDPDirect dependency flowDepend on stable (high fan-in, low fan-out) packages
SAPMaintain flexibilityStable packages must be abstract, not concrete

SAP + SDP = Dependency Inversion Principle (DIP) at the package level:

  • Stable packages are abstract (SAP)
  • Unstable packages depend on stable ones (SDP)
  • Result: Concrete details depend on abstractions

Practical Application

When Designing Packages

  1. Identify what changes together (CCP)
  2. Consider what’s reused together (CRP)
  3. Version packages that are reused (REP)
  4. Draw the dependency graph—eliminate cycles (ADP)
  5. Ensure dependencies point toward stability (SDP)
  6. Make stable packages abstract (SAP)

Warning Signs

  • Cyclic dependencies: Packages that depend on each other
  • Stable concrete packages: Core packages with no abstractions
  • Unstable packages with many dependents: Volatile code that many packages rely on
  • Releases that cascade: Changing one package forces many others to update

Resources

See Also