The Dependency Inversion Principle: Depend on Abstractions, Not Concretions

2026-04-30

The Dependency Inversion Principle (DIP) — the "D" in SOLID — states two things: (1) high-level modules should not depend on low-level modules; both should depend on abstractions, and (2) abstractions should not depend on details; details should depend on abstractions. This sounds academic until you feel the pain of violating it.

Imagine an OrderService that directly instantiates a PostgresRepository and a StripePaymentGateway. Your high-level business logic — processing orders — is now welded to Postgres and Stripe. Want to swap to MySQL during a migration? Need to run tests without hitting Stripe's API? You're rewriting OrderService.

The fix is to invert the dependency direction. Instead of OrderService reaching down to concrete implementations, you define interfaces that the high-level module owns:

Now PostgresRepository implements OrderRepository, and StripeGateway implements PaymentGateway. The critical shift: the interfaces live with the high-level module, not with the implementations. The low-level modules depend upward on those abstractions, not the other way around.

This is different from simply "coding to an interface." DIP is about who owns the abstraction. If your OrderRepository interface lives in the postgres package, you've technically used an interface but haven't inverted anything — your domain still depends on your infrastructure package.

A real-world example: a notification system that sends alerts via email, Slack, and SMS. Without DIP, your AlertService imports all three clients. With DIP, you define a Notifier interface in the alerting domain. Each channel implements it. Adding PagerDuty means writing one new class — AlertService never changes.

Rule of thumb: count your import statements. If a high-level module imports more than 2-3 infrastructure packages directly, you're likely violating DIP. Each direct infrastructure import is a coupling point that makes testing harder and change riskier.

Common mistakes to avoid:

See it in action: Check out Depend on Abstractions not Concretions (Framework) by Christopher Okhravi to see this theory applied.
Key Takeaway: High-level business logic should define the interfaces it needs; low-level infrastructure modules implement those interfaces and depend upward — never the reverse.

All newsletters