IOC Containers, Dependency Injection and Service locator

Working mainly on .NET legacy project since a few years, I often meet the same kind of problems. One of them is a bad usage of Inversion Of Control (IOC) Containers, or Service Locator to magically access everything everywhere in the code. Just like a giant singleton.

I think these tools are not well understood. They are used as part of frameworks, or as a “good practice” without understanding the reason of their exsitence.

So let’s back to basics. images

What is Inversion Of Control? (IOC)

It is when Something control your code, instead of your code controling Something.

For example, when we need a library, we call it to delegate some work (like reading a mp3 file). Hence we control it.
When we use a framework, it calls us to manage some events (like user clicks on a button).  Hence there is an inversion of control.
inversion

What is Dependency Injection?

It is when dependencies are injected into a class, instead of this class managing its own dependencies.

For example, we often need to save something using a repository. The class has a dependency on a repository. We could directly instantiate the repository in our class. As a result, we won’t be able to write unit test on this class, because it will require a database connection, no matter what is the context.
Instead, we could inject the repository, to decide depending on our context if we want to inject a test repository or a runtime repository.
 injection

Why to inject dependencies into a class? 

In OOP, computer programs are designed by making them out of objects that interact with one another.
Dependency Injection allows to change the injected class implementation, hence the behavior, depending of the execution contexts (at least test or production). It creates relationships from high-level modules to low-level modules. It is an efficient way to apply the D from SOLID: Dependency Inversion Principle.

It allows to think about a given object in isolation (by isolating its behavior), and is really convenient for unit testing. Using our own class through tests is just dogfooding, and encourages us to write simpler classes with fewer responsibilities.

dogfooding-r-w1024-q75-m1414025204

How can we inject behaviour into a class?

There are three well known possibilities:

Setter injection
A setter with the required dependency in the (public) contract of the class.

public class MyClass
{
private MyRepository _myRepository;
public void SetMyRepository(MyRepository myRepository)
{
_myRepository = myRepository;
}
}

Constructor injection
The constructor is used to inject all the dependencies at once

public class MyClass
{
private readonly MyRepository _myRepository;
public MyClass(MyRepository myRepository)
{
_myRepository = myRepository;
}
}

Service locator
A class (the locator) is called to retrieve a service for us.

public class MyClass
{
private readonly MyRepository _myRepository;
public MyClass()
{
_myRepository = ServiceLocator.GetInstance<MyRepository>();
}
}

What is an IOC container?

Inversion Of Control Container is an unfortunate name for components managing Dependency Injection, in frameworks or libraries.

When we do dependency injection using a Service Locator, we explicitly call the service to get the dependency. IOC containers do dependency injection using constructor or setter injection, there is no explicit request. Here is the Inversion of control, supposed to justify the name.

It’s a bad name because we do not care about the concept of control here, the benefit is dependency injection. In other words, to understand IOC container, forget that they do IOC, just remember they do dependency injection.

dont-try-this-at-home

How not to use it

Here is a list of usage hurting maintenance and readability I saw in different projects.

– Usage of both Dependency Injection by constructor and service Locator.
Choosing one of the three Dependency Injection methods (constructor, setter or service locator) is up to your style of code, but mixing several of them makes it hard to think about the code. Be consistent around the project, the 3 methods achieve the same goal, there is no interest in mixing them.
The lack of consistency hurts the usability of the design.
As a direct painful example, the configuration for unit testing is harder, because some dependencies have to be mocked in the IOC container, some others in the service locator.

– Usage of a static singleton of service locator.
Singleton is probably the most used pattern, unfortunately it is not always wise. It is especially hard to write independent unit tests in this case, because all the dependencies are registered in the same instance of locator.

whisky_singletonsignature

Why to avoid Service Locator

The argument to use a service locator is usually that it reduces the pain for refactoring: the only dependency we have is the service locator, because the service locator can reach anything!
I believe it hides dependencies in order to write code faster. It literally means that each class could depend of anything. And the only way to know what the dependencies are is to look at the implementation.

 b_1_q_0_p_0cri4jaoj

Why to avoid Setter Injection

The main problem with setter injection is that the class is generally not in a valid state just after the creation. I hate when I can create a class, but it raises an exception when I try to call a function because I didn’t initialize the good values. I prefer to have explicit constructor, creating classes in a valid state, or not created it at all. I believe the role of the constructor is to ensure that the new object is in a valid state.

what-is-a-sql-injection-attack

Why Constructor Injection makes sense

I prefer to use IOC container only to instantiate the first classes for the system to start. From this point, I create manually other classes, and explicit all the dependencies in every constructor. Some would argue it is too verbose, but I see it as a guide.
When the constructor is too big, it’s a code smell encouraging me to think again about my design. Lots of dependencies implies lots of responsibilities.

And we know how to deal when a class has too much responsibility, don’t we?

 

To learn more on this topic, read the excellent work from Mark Seeman and Martin Fowler.

 

Thanks Thibaud Desodt and Thomas Pierrain for suggesting improvements.

 

Ouarzy

 

2 thoughts on “IOC Containers, Dependency Injection and Service locator

  1. Lots of good points in here !
    You may also want to read DI-related articles by Mark Seemann (for instance http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ ), or also his book “Dependency Injection in .NET” that happens to cover most patterns/antipatterns … and also happens to be a great book about OO Design in general !

    Chapter 4 (readable for free here https://www.manning.com/books/dependency-injection-in-dot-net) has valid arguments about when to use Property Injection (what you call “setter injection”) , and concludes that by default you should use Constructor Injection , and fallback to other mechanisms (Property Injection / Method Injection / Ambient Context) only in some cases.

Leave a Reply

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

IP Blocking Protection is enabled by IP Address Blocker from LionScripts.com.