A Guide to Loose Coupling and Writing Better Python Code With Dependency Inversion

A Guide to Loose Coupling and Writing Better Python Code With Dependency Inversion
Photo by Rachel Nickerson / Unsplash

This post is part 5 of a series on the SOLID principles.
You can find post 4 here, post 3 here, post 2 here and post 1 here.  

We have finally reached the last of the SOLID principles 😇
As usual we start with a definition:

Principle 5 is named the dependency inversion principle.
The definition has two parts:

A. High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).

B. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

Source: Dependency inversion principle - Wikipedia

In traditional software architecture we design lower level components to be used/consumed by higher level components. In other words, higher level components depend on lower level components. This dependency causes tight coupling in the software. As explained in principle one, we strive to achieve loose coupling to make it easier to develop, maintain and change code in the future.

The dependency inversion principle inverts this dependency in the sense that instead of higher level components depending on lower level ones, both should depend on abstractions. This abstraction layer would be an intermediate component that sits between the higher and lower level components. The two will then use this component to communicate and interact amongst each other. The abstraction component would usually be implemented as an interface.

Time for some code and a concrete example!

Code

Consider the following example where we model a robot:

The Robot class has only one function get_energy.
We model an Apple that the robot can get energy from.

Now, at some point the robot will get tired of eating apples.
So we add a Chocolate class to offer more eating options to the robot.

Notice however, what happens to the get_energy method. We must pass a string as a parameter indicating what eatable the robot should eat. Also, we must use if-else branching on the two different eatables. Now you can imagine if more eatables are added we would need more else branches. This is not good design.

Furthermore, because Robot has a dependency on each of the individual eatables we will run into issues if the implementation of one of the eatables changes. For example, if we introduce an additional parameter to the eat method in Chocolate the code in get_energy would break and we would have to refactor it to reflect the changes in Chocolate. These issues occur due to tight coupling and strong dependencies and are a violation of the dependency inversion principle.

Currently our architecture looks as follows:

Robot with dependencies on Apple and Chocolate

Solution  

To solve this, we need to introduce an abstraction layer.
We modify the architecture as follows:

Removing tight dependencies through abstraction layer: Eatable interface

The code looks like so:

We create an Eatable interface that is implemented by both Apple and Chocolate.
We change the method signature of get_energy so that it expects an argument of type Eatable instead of str. This means we can get rid of the if-else branching. Furthermore, since all eatables implement the Eatable interface we are sure that there will be no code breakage if there changes to Chocolate or Apple.

Conclusion

In this post, we looked at the dependency inversion principle. The principle essentially states that higher level modules should not depend on lower level modules. Instead both should depend on abstractions. We make higher level modules independent of implementation specifics in lower level modules.

The principle:

  • Enforce loose coupling and thereby helps make code more robust in face of changes.
  • Allows re-use of higher level components since the abstraction layer prevents code breakage in case the lower level components need to be changed.

We have finally reached the end!

I hope you enjoyed this post and all the previous posts on the SOLID principles.

You might consider signing up for my newsletter to get awesome content in the future!


Enjoyed this article? Please consider subscribing using the form below😇
It is 100% free. You get an email every time I post (about once a week) + access to premium content in the future. Connect with me on LinkedIn or follow on Twitter.