Dependency inversion
Dependency inversion is a design principle of object-oriented programming. It is the D in SOLID, the family of principles popularized by Robert C. Martin. Dependency inversion governs the direction of dependencies between modules. The principle has two clauses.
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend on details. Details should depend on abstractions.
In a conventional layered design, a high-level module that encodes business policy depends on the low-level modules that implement mechanisms such as data access, messaging, or calls to external services. The dependency direction follows the call direction. When a low-level module changes, the high-level module that depends on it must change too, even though the policy it expresses has not changes. Thus, policy is held hostage to mechanism.
Dependency inversion reverses this. The high-level module defines an abstraction – typically an interface – that describes the capability it needs, and both the high-level module and the low-level implementation depend on that abstraction. The low-level module now depends on the abstraction that the high-level module owns.
A typical consequence is that the high-level module no longer mentions any concrete low-level type. Some other agent supplies a concrete implementation at the seam – a constructor, a factory, or a dependency injection container. The high-level code continues to work because of polymorphism. Every low-level implementation satisfies the shared interface, so the call dispatches to whichever one is supplied.
The payoff is that high-level policy becomes independent of the volatility of low-level detail. A change to a database driver, a third-party API, or a message transport touches only the implementation behind the abstraction. The policy module, its tests, and every other module that depends on the same abstraction are untouched. The principle thus protects the parts of the system that change least – the business rules – from the parts that change most — the infrastructure.
The dependency inversion principle is itself one form of inversion of control, a related design principle.
The dependency inversion principle is behind several architectural styles that keep business logic at the center and push infrastructure to the edges. The hexagonal architecture, onion architecture, and clean architecture each express the same dependency rule. Dependencies point inward, toward the domain, and outward-facing layers depend on inner abstractions rather than the reverse. At the design pattern level, the adapter pattern and the strategy pattern are both applications of dependency inversion, since each lets a client depend on an abstraction while concrete implementations vary behind it. The publish-subscribe pattern is another. Publishers and subscribers both depend on the message abstraction rather than on each other.
Trade-offs
Dependency inversion trades directness for flexibility. Every inverted dependency adds an abstraction and a seam, which is indirection a reader must follow. In a small or stable system the abstraction may not pay for itself, and a dependency that never varies is better left concrete until it does. See YAGNI.
The principle also depends on the abstraction being honest. If the interface leaks the concerns of a particular implementation – a method shaped to fit one database vendor, an error type that exposes a transport detail – then the high-level module is coupled to the low-level detail through the abstraction itself, and the inversion is only nominal. See leaky abstractions.
A related pitfall is inverting dependencies prematurely. Introducing an interface for every collaboration, ahead of any second implementation, produces empty abstractions that multiply without earning their keep.
The dependency inversion principle is best applied where a dependency is genuinely volatile or where testability demands a seam, not as a blanket rule over every collaboration.
See also
- Abstraction
- Clean architecture
- Composition
- Coupling
- Decoupling
- Dependency injection
- Design patterns
- Encapsulation
- Hexagonal architecture
- Inversion of control
- Leaky abstractions
- Onion architecture
- Polymorphism
- SOLID
References
- Martin, Robert C. (1996). The Dependency Inversion Principle. C++ Report.
- Martin, Robert C. (2002). Agile Software Development, Principles, Patterns, and Practices. Pearson.