2.2.8 · D1Design Principles

Foundations — SOLID — Dependency Inversion Principle

2,802 words13 min readBack to topic

This page builds every word and symbol the Dependency Inversion Principle uses — module, dependency, arrow direction, abstraction, interface, coupling, and the symbols , , , — from nothing. Everything you need is defined right here on this page; nothing is assumed from elsewhere.


1. What is a "module"?

Figure — SOLID — Dependency Inversion Principle
Figure 1 — Two boxes side by side. The yellow box is policy (rarely changes, valuable); the blue box is mechanism (changes often, swappable). The figure fixes the colour code — yellow = high-level, blue = low-level — that every later diagram reuses so you can track a box by its colour alone.

We split modules into two kinds:

  • High-level module = the box holding policy — the rules, the "what to do". Rarely changes. Valuable.
  • Low-level module = the box holding mechanism — file I/O, database, email. Changes often. Cheap / swappable.

2. What is a "dependency" and its "arrow"?

Figure — SOLID — Dependency Inversion Principle
Figure 2 — The pink solid arrow is the source-code dependency (who names whom); the white dashed arrow shows the tremor of change travelling backwards up it. The figure adds what words alone hide: these two arrows are separate ideas, and the danger is the tremor reaching your yellow policy box.


3. What is an "abstraction" / "interface"?

Figure — SOLID — Dependency Inversion Principle
Figure 3 — The contract box sits above both. The yellow policy arrow and the blue detail arrow now both point UP at the shared shape. The independent insight: notice the blue arrow has physically reversed compared with Figure 2 — that reversal is literally the "inversion" the principle is named after.

The interface should be owned by / live near the high-level policy. That is what turns the low-level box's arrow upward — the detail now depends on the policy's contract, inverting the original arrow.

Seeing the inversion in actual code

Words describe the flip; code proves it. Here is the before — policy welded to a detail:

// BEFORE — arrow points DOWN from policy to concrete detail
class NotificationService {              // high-level policy
    EmailSender sender = new EmailSender();   // names a concrete detail!
    void notify(String m) { sender.sendEmail(m); }
}
class EmailSender {                      // low-level detail
    void sendEmail(String m) { /* SMTP code */ }
}

NotificationService spells out EmailSender. Source-code arrow: NotificationService → EmailSender. To add SMS you must open and edit the policy box.

Now the after — introduce a contract the policy owns and hand the detail in:

// AFTER — arrow points UP from BOTH to the shared contract
interface MessageSender { void send(String m); }     // contract (owned by policy)

class EmailSender implements MessageSender {          // detail's arrow now points UP
    public void send(String m) { /* SMTP code */ }
}
class SmsSender implements MessageSender {             // a second detail, same shape
    public void send(String m) { /* SMS gateway */ }
}

class NotificationService {                           // high-level policy
    private final MessageSender sender;
    NotificationService(MessageSender s) { this.sender = s; }  // handed in, never `new`ed
    void notify(String m) { sender.send(m); }
}

What changed: NotificationService no longer names EmailSender — it names only MessageSender, a stable shape it owns. The concrete EmailSender now names (implements) the contract, so its arrow flipped upward. That single reversal is the whole principle.


4. What is "coupling"? ( and )

Figure — SOLID — Dependency Inversion Principle
Figure 4 — One box in the middle with pink arrows arriving (counted as ) and blue arrows exiting (counted as ). The figure turns two abstract letters into something you can literally count on your fingers: tally the incoming heads, tally the outgoing tails.


5. The two numbers: (instability) and (abstractness)

Now the two summary numbers are earned.

The A–I plane: where a module lives

Because both and run from to , we can plot every module as a point on a square. This single picture tells you at a glance whether a module is healthy or in trouble.

Figure — SOLID — Dependency Inversion Principle
Figure 5 — The Abstractness (, up) vs Instability (, across) square. The diagonal is the main sequence (healthy). The bottom-left corner is the Zone of Pain; the top-right is the Zone of Uselessness. The figure gives learners a map they can drop any measured module onto — text can name the zones, but only the picture shows how far a point sits from the healthy line.


How the foundations feed the topic

Module = a labelled box

Dependency arrow = who names whom

High-level vs Low-level

Inversion = flip the arrow

Abstraction / Interface = the contract

Coupling counts Ca and Ce

Instability I = Ce over Ca plus Ce

Abstractness A

A-I plane: pain vs uselessness

Dependency Inversion Principle

Related tools that deliver the inverted arrow (built on these same foundations): Dependency Injection, Strategy Pattern, Factory Pattern, Inversion of Control Containers, and the architecture-scale version Hexagonal Architecture / Ports and Adapters. DIP sits alongside its SOLID siblings SOLID — Single Responsibility Principle, SOLID — Open-Closed Principle, SOLID — Liskov Substitution Principle, and SOLID — Interface Segregation Principle.


Equipment checklist

Recall Can you answer each before reading the main note?

What is a "module" in one phrase? ::: A self-contained named chunk of code — usually one class or file — that does a job. High-level vs low-level module? ::: High-level = policy / the what; low-level = mechanism / the how (DB, email, I/O). What does the dependency arrow actually mean? ::: A cannot be written/compiled without naming B — A depends on B. Why does the arrow's direction matter so much? ::: Change flows backwards up the arrow; you want it pointing toward the thing that changes least (stability). What is an interface/abstraction? ::: A contract: method names and shapes with no implementation — the "what", never the "how". In the before/after code, what one change inverts the arrow? ::: The concrete detail starts to implement a contract owned by policy, so its arrow flips upward, and the policy names only the contract. Where should the interface live for a true inversion? ::: Near/owned by the high-level policy, so the low-level detail's arrow points up to it. What is (afferent coupling)? ::: The number of outside modules that depend on this one (arrows arriving). What is (efferent coupling)? ::: The number of modules this one depends on (arrows exiting). Formula and range of instability ? ::: , ranging ; = maximally stable, = maximally unstable. What happens to when ? ::: It's , undefined — an orphan module with no arrows; the metric doesn't apply, so exclude it (report N/A). What does tell you? ::: : the module depends on nothing, so nothing forces it to change — maximally stable. Formula for abstractness ? ::: , the fraction of a module's types that are abstract/interfaces. What is the "main sequence" ideal? ::: : the more depended-upon (stable) a module is, the more abstract it should be. What is the Zone of Pain? ::: Low , low — a concrete module everything depends on: rigid and load-bearing, painful to change. What is the Zone of Uselessness? ::: High , high — an abstract module nobody uses: dead abstraction / clutter.