Vadim Samokhin

@wrong.about

Dependency Inversion Principle

Decoupling, modularisation, and clean architecture

This is the fifth, and the last post on SOLID principles. Check the previous one, Interface Segregation Principle, here.

Definition

As usual, I start with Wikipedia citation:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions
B. Abstractions should not depend on details. Details should depend on abstractions.

There is no such division on A and B items in original Robert Martin’s book. Wikipedia has it, but unfortunately, it doesn’t elaborate on why is it so. Besides, it’s not clear what is assumed by high-level and low-level modules. I think it deserves some notes.

Objects exist to carry out some work. They can do it themselves, or with a help of some other objects. Chances are that those “helper” objects represent some useful abstraction, that is, there are more than one classes capable of implementing the certain contract. So I want to reflect this fact in code:

class A
{
private $b;

public function __construct(B $b)
{
$this->b = $b;
}
}

Object $b is an implementation detail for object of class A. Thus, interface B is, or, however, should be defined in terms of A, and in the same package as A. So that’s why any object implementing interface B is considered a lower-level with respect to A.

So according to its definition, Dependency Inversion Principle is about two things: decoupling and correct modularisation.

Let’s elaborate a bit further

At good old times, when nobody used interfaces, objects were instantiated right inside the classes that used them. So they depended directly on those implementation details (Figure 1 in the image below). Today we value decoupling and polymorphism, so we use interfaces to make our dependencies explicit. This is not Dependency Inversion Principle still, this is just a Dependency Injection. In order for it to become an inversion, we must claim that consumer class owns his dependency abstractions. Now, modules representing an implementation detail, depend on more abstract modules (Figure 2 on an image below). Thus, Dependency Inversion Principle reversed the dependency direction between a consumer code and dependency implementation code.

Source: en.wikipedia.org/wiki/Dependency_inversion_principle

Evolution to Clean Architecture

As a special case, and further evolution, DIP states that business-logic should not directly depend on technical details. Instead, it should define an interface that it owns, so that all the implementation code (for example, database queries, http communication, email sending and pretty much any infrastructure logic) depends on this central layer — policy layer. For me it sounds like a harbinger of a Clean Architecture:

Final thoughts

Well, this principle basically boils down to good old loose coupling thing, which has been around for at least fifty years. And David Parnas has already said everything that was necessary on how to define modules. I guess the only advantage of Dependency Inversion Principle is that it’s way less ambiguous than the others in SOLID family.

More by Vadim Samokhin

Topics of interest

More Related Stories