Cover Image

Dependency Inversion Principle

DIP

“High-level modules should not depend on low-level modules. Both should depend on abstractions.” – Robert C. Martin

“Abstractions should not depend on details. Details should depend on abstractions.”

When to use

Always, when connecting two layers of your application (e.g., Domain Logic connecting to Database, or Controller connecting to Service).

Why it matters

  • Decoupling: High-level business rules don’t care about the messy details of databases, APIs, or UI.
  • Flexibility: You can swap out a database (MySQL -> Postgres) without changing a single line of business logic.

Signs of Violation

  • Using the new keyword to instantiate low-level dependencies inside a high-level class.
  • Importing concrete classes (e.g., import MySQLDatabase) in your domain logic.

Explanation

Problem

If high-level modules (business logic) depend directly on low-level modules (utility classes, DB drivers), changes to the low-level details can break the high-level logic.

Solution

Invert the dependency. Define an interface (the abstraction) in the high-level module. Make the low-level module implement that interface. Now both depend on the interface (abstraction).

Real world analogy

You plug your lamp into a wall socket (interface). You don’t solder the lamp directly to the electrical wiring in the wall (implementation). This allows you to plug the lamp into any socket, and the socket to power any device.

Pros and Cons

Pros Cons
  • Loose coupling
  • Easier unit testing (mocking)
  • More boilerplate (interfaces)
  • Code can be harder to follow (indirection)
  • Comparison

    • Dependency Injection (DI): A pattern/technique used to implement DIP.
    • Inversion of Control (IoC): A broader principle where the flow of control is inverted; DIP is a specific form of this related to dependencies.

    Code example

    Typescript

    Bad (Violation)

    Good (Adherence)

    PHP

    Bad (Violation)

    Good (Adherence)