SOLID Principlescritical

Dependency Inversion Principle (DIP)

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.

Memory anchor

DIP = wall outlets. Your laptop (high-level) doesn't hardwire to a specific power plant (low-level). Both depend on the standard outlet interface. Swap coal for solar — the laptop never knows.

Expected depth

DIP means your business logic (OrderService) should not directly instantiate or import your infrastructure (MySQLOrderRepository). Both should depend on an OrderRepository interface defined in the domain layer. The dependency flows inward: infrastructure adapts to domain contracts, never the other way. DIP is what makes Dependency Injection (the technique) necessary: since high-level modules no longer create their dependencies, something else must provide them.

Deep — senior internals

DIP is the principle that makes large-scale architecture possible. Without it, your entire codebase is a single connected component — a change to a low-level database driver forces recompilation of business logic. With DIP, you invert the dependency graph: the core domain is dependency-free, and all infrastructure points inward. This is the Clean Architecture / Hexagonal Architecture / Ports & Adapters architecture. In Java, this is enforced by putting interfaces in the domain module and implementations in the infrastructure module. The inversion of the Dependency Inversion name is about the inversion of control flow vs source code dependency: the high-level module calls the low-level module at runtime (control flows down), but the source code dependency is inverted (low-level implements the interface defined in high-level).

🎤Interview-ready answer

DIP says my OrderService should not import MySQLOrderRepository directly — it should import an OrderRepository interface defined in the same domain package. MySQLOrderRepository implements that interface. Now if I swap MySQL for Postgres, the service never changes. DIP also makes unit testing clean: I inject a MockOrderRepository that satisfies the interface, no real database needed. This principle is the motivation behind dependency injection containers and the ports-and-adapters architecture.

Common trap

DIP is not the same as Dependency Injection. DI is the technique (passing dependencies); DIP is the principle (depend on abstractions). You can violate DIP while using DI if you inject a concrete class rather than an interface.

Related concepts