The Dependency Injection Jungle
This is a short overview of IoC (inversion of control), DI (dependency injection) and DI containers I was asked to do for my colleagues at work.
In this post there is no code at all but lots of links and explanations. Hopefully somebody manages to read it through.
TL'DR
Inversion of control is used to increase modularity of the program and make it extensible,maintainable, testable and its dependencies more discoverable.
To begin to reap these benefits you really don't need to know most of what I talk about in this post. You just need to know how to implement DI e.g through constructor injection.
You basically just need to tell a IoC Container[1] what implementation it should serve up for each interface it encounters and initiate the container once in the app startup!
That was the quick and dirty of it all.
So what are you talking about?
Well it both kinda of easy and difficult to explain.
The problem is that here are many different words used when this matter is discussed.
Here are at least few
- Inversion of control (IoC)
- Dependency INJECTION pattern
- Dependency INVERSION principle (DIP)
- Inversion of Control Containers (IoC Container)
- Service Locator
Confused?
I think it basically boils down to two things
- pattern/principle
- practical implementation.
The pattern/principle
Lets see what Martin Fowler had to say about IoC in 2004.
Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.[2]
Note that Martin used Injection instead of Inversion so that is probably the source of the interchangeable usage of the two words (but I'm not 100% sure).
So I'm going to assume that the following applies
Dependency Inversion == IoC == Inversion of Control=> Dependency Injection
Where, principles => practice
But what is it really?
First a little history trivia
The term [inversion of control/dependency injection pattern] was used by Michael Mattsson in a thesis [3] , taken from there[4] by Stefano Mazzocchi and popularized by him in 1999 in a defunct Apache Software Foundation project, Avalon, then further popularized in 2004 by Robert C. Martin and Martin Fowler. [5]
But that doesn't tell you much does it?
Lets then try this one.
Its the D in the SOLID principles.
"Depend on abstractions, not on concretions."
Wikipedia has this on what its used for [5:1]
- To decouple the execution of a task from implementation (look at "new is glue"[6])
- To focus a module on the task it is designed for.
- To free modules from assumptions about how other systems do what they do and instead rely on contracts.
- To prevent side effects when replacing a module.
I think we can add these here below that could be looked at as side affects of IoC
- it reveals class dependencies (specially if construction injection is used)
- it helps making code extensible
- it helps making code testable.
One fun fact is that IoC is sometimes called "Hollywood Principle as in Don't call us, we'll call you"
So what problems does it solve?
It makes the code loosely coupled and more easily testable.
Imaging you have a method in a class that calls another one that e.g sends an email and you wanted to test that method?
You wouldn't want to send an email every time you ran the tests would you?
If your email method is based of of interface you can swap it out with a fake/mocked version of that class, where the method could just always return "Success"/"Failure" depending on your test.
Implementation in practice with Containers
As before I assume the following
IoC Container == Dependency Inversion Container == Dependency Injection Container
So what is a Container?
IoC Container (a.k.a. DI Container) is a framework for implementing automatic dependency injection. It manages object creating and its life time and also injects dependencies to the class. [7]
Break that down and you get
- framework
- automatic dependency injection
- manages object creation and life time
- injects dependencies to a class
That basically means that once at the start of your app, you use a DI Container/Framework to match an interface to an concrete implementation of that interface.
The framework then automatically sees to it that the class gets that implementation on runtime without you needing to do anything more.
Here is an excellent code example with to look at Dependency Injection: Going Start to Finish With Unity in C#
Types of containers and their performance
There are many many different IoC Containers out there. I have mostly used Unity.
My personal problem with Unity is that it has rather poor documentation and is now far from being the most performant one.
Please look at the following two sources before you choose a container
- Containers performance with Xamarin.Forms when deciding for mobile development
- IoC Performance
Do you even need a Container?
No you don't need a container to do DI.
You can use Poor mans DI and could get away with it. But why would you? I think containers make your life much easier that without them.
There is also the option of creating your own IoC Container using reflection and generics.
Mark Seemann as a good article on when to use DI containers with a good graph.
I have Maks book Dependency Injection in .NET here on the table with me. I hope I'm doing it some justice.
Service Locator is an anti-pattern
I myself have used service locators in the past where I did not have access to containers through the constructor and refactoring was not an option.
In short, the problem with Service Locator is that it hides a class's dependencies, causing run-time errors instead of compile-time errors, as well as making the code more difficult to maintain because it becomes unclear when you would be introducing a breaking change.[8]
So try not to used it and use constructor injection instead.
Avoid Property injection
I just wanted to point this out specially.
Steve Smith (Ardalis) has a good article on the three basic approaches to dependency injection and the problem with Property Dependencies.
...if you have a choice, you should generally avoid property injection in favor of the other two approaches.
Here is a good example of a property setter injection.
If you haven't signed up for his WeeklyDevTips email already I recommend you do it asap and then listen to all of his short 5-10 min pod casts on Weeklydevtips.com.
Little more on SOLID
Every software developer should be aware of the SOLID principles
-
Single Responsibility
-
Open/Closed
-
Liskov Substitution
-
Interface Segregation
-
Dependency Inversion
I recommend either SOLID Principles for C# Developers on PluralSight or a upcoming series on the Weeklydevtips.com
Final words
I hope I haven't wasted your time with this no-code blog post. It was a good thought exercise for me just like everything on this blog. But if it got you thinking great and if you have anything to add or you disagree to something don't hesitate to ping me on Twitter
Yes I know perfectly well you don't need a container. Please keep on reading :-) ↩︎
Martin Fowler "Inversion of Control Containers and the Dependency Injection pattern" ↩︎
Michael Mattsson (Feb 1996). "Object-Oriented Frameworks, A survey of methodological issues" (PDF). ↩︎
Stefano Mazzocchi (22 January 2004). "On Inversion of Control". Archived from the original on 2 February 2004. ↩︎
Wikipedia Inversion of control ↩︎ ↩︎
Ardalis "New is Glue" ↩︎
Mark Seemann "Service Locator is an Anti-Pattern" ↩︎