skip to content

What does the Stable Dependencies Principle (SDP) require, and what does "stable" mean for a software component?

level: juniorimportance: must knowfreq 38%

answer

  1. Depend in the direction of stability
  2. Ca = arriving, Ce = exiting
  3. Stable = responsible + independent
  4. Hard to change, not unchanging
  5. Coin on edge vs coin flat

basics

~20 s

The Stable Dependencies Principle says a component should depend only on components that are more stable than it. "Stable" means hard to change — lots of other things depend on it — not "never changes".

solid answer

~50 s

SDP (one of Robert C. Martin's component-coupling principles) states: depend in the direction of stability. Every dependency arrow should point at something at least as hard to change as the thing drawing the arrow. Stability here is structural, not temporal: a component is stable when many others depend on it and it depends on few things, so changing it forces a lot of downstream rework and it is under pressure not to move. It is unstable when nothing depends on it and it depends on many things — it can be edited freely because nobody is standing on it. The violation to look for is a component you intend to change often (a UI screen, a policy, a feature module) that is depended on by a component meant to be rock-solid: now the "flexible" piece is frozen by its dependents. SDP keeps volatility flowing away from the parts everyone builds on.

go deeper

for a junior

State the one-line rule (depend toward stability) and define stable as "hard to change because many things depend on it". Getting Ca vs Ce right is enough.

for a middle

Add the responsible/independent framing, give a concrete backwards-arrow example, and say what the fix direction is (move the code down or invert the dependency).

for a senior

Connect stability to release cadence and blast radius, and pair SDP with SAP: a stable component must be abstract or it becomes rigid. Note when a violation is acceptable.

for a principal

Frame it as an organizational property — dependency direction encodes who can ship independently. Discuss enforcing direction in build tooling and where the metric misleads.

### The vocabulary first **Component.** A component is the smallest unit of deployment/release you version and ship as a whole: a package, a library, a jar/dll/wheel, a module, a service. SDP is a *component-level* principle — it is about arrows between these units, not about arrows between individual classes. **Dependency arrow.** Component X *depends on* component Y if code in X references, imports, calls, or otherwise needs Y to compile or run. The arrow points X → Y. **Afferent coupling (Ca)** — "incoming": the number of components outside X that depend on X. Mnemonic: **A**fferent = **A**rriving. **Efferent coupling (Ce)** — "outgoing": the number of components outside X that X depends on. Mnemonic: **E**fferent = **E**xiting. ### What "stable" actually means Stability is *the difficulty of changing a component*, not the observed frequency of change and not "correct" or "bug-free". Think of a coin standing on edge versus a coin lying flat. The upright coin is not moving right now, but it is easy to knock over — it is *unstable*. Lying flat, it takes real work to disturb — *stable*. In the same way, a component with many dependents is like a table with many things stacked on it: you *can* move it, but every dependent may need to be revisited, retested and re-released, so social and engineering pressure keeps it still. Two ingredients make a component stable: 1. **Responsible** — many components depend on it (high Ca). Changing it hurts many people. 2. **Independent** — it depends on few or no other components (low Ce). Nothing else can force it to change. The mirror image — **irresponsible and dependent** (Ca low, Ce high) — is maximally unstable: nobody would be hurt if it changed, and it is easily *forced* to change because it leans on many things. That is exactly what you want for the volatile parts of a system. ### The principle > **SDP: depend in the direction of stability.** A component should depend only on components that are more stable than itself. Equivalently: the instability of a component must be greater than or equal to the instability of everything it depends on. Arrows point from volatile toward solid, from changeable toward fixed, from details toward policies. ### Why it matters Software must be able to change; the goal is to make *some* parts easy to change and to make sure the hard-to-change parts are the ones you rarely need to touch. If a stable component depends on a volatile one, the volatile one is transitively frozen — every edit to it ripples into a component that many teams rely on, so people stop editing it, work around it, or copy-paste it. The design has lost its intended flexibility precisely where flexibility was the point. A concrete failure: a shared `core-domain` library (dozens of dependents) imports a helper from `checkout-ui` for one date formatter. `checkout-ui` was supposed to be redesigned every quarter. Now every redesign risks recompiling and retesting everything that depends on `core-domain`. SDP says the arrow is backwards; the formatter should move down into `core-domain` (or into a tiny stable utility component), not be borrowed upward. ### Edge cases and honest caveats - **Nothing can be maximally stable everywhere.** A system where every component is stable is a system that cannot change. You *want* a spread: unstable, volatile components at the top, stable, general components at the bottom. - **Not every violation is a defect.** A deliberate, well-known coupling to something you know will not move (a mature third-party library, a frozen protocol) is fine even if the metrics grumble. - **Stability ≠ abstractness, but they should travel together.** Very stable components are hard to change, which is bad if they are full of concrete logic. The companion Stable Abstractions Principle says stable components should be abstract so they can be *extended* without being *modified*. - **Stability is not a claim about quality.** A stable component can be terrible code; it is just expensive to change.

  • If stability means "hard to change", isn't a stable component a bad thing?
    Only if it is also concrete and full of volatile business rules. Stability is fine — desirable, even — for general, abstract policy that you extend rather than edit. The Stable Abstractions Principle pairs high stability with high abstractness precisely so a hard-to-modify component can still be extended.
  • How do you make a component more stable if you need to?
    Increase Ca or decrease Ce: pull more consumers onto it, and remove its outgoing dependencies (inline what it needs, invert dependencies so others hand it what it needs, or move the shared piece into it). Reducing Ce is usually the honest lever — you control it.
  • Does SDP apply to microservices too?
    Yes, with the same reading: a widely-consumed service should not call out to a service that changes weekly, because the callee's churn propagates into the caller's contract, availability, and release cadence. The remedy is the same — invert via an interface/event the stable side owns.

A coin standing on its edge isn't moving, but a breath knocks it over — unstable. Lying flat it takes effort to shift — stable. Component stability is about how hard it is to move something, not whether it happens to be moving.

saying these in an interview costs you the question

  • Saying stable means "doesn't change" or "has no bugs" / "is well tested"
  • Mixing up Ca and Ce (incoming vs outgoing)
  • Concluding every component should be maximally stable
  • Treating SDP as a class-level rule instead of a component/deployable-unit rule
  • Claiming a dependency on a volatile component is fine "because we'll just be careful"

context