Legacy Coderetreat: Part 7 – Dependency inversion

Dependency Inversion

Blog post series

This blog post is part of a series about legacy coderetreat and legacy code techniques you can apply during your work. Please click to see more sessions about legacy code.

Purpose

As you found out from the previous post, it would be a good idea to refactor in a safe way. This session is about another concept that will prepare for the tough refactorings ahead.

Dependency inversion is one way of transforming a tightly coupled system into a system that has a core and many small external dependencies. These external dependencies can be called also plugins.

Sierpinski_Racket_example

Concept

If we want to test a system in isolation from slow or changing dependencies we need to isolate these static dependencies from the rest of the system. In this way we can test the system in isolation. The way we isolate the static dependency from the rest of the system is by creating an integration layer.

After we have isolated this static dependency, we need to find a way to have that part of the code testable. In the same time we need the code to be usable in a simple way in production. For that we need to invert the static dependency. So, instead of the existing system depending on the static dependency, we need to have the static dependency being injected to the rest of the system. This is what we call dependency injection.

The big concept is that high level modules should not depend on low level modules, and abstractions should not depend on details. To read more see Dependency Inversion Principle (DIP). When working on legacy code, we very often need to change a system so that high level modules are separated from low level modules. And the details are just injected, they are at the top of the system like plugins

Let’s see an example. If we have a method that adds two integers and writes the result at the console, we have a code like this:

System where dependency inversion not applied

System where dependency inversion not applied

But if we want to test that this code writes the correct message at the console, we will need to interact with the console, which is a static dependency. This is a very simple example, but if we had a database, or the need to access the memory of a device, that would make things a lot more difficult.

So we need to refactor the code. This is one way we can do this:

System where we apply dependency inversion

System where we apply dependency inversion

This refactoring got us to the situation where high level modules (the add function) are not dependent any more on low level modules (the console).

We will use this technique in the next blog post, where we will focus more on how to break the static dependencies. After we will break the dependencies we will need to apply dependency inversion.

Outcomes

As we are writing characterization tests, like in the post From Nothing to System Tests, we need to focus also on dependency inversion. In the moment when we have applied dependency inversion on all the static dependencies, we can say that we have a better design of the legacy system. In this way the system is easier and faster to test, and usually easier to change.

Probably this is one of the most used refactoring when changing legacy code. Knowing very well how to apply this session will help speeding the process of improving the legacy code.

Remarks

One should be very careful when this technique needs to be applied. The first places where we should start applying this technique is where we try to write unit tests and we fail because the test calls static dependencies. We need to start writing characterization tests, and only when the test cannot run, we need to start the refactorings. So be careful not to extract too many dependencies, because maybe we do not need to extract those dependencies. Another good reason would be that maybe now it is not the good time to extract that specific static dependency. It is important to find the good moment to extract these static depdendencies.

Besides writing unit tests on the isolated code, we should also think about writing integration tests to the static dependency. We will see that later in a dedicated blog post.

History

The Dependency Inversion Principle (DIP) is one of the SOLID Principles. Robert Martin created this concept, and wrote about it in the paper OO Design Quality Metrics and later in the paper The Dependency Inversion Principle.

Code Cast

Please find here a code cast in Java about this session

 

Image credit: http://upload.wikimedia.org/wikipedia/commons/8/8c/Sierpinski_Racket_example.png

Subscribe

If you want to receive an email when I write a new article, subscribe here:

Subscribe for new articles

Leave a Reply

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

Post Navigation