The Dependency Inversion Principle

The dependency inversion principle(known as DIP from here on out) is one of the core tenants of the S.O.L.I.D principles and probably my favorite. This principle underlies so many of the design patterns we see in software and system design and as a result if you understand it then you begin to see systems all around you in an entirely new light.

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

B. Abstractions should not depend upon details. Details should depend upon abstractions.

~Uncle Bob

Bear with me…The above statement sounds a little confusing but its actually pretty simple. We all use devices that implement this principle ALL THE TIME.

Lets take cars for an example. Everyday I get in my car and I turn the key and the engine comes to life. I am abstracted from the complexities of my engine.

ABSTRACTED

Now lets say one day I’m driving my car and unfortunately my engine breaks and I need a new one. I’m a little tight on cash and I decide I want an engine thats cheaper than the one I had before. I shell out the dough to the mechanic and he does the replacement for me. Now imagine that when I come pick up my car the mechanic hands me a different steering wheel, gas pedal, and radio. The mechanic explains to me that because of my new engine I need to have a different version of all the items he handed me. I have just learned the hard way that my car depended on a concrete implementation of an engine. Lets look at some code to illustrate this in the software world.

The problem with this situation is the my concrete engine has exploded and I want to be able to swap in a new one without even noticing it. With the above case I have to go change code in my car class now. This violates the open/close principle of S.O.L.I.D. A much better implementation would be like below

What we did here is create an abstraction. Now our higher level module(the car) depends on an abstraction(Engine) as opposed to a low-level module. As for part B of uncle Bob’s statement. We don’t want our abstraction to depend on a low-level module. So if ConcreteEngine ever needs to change then it has to make sure that it still stays within the constraints of the abstraction.

SOAP BOX TIME

The reason i singled out this particular principle is because it is everywhere in software. When building large software projects with ever changing requirements you want software that can change with the requirements and not become a huge hassle. An example of this is data retrieval for an application.

In my experience we have had applications that speak directly to a database and then as security and data integrity concerns grow we are instructed to change our apps so that they make REST calls to another service to get the same data. If several parts of our code are tightly coupled to a specific way of retrieving data then refactoring the codebase to make REST calls becomes time consuming, complicated, and cumbersome. It also drags down developer moral. Developers love doing interesting, fun, and challenging work. Making several changes to a code because of bad design is a waste of the company and developers time.

Another aspect where this principle is seen frequently is in software design patterns. Many software patterns were birthed out of a desire to have a code base that can be easily modified.

That’s it for this post. Let me know what you guys think!

Add a Comment

Your email address will not be published. Required fields are marked *