DIP - The Dependency Inversion Principle

The Dependency Inversion Principle is a part of SOLID, a mnemonic acronym which bundles a total of 5 design principles.

It is often associated with clean code.

But what exactly is it, is it important to you, should you even care?

🧵👇
1⃣ What does it state?

It states:

Modules that encapsulate high-level policy should not depend upon modules that implement details. Rather, both kinds of modules should depend upon abstractions.

This may sound a little complicated, but you can break it up, as follows:
1. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).

2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
Still not better?

Okay, view it this way:

Don't let anything you build depend on a concrete implementation of something.

Better depend on an abstract description of a contract, and let any implementor decide how to satisfy that contract.

👇
2⃣ An Example

Take a look at the following example (which is in TypeScript):

What you see here is one way of structuring a backend API.

A resource layer that implements the specific of the API, a service which contains the business logic, and repositories which handle ...
... the persistence layer (e.g. database interactions).

And if you take a closer look, you can see that the high level class (resource) depends on a concrete lower level class (service) which itself depends on two (more) lower level classes (repositories).
The control flow thus goes from left to right, from the highest to the lowest level.

It is like a Singly Linked List, every higher-level module references at least one lower-level module.

👇
3⃣ What does it try to prevent?

Whenever you couple a module (a class, a function, a whole module) to another module, that first module depends on a lot of lower-level detail.

In object-oriented systems this also means that you can only replace the logic you depend on ...
... by deriving from exactly this class and overwriting existing logic.

This is a pretty tight coupling, and a lot of inflexibility.

It becomes pretty difficult to replace lower-level logic, and changes to the lower-level logic might have a larger impact on higher-level one.
Just imagine you'd now restructure the TransactionService from the example.

You couldn't tell, without taking an explicit look at the TransactionResource, that you maybe now have to also make adjustments there.

Another issue is the direct dependency on the lower-level module!
If you apply this example to a library, and class A depends on class B, and both originate from different modules, a user would always have a dependency on module A and module B (transitive).

A user couldn't even choose to not take B, because the direct relationship exists!

👇
4⃣ Fixing the issues

You can inverse the control flow by letting each concrete implementation either depend on an interface or implement said interface.
Instead of the control flow going from the highest to the lowest level modules, there is now an abstraction in-between them!

And before you shout it out loud, yes, this adds more code overall, as each interface also needs to be described first.
But do you remember the issue with module dependencies?

Instead of module A now requiring also module B, module B now requires module A (given module A defines the interface), and this gives users the choice whether they want to pull in B, as well, or want module C...
...as an alternative to provide another implementation of the interface, which might be a better option for their use case!

👇
5⃣ Should you care?

Well, it depends!

In dynamically typed languages like JavaScript, you already depend on interfaces pretty much everywhere, as you can simply call any method or property on any object.

As long as a user provides everything you require, you're good to go!
But as soon as static typing comes into play, you should indeed care.

You gain all benefits described within this thread, and it'll improve your code quality, usability, and maintainability a lot.

The benefits weigh pretty heavy, and should not be ignored!
You can follow @oliverjumpertz.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled: