A system is made up of many modules.
Some modules change often — like user interfaces, APIs, or integrations. Others rarely change — like core business rules or domain logic.
The goal of good design is to make this difference explicit — and to shape dependencies around it.
Dependencies express assumptions about stability
When module A depends on module B, A is making an assumption:
“B will stay stable longer than I will.”
If that assumption turns out to be false, your system becomes fragile. A change in B will ripple outward and force A (and maybe everything else) to change too.
That’s why dependencies should always point toward stability — toward the parts of the system that represent long-term truths.
The more stable a module is, the safer it is for others to rely on it.
You can picture this as a stability gradient:
Volatile details (frameworks, UI, I/O) → depend on → Stable core logic (business rules, domain concepts).
Never the other way around.
Abstractions exist to isolate volatility
Abstractions — like interfaces, adapters, or wrappers — aren’t for decoration. They exist to contain change.
You introduce an abstraction only when you expect its implementation to shift in the future.
If your database engine, API provider, or message queue might change, an abstraction helps you isolate that volatility.
But if something is unlikely to change — like core domain logic — adding an abstraction only makes the code more complicated for no real gain.
Abstractions are boundaries for change. They keep the “moving parts” from contaminating the stable core.
Their purpose is control, not elegance. Elegance is a side effect.
The Stability Gradient
Imagine your system as a set of tectonic plates:
Core (highly stable): domain logic, rules, long-term invariants Edges (volatile): frameworks, APIs, databases, UI Dependencies should always flow inward, from the volatile edges toward the stable center.
When outer layers shift — new framework, new API, new storage — the core remains steady.
A system designed this way absorbs change instead of collapsing under it. Stability at the core gives flexibility at the edges.
Good architecture doesn’t resist change — it channels it. The sooner we design for that reality, the longer our systems survive. Thank you for reading. Share if you found this useful