Dependency Inversion Principle

High-level policy should not depend on low-level detail. Both depend on an abstraction, and the abstraction is shaped by the policy, not by the detail.

Overview

The Dependency Inversion Principle (DIP) is the D in SOLID. Robert C. Martin stated it in his third C++ Report column (May 1996) in two parts. A: high-level modules should not depend upon low-level modules; both should depend upon abstractions. B: abstractions should not depend upon details; details should depend upon abstractions.

High-level means the code that holds the business rules, the part that makes the application what it is. Low-level means the mechanisms it uses: a database driver, a file, a network client, a screen. The traditional structure has the rules call the mechanisms directly, so a change in a driver can force a change in a rule. DIP flips the arrow.

  • A — policy and detail both depend on an abstraction — the service takes a Repository interface, not a Postgres class
  • B — the abstraction is not shaped by the detail — the interface says what the policy needs, not what the driver offers

The Copy program

Martin's example is a program that copies characters from a keyboard to a printer. The first version has a copy loop that calls read_keyboard and write_printer directly. It works, but it can only ever copy from that keyboard to that printer. Add a disk file as a target and the loop grows an if; add more devices and the high-level loop fills with low-level branches.

The inverted version gives copy an abstract Reader and an abstract Writer. The keyboard and printer implement them. Now the loop depends on nothing concrete, and the devices depend on the abstractions the loop defined.

Why it is called inversion

Martin chose the word because structured design produced call hierarchies where the top calls down into the details, and the dependency arrows follow the calls. In the inverted design the arrows from the details point up to the abstraction. He adds a point about layers: if policy uses mechanism and mechanism uses utility, policy depends on utility too, because dependency is transitive. Putting an abstract interface between each pair of layers cuts both the direct and the transitive dependency.

  • Policy uses Mechanism uses Utility — Mechanism, and through it Utility
  • Policy uses an abstract Mechanism interface; Mechanism implements it — only the interface it defined

Before and after

A service that decides whether an order can ship. In the first version it creates its own database access, so the rule cannot run without that database.

The inverted version declares what the policy needs as an abstraction, takes it through the constructor, and lets any implementation plug in. The test uses an in-memory one.

DIP, dependency injection and inversion of control

Three names that get mixed up. DIP is the principle: depend on abstractions, with the arrows pointing toward the policy. Dependency injection (DI) is one technique for doing that: someone outside the class hands it the implementation. Inversion of control is the older and wider term for a framework calling your code; Martin Fowler coined dependency injection in 2004 because inversion of control was too general to name the pattern.

  • Dependency Inversion — a design rule about the direction of dependencies — ShippingService depends on OrderSource
  • Dependency Injection — a way to supply the implementation from outside — ShippingService(InMemoryOrders(...))
  • Constructor injection — dependencies arrive in the constructor — as above
  • Setter injection — dependencies arrive through setters after construction — the second of Fowler's three forms (constructor, setter, interface)
  • Service locator — the class asks a registry for what it needs — every user now depends on the locator
  • DI container — a framework does the wiring — Spring, Guice, .NET DI

You can follow DIP with no framework at all. A main function that builds the concrete objects and passes them in is enough. Fowler's point is that what matters is separating the configuration of services from their use.

Who owns the abstraction

Part B of the principle answers this. The abstraction is not shaped by the detail; it is shaped by what the policy needs. So the interface belongs with the policy: it is named in the policy's terms (OrderSource.get, not PostgresConnection.execute) and lives in the policy's module. The detail then adapts itself to that interface. This is the same idea as ports and adapters (Alistair Cockburn, 2005), where the application defines ports and each technology supplies an adapter, so the application can be driven by tests as easily as by users and run without its real database.

What you will be able to do

  • State both parts of the principle and explain what is being inverted.
  • Draw the arrows for a service that creates its own database access, then redraw them inverted.
  • Tell DIP, dependency injection and a DI container apart.
  • Put the interface with the policy and explain why a test double is then easy.

Interview questions

  • What is the difference between Dependency Inversion and Dependency Injection?
  • How does DIP make code testable?
  • How do you implement DIP in Java, Python and Go?
  • What is a composition root and why does it matter?
  • What are the downsides of applying DIP everywhere?
  • How does DIP relate to hexagonal architecture?

Sign up free to read the full topic

More Low-Level Design topics

Start free on Cariara · Coding problems · System design studio