Under the Stable Dependencies Principle, does a component that is edited every day automatically count as unstable? Explain the difference between stability and volatility, and why it matters.
answer
- Stability = hard to change; volatility = often changes
- I comes from the graph, churn comes from git history
- Stable + volatile = the danger quadrant
- Volatile things belong where nobody depends on them
- Overlay commit frequency on the dependency graph
basics
~20 sNo. Stability measures how hard a component is to change (how many things depend on it), while volatility is how often it actually changes. A frequently-edited component with many dependents is stable and volatile at once — the dangerous combination.
solid answer
~50 sStability, in SDP terms, is structural: it is set by the coupling counts, I = Ce/(Ca+Ce). Volatility is behavioural: how often the component's code actually changes, driven by business churn, immature requirements, or external APIs. They are independent axes. The trouble case is *stable and volatile* — many dependents plus constant churn — because every edit ripples through everything downstream: rebuilds, retests, coordinated releases, broken consumers. SDP's real intent is to align them: make the components you expect to churn structurally unstable (few or no dependents) and the components everyone depends on genuinely low-churn. So when auditing, do not read I alone — overlay change history (commits per file/module over the last months) on the dependency graph. A component with I = 0.1 and the highest commit count in the repo is your top architectural risk, even though the metrics alone look pristine.
go deeper
Draw the distinction clearly: hard-to-change vs often-changed, and note that the metric measures only the first.
Lay out the quadrants, name stable+volatile as the danger case, and give the shared-utils example plus the split fix.
Describe the audit — overlay VCS churn on the dependency graph — and pick between split / invert / abstract per hot spot, weighting breaking vs additive changes.
Treat volatility as a forecast tied to the roadmap and to team boundaries; place component seams ahead of predicted churn and watch for low churn caused by fear.
### Two different questions - **Stability (structural):** *How hard would it be to change this?* Determined by the dependency graph: many dependents (high Ca) and few dependencies (low Ce) → stable, I near 0. This is what SDP and the instability metric measure. - **Volatility (behavioural):** *How often does this actually change?* Determined by the domain: pricing rules change monthly, a UI is redesigned quarterly, a physics constant never changes. Nothing in the dependency graph tells you this — it comes from requirements, roadmap and version-control history. SDP is stated in terms of stability, but its *motivation* is volatility. The reason you want arrows pointing toward stable components is so that churn does not propagate. If a hard-to-change component never changes, its hardness costs nothing. ### The four quadrants | | Low volatility (rarely changes) | High volatility (changes often) | |---|---|---| | **Stable** (many dependents, I ≈ 0) | Ideal foundation — a maturing core domain model, a frozen protocol library. Hard to change, but you never need to. | **The danger zone.** Every edit ripples across the whole system: mass rebuilds, mass retests, coordinated releases, angry consumers. | | **Unstable** (no dependents, I ≈ 1) | Slightly wasteful — a leaf component that nobody depends on and that nobody touches. Often dead code. | Ideal for churn — UI screens, feature modules, `main`/composition roots, experiments. Change them freely; nobody notices. | SDP's practical goal is to keep the system out of the top-right cell by pushing volatile things into the bottom-right cell. ### How the danger cell gets built - A `common`/`utils`/`shared` library accretes business rules because it is convenient to import; everyone depends on it and it changes weekly. - A shared data model or generated-from-schema types package sits at the bottom of the graph and changes with every schema tweak. - A "core" service in a distributed system owns policies that the business revises constantly, and every other service calls it synchronously. Each one looks fine by I alone — low I is supposed to be good! — which is exactly why the metric must be read together with change history. ### The audit technique 1. Build the component dependency graph and compute I per component. 2. Pull change frequency per component from version control (commits, or better, distinct change-requests touching it, over 6–12 months). 3. Plot or table them together: **low I × high change frequency = top risk**. 4. For each hot spot, decide: - **Split it.** Extract the churning part into a new high-I component; leave the genuinely stable remainder behind. Usually the best fix for a bloated `common`. - **Invert it.** Turn the churning behaviour into an abstraction the stable component owns, with volatile implementations above it (DIP). - **Abstract it.** Raise abstractness so consumers depend on shapes, not decisions — churn behind the interface stops rippling (Stable Abstractions Principle). - **Reduce the churn.** Sometimes the requirements really did stabilize and the history is stale; check before restructuring. ### Edge cases - **Change frequency lies both ways.** A component may be quiet because it is *too painful* to change (frozen by fear), which is the Zone-of-Pain symptom, not health. And a burst of commits may be one refactor, not ongoing churn — look at distinct authors and distinct reasons. - **Additive change is cheaper than breaking change.** A stable component that only ever gains new optional API surface does not ripple the same way. Weight the history by whether changes broke consumers. - **Forecast, not just history.** Volatility is about the *future*; the roadmap can tell you a currently-quiet component is about to become the hottest thing in the codebase. Restructure before the churn, not after.
- You find a component with I = 0.1 and the highest commit count in the repository. What do you do?Treat it as the top architectural risk and look for a split: most such components are grab-bag `common`/`shared` libraries where a genuinely stable core has attracted volatile business rules. Extract the churning parts into high-I components, or invert them behind abstractions the stable core owns, so the churn stops rippling into every dependent.
- A stable component has almost no commits. Is that automatically healthy?Not necessarily. It may be quiet because changing it is too painful — the Zone of Pain symptom, where teams work around it, fork it, or bury logic in flags. Check whether feature work near it routes around it; low churn earned by fear is different from low churn earned by genuine generality.
- Where does the volatility estimate come from before a component has any history?From the domain and the roadmap: which rules are the business actively negotiating, which integrations are with immature external APIs, which parts are experiments. Volatility is a forecast; you place the boundaries so that things you expect to churn end up with no dependents, then correct with real history later.
saying these in an interview costs you the question
- Equating instability with change frequency — I is computed purely from the dependency graph
- Assuming low I is always good news
- Reading I without ever looking at change history
- Assuming a rarely-changed component is healthy, ignoring change-avoidance
- Justifying a churning shared library because "it's core, everyone needs it"