Catalog / SOLID Principles / Dependency Inversion Principle (DIP)
SOLID

Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Intent & Objective

Abstractions should not depend upon details; details should depend upon abstractions. Invert the traditional top-down dependency graph so core business rules are decoupled from concrete database, network, or UI drivers.

πŸ‘₯ Real-World Human Analogies & Social Roles
1 Intuitive Scenarios
Wall Electrical Outlets Home Construction

"A lamp does not solder directly to copper wiring inside the wall; both depend on the standardized wall outlet socket abstraction."

The Problem

In tightly coupled code, a high-level service directly instantiates concrete drivers (e.g., `new MySQLDatabase()`, `new SmtpMailer()`). Testing without a real database becomes impossible, and swapping to PostgreSQL or AWS SES requires modifying core business logic.

The Solution

Define an interface owned by the high-level layer (e.g. `UserRepository`). Have low-level drivers (`PostgresUserRepository`) implement that interface, and inject the implementation at runtime (Dependency Injection).

Key Participants & Architectural Roles

High-Level Domain Service
Contains high-value business logic and defines interface requirements
Interface / Port
Specifies the contract that high-level modules require
Low-Level Adapter / Detail
Implements the contract using specific libraries or hardware

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, DIP is achieved via interfaces and Dependency Injection (IoC containers). In Functional Programming, DIP is achieved via Dependency Injection through Parameter Passing (Partial Application / Currying): high-level functions take their dependencies (effectful functions) as arguments, leaving pure domain logic free of I/O.

Advantages

  • βœ“ High-level business logic is completely isolated from framework and database churn
  • βœ“ Enables effortless mocking for unit testing
  • βœ“ Powers Clean Architecture and Hexagonal / Ports & Adapters design

Trade-offs

  • βœ— Requires Dependency Injection containers or manual wiring boilerplate at application startup

When to Apply

  • β†’ Whenever business services need to interact with databases, network APIs, or disk files
  • β†’ To build testable systems where infrastructure can be swapped with in-memory test doubles

When to Avoid

  • ! For stable utilities that never change (e.g. Math libraries or standard string helpers)