What is Dependency Inversion? (in plain English)

Anatoly Volkhover
Become an Awesome Software Architect
5 min readOct 30, 2019

--

Speaking with many software engineers, including very experienced ones, I realized that the purpose of Dependency Inversion is poorly or incorrectly understood. This is one of the cornerstone principles of code composition, and many think of it as simply a “trick with interfaces” which somehow magically works. Time to demystify it.

Consider a highly hypothetical example. Imagine you quit your engineering career (!), and opened a pizza shop in Mountain View, CA. Your main customer is a large high-tech company Zoogle located down the street, which keeps you busy. The company pays for the food ordered by the employees, and they even streamlined the process by creating a Google Form for ordering. When hungry, all a Zoogle engineer has to do is fill in their name, select the desired toppings and push the Send button. This automatically emails the doc to you, and you make and deliver the pizza to the company’s front desk. Easy.

Through the first year of your shop’s existence, the number of orders increased so much you were getting too many emails to handle them manually. Thank God all the emails share the same consistent format since they are based on the same Google Form. You dusted off your Python coding skills and wrote a tiny program, which parsed the incoming emails and entered the orders automatically into your point of sale system.

Another year passes by. Your business is thriving, and you decide to take a break and go on a long-awaited (and well-deserved) vacation to Bora Bora. You board the 2 pm United flight UA115 from SFO, land on Tahiti 8 hours later, then a quick hop between the islands next morning — and you are in paradise!

Bora Bora is indeed so good; that’s why they named it twice.

Then the unimaginable happens. In an attempt to make the Google Form prettier, someone at Zoogle changes its format. The new template looks awesome, but the new format breaks your little Python automation. Your business immediately stalls, and you are too far away. You are relaxing on the beach and not even checking your emails. Ouch!

Turns out that your business has a hidden dependency on the form owned by your customer. BTW, when saying dependency, I mean the following: A depends on B if changes made to B may require A to change. In the above example, a change to the ordering form by Zoogle (B) forces your business (A) to rewrite your Python automation, therefore your business (A) depends on Zoogle (B).

Sounds logical… but could you do better?

The answer is yes. You could have provided your own form to the company for ordering pizza. Heck, you could probably do even better, and give them an online form. Either way, by publishing your own form, you could have inverted the dependency — making the company employees dependent on your form, and not the other way around. All that was required from you is to clearly declare the contract for engaging your services.

In the nutshell, this is what dependency inversion is all about. It breaks the natural order in which the consumer of the data (the pizza shop) depends on the supplier of the data (the customer). It turns the tables, making the supplier dependent on the consumer.

We encounter Dependency Inversion every day. Almost every time you are filling out a form to order a service, you are dealing with an inverted dependency. Service providers don’t want to be dependent on you, and they invert the dependency by forcing you into compliance with their contracts (forms).

In software engineering, this is usually implemented through the use of interfaces. An interface published by a service provider is an equivalent of the form handed out to a customer. A pizza ordering interface may look like this:

Now, the code that creates a new pizza order is forced into compliance with the contract:

This simple “trick” became the basis for the Dependency Inversion Principle (DIP), which demands that your higher-level implementation should never depend on a lower-level implementation, but rather on an abstraction of that lower-level implementation.

Here is a more technical example. Imagine you are writing code which needs a logging library to print out diagnostic messages. Let’s say you found a third party library that does the work nicely. The most straightforward way to incorporate it into your app is to import the library and start using it. However, this creates a problem very similar to the pizza shop scenario from the earlier: your application code (the consumer of logging functionality) becomes dependent on the library (the supplier of the functionality). Every time the supplier changes the library’s interface, you have to change your code. This makes you vulnerable as the use of the library proliferates through your code, and makes you heavily dependent on one particular vendor (this is known as vendor lock-in). Besides, you will be also stuck with an old version of the library for a long time or forever. To avoid this, your application must define the contract that has everything it needs from a logging library, and use it throughout the code. The contract is the abstraction mentioned by DIP (see above). It may take a number of shapes and forms. The most obvious one is an interface, although other options exist (for instance, a microservice endpoint). You will likely end up writing a small adapter which translates your contract to the specifics of a particular library implementation (a bit of extra code), but this saves you a lot of time refactoring the code once you decide to replace the library (if done right, there should be no changes to the application code at all).

DIP is one of the five famous code composition principles known as SOLID:

  • The Single Responsibility Principle (SRP)
  • The Open-Closed Principle (OCP)
  • The Liskov Substitution Principle (LSP)
  • The Interface Segregation Principle (ISP)
  • The Dependency Inversion Principle (DIP)

Would you like to learn more about SOLID, as well as other foundational software architecture principles and patterns? Check out my recent book Become an Awesome Software Architect. The book covers all the important fundamentals of software architecture and code composition, to help you up your game as a developer, an engineering leader, or a techpreneur.

See you around!

--

--

Anatoly Volkhover
Become an Awesome Software Architect

Serial entrepreneur, dynamic engineering leader, software architect extraordinaire, marketer, and writer. https://www.linkedin.com/in/anatolyvolkhover