Rejecting Dependency Injection Inversion

Uncle Bob has a post about why you should limit your use of IoC containers. I read that post with something very close to trepidation, because the first example that I saw told me a lot about the underlying assumptions made when this post was written.

Just to give you an idea about how many problems there are with this example when you want to talk about IoC in general, I made a small (albeit incomplete) list:

  • The example is a class that has two dependencies, who themselves has no dependencies.
  • There is manual mapping between services and their implementations.
  • All services share the same life span.
  • The container is used using the Service Locator pattern.

Now, moving to the concrete parts of the post, I mostly agree that this is an anti pattern, but not because of the code is using IoC. The code is actually misusing it quite badly, and trying to draw conclusions about the practice of IoC from that sample (or similar to that) is like saying that we should abolish SQL because of an example using string concatenation has security issues.

I am not really sure about the practices of IoC usage in the Java side, but on the .NET world, that sort of code is frowned upon for at least 4 or 5 years. The .Net IoC community has been very loud about how you should use an IoC. We have been saying for a long time that the appropriate place to get instances from the IoC is deep in the bowels of the application infrastructure. A good example of that is using ASP.Net MVC Controller Factory, that is the only place in the application that will make use of the container directly.

Now, that takes care of the direct dependency on the container, let us talk about a dependency graph that has more than a single level to it. Here is something that is still fairly simplistic:

 

image

I colored all the things that share the same instance and those that do not. Trying to keep track of those manually, or through factories, would be a pure nightmare. Just try to imagine just how much code you are going to need to do that.

Furthermore, what about when we have different life spans for different components (logger is singleton, database is per request, tracking service is per session, etc). At this point you raise the complexity of the hand rolled solution by an order of magnitude once again. Using an IoC, on the other hand, means that you just need to configure things properly.

Which leads me to the next issue, manually mapping between services and their implementation is something that we more or less stopped doing circa 2006. All containers in the .Net space supports some form of auto registration, which means that usually we don’t have to do anything to get things working.

As I said, I am not really sure what the status is on the Java world, but I have to say that while the issues that Uncle Bob pointed out in the post are real, the root cause isn’t the use of IoC, it is the example he was working with. And if this is a typical example of IoC usage in the Java world, then he should peek over the fence to see how IoC is commonly implemented in the .Net space.

Print | posted on Friday, January 22, 2010 12:00 PM

Feedback


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 12:31 PM Achim Domma

Thanks for this very interesting point of view! I usually really like Uncle Bobs writings and I'm surprised that he mixes up the limitations of concrete implementations in the java world and the limitations of an abstract concept.

What readings would you recommend to somebody to get started with DI in the .Net world? My feeling is, that there is a lot of information available, which leads you in the wrong direction as their technics are implementation/language dependent. Also there are many DI implementations in .Net and you have to get started with one. But how to choose one if you are not already an DI expert?

cheers,
Achim


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 12:47 PM Thoại Nguyễn

Hi Ayende,

Thank for your post. The case you mentioned above is exactly like my case. I'm using Unity as the IOC library. Since i don't want to make my Service implementation dirty with [Dependency] attribute from Unity, I decided to use Contructor injection. However, following this approach, the bootstrapper becomes a huge class with thousand lines of injection code for service classes. Personally, I think It's really the main drawback when using IOC


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 1:02 PM Ayende Rahien

Thoai,
They you have a problem in the way you are using IoC, period.
Most commonly, I have about 10 lines to setup IoC for an entire project


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 1:12 PM Bunter

Thoại, nobody orders you to put all the IoC setup into single class... Maybe the main drawback sits between the table and the chair?


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 1:42 PM Stephen Oakman

Thoai,

I've found that Unity is more the limitation in this sense. It doesn't go as far as I would like (in my opinion) and almost refuse to call it an IoC Container. Using something like windsor enables more of a mindset change as it supports not only auto registration (which is why you are experiencing the pain you are having) but also the lifestyle management and facilities open up so many more possibilities.

When unity is the only exposure to IoC I've just not seen them 'get' the benefits of IoC and ultimately it ends up being a mess. Of course, ymmv but I would strongly suggest giving something like windsor a go and see what possibilities it opens up.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 1:48 PM Petar Repac

@ Achim
Look at "Dependency Injection in .NET"
http://www.manning.com/seemann/


Gravatar

# Well, how do I use it right? 1/22/2010 1:54 PM Greg

I have to confess, I'm stuck in the "confused by IOC" camp. I keep hearing IOC veterans talking about how easy it is, how if it's hard that's because you're doing it wrong -- but then they never go on to demonstrate, with substantial code examples, how to do it right. Where are the good implementations, that use IOC the right way, in nontrivial real-world apps? A pointer to two or three of those would be worth a hundred blog posts saying "Uncle Bob is wrong".


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 2:13 PM JeroenH

I agree with Greg. I'm looking for some guidance as well in this regard. Ayende, sharing the 10 lines of setup for a typical project along with some explanation would be a nice topic for future post.

I added a "new post" suggestion for this topic:
nhprof.uservoice.com/.../455080-real-world-ioc-...


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 3:03 PM Nicko

Thoai/Greg,

I use structuremap to autowire my dependencies and can usually get away with 10 to 20 lines of code.

structuremap.sourceforge.net/...ningAssemblies.htm


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 3:22 PM Jonty

We only use constructor injection and use StructureMap to auto wire it up. All we need is:

Scan(x => {
x.Assembly("MyAssembly1");
x.Assembly("MyAssembly2");
x.WithDefaultConventions();
});

DefaultConventions ties up the interface with its concrete class, eg ICustomerService to CustomerService. Then we only need to be specific when the lifecycle of the instance is different.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 3:30 PM Harry Steinhilber

@Greg
ayende.com/.../...o-registration-is-mandatory.aspx

That is from almost 2 years ago on this very blog. The Binsor registration can also be translated into C# with almost no effort. The point being, there are 11 lines of code there and everything is wired up. If you use conventions instead of manually wiring everthing, it can be done very simply and only once.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:06 PM Eddie

Uncle Bob tried using the Straw Man Argument:

http://en.wikipedia.org/wiki/Straw_man


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:08 PM Gavin

Ayende, you mention that we stopped manually mapping between services and their implementation in 2006. Could you please elaborate on what you mean by this. Are you actually talking about manually writing xml config file for a given container ie. Castle Windsor? If so, how else would you do it? I find attributes a little invasive but would use them if I had to. I also struggle to see how you would request instances from a given container without the use of a factory vis a vis auto registration.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:10 PM Ayende Rahien

Gavin,
Take a look here: http://ayende.com/Blog/category/451.aspx
That is just one example of how to implement convention over configuration for a container. You setup the parameters, and then you are pretty much done with it


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:11 PM Suedeuno

Jonty, you don't even need that as StructureMap will scan all assemblies with a single line on of code.

x.LookForRegistries();


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:15 PM Frank Quednau

Greg,
another example from StructureMap:
Scan(s =>
{
s.AssemblyContainingType();
s.AddAllTypesOf().NameBy(t =>
t.Name.Replace("Action", "").ToLowerInvariant());
});
means, register all types implementing IAction with a name that is derived from the type's name with a certain convention.

A good IoC may also help you in separating your conventions from your wiring code:
Scan(s=>
{
s.AssemblyContainingType();
s.With();
});
HttpHandlerRegistrar is a convention for finding IHttpHandler implementations and name it with a relative URL provided via attribute. Such conventions can be reused, which can dramatically reduce your wiring code.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:18 PM Frank Quednau

And I forgot to escape the < and >, damn :(

It says e.g. "s.AddAllTypesOf<IAction>() "
and "s.With<HttpHandlerRegistrar>"
sorry!


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:26 PM Gavin

Thanks for your reply, I am so totally going to be using the castle batch registration facility from now on!


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:35 PM Jonathan Allen

I write applications like that all the time, and I don't see the complexity you are speaking of. I just create the logger and settings objects at the top level and pass them down to whatever components need it. It can be tedious at times to thread everything through, but it isn't the slightest bit complex.

Dependency Injection only makes sense when you truly don't know what the concrete dependencies are until runtime. For example, generating menus and the pages/forms they link to at run time. For stuff that is never, ever going to change like your logging component or how you access databases, there is just no point to it.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:48 PM Bradley Landis

Jonathon,

I have to disagree. Probably the single biggest benefit to DI is in testability. When testing, being able to replace your logging component or database access object is key.

Thanks,

Bradley


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 4:59 PM firefly

Bradly is right...

Regarding the registration, not sure about all the other container but both Windsor and StructureMap will allow you to register your entire application with a few lines of codes with a fluent interface :)


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 5:41 PM Aaron

I do find some use from Uncle Bob's post, but the one thing that was left out was that this pattern should be used only for the Composition Roots in the application. In MVC, there needs to be only one, the Controller. This is a consequence (and a testament) to MVC's design. When we use the Controller factory for containing the use of the IoC container, we are essentially doing what Uncle Bob is talking about, hiding the use of any particular IoC container within a factory, so that the container code is not spread all over the application. We could use the container from within each Controller, but fortunately there is a better way, thanks to MVC's design. In some situations, the one and only one Composition Root may be harder to find. I'm sure it's possible with the "right" design of the application, but at the very least, keeping the IoC code contained within a factory (even if there is more than one Composition Root) is better than calling the container directly. When/If a breakthrough emerges and we find a way to refactor towards a single Composition Root for the application, we can do so more easily. I agree that the example may be spreading some bad behavior for those new to using IoC, but only because there was no mention that this factory pattern should be contained to the Composition Root.

In response to the book question above, I highly recommend Dependency Injection in .Net by Mark Seemann (http://manning.com/seemann/).


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 6:29 PM Jeremy Gray

@Jonathan - but why even pass such objects down all the time in all the places when you can set up an IoC convention once and only once and then have it taken care of everywhere? I haven't instantiated or passed down a dependency in close to two years now, and I was late to the IoC game, in terms of getting it into a client project that is. ;)

For the record, I also haven't instantiated a factory for dependencies or even written any IoC registration code in just as long, as the automatic registration convention I implemented takes care of that too. I just write new public interfaces that implement my IComponent interface, write new implementations, and then consume them in the ctor arguments of other component implementations. The whole thing gets wired up automatically based on the conventions I established long ago. Ya gotta love low-friction development!


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 7:06 PM Michael Valenty

@Greg I just did a presentation at my company on using Unity in ASP.NET MVC in a real-world scenario with a deep dependency graph and some AOP. You can read the overview and download the source code to see how I configure things with Unity.

http://www.agileatwork.com/where-does-it-hurt/

It demonstrates using IoC for lifetime management, composition, and AOP (logging, performance counting).


Gravatar

# re: Rejecting Dependency Injection Inversion 1/22/2010 7:35 PM Dmitry

Uncle Bob did not write that code. It comes from the tutorial on Google Guice, the IOC used in the example.

code.google.com/.../

This happens in big companies all the time. Just remember the MVC sample applications from Microsoft.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/23/2010 1:48 AM Jimmy Zimms

Stephen Oakman :

"I've found that Unity is more the limitation in this sense. It doesn't go as far as I would like (in my opinion) and almost refuse to call it an IoC Container"

Agreed and technically I'd say it actually ISN'T a container. It's a container-like facade over a factory (which incidentlly is somehting the Unity guys would agree with). For instance, a container "contains" things you put in it. If you don't put something in it you can't get it out of the container. In Unity if you don't put something in it first you still can get it out! This is really because of the architectural mistake of not actually keeping a mapping of registered types on the container but deffering everything to the underlying ObjectBuilder system.

Don't believe the above? Here's a fun expiriment: Create a UnityContainer and ask for an Object from it. Guess what? You'll get one.

This is the cause of innumerable unity configuration based bugs than I can tell you. Item not in the container? Throw and exception or return null or something - ANYTHING than make me think it's actually been set up right. [rolls eyes]


Gravatar

# re: Rejecting Dependency Injection Inversion 1/23/2010 2:55 AM Steve Py

I've learned to take what Uncle Bob says with a grain of salt. :) As Ayende points out, his argument is based on a very bad example.

For others looking to explore the benefits of IOC Containers, a good starting point is ensuring they understand the fundamental concept of Inversion of Control.

Start writing code where you are providing dependencies to instances of classes instead of "new"ing them inline, or even using Factories to construct them. This can be by passing them in a constructor, or setting up properties. The key beneffit of IOC as Bradley mentioned, is testability. Once your code is interacting with what it is provided, instead of creating instances of its dependencies, you can substitute those dependencies with Mocks and Stubs to test your code atomically. Provided you also follow good programming fundamentals such as Liskov substitution principle (LSP) it makes your code much easier to modify later on by substituting in new implementations that take advantage of different technologies, etc. (I.e. substituting a logger that logs to file with one that supports event log or DB.)

Once this "clicks", then start experimenting with IOC Containers to detect and automatically provide those dependencies. Two good IOC containers to get started with are StructureMap or Autofac.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/24/2010 2:40 PM Travis

Thoai, Spephen, and others

In regards to auto registration with Unity IoC, have a look at http://autoregistration.codeplex.com/


Gravatar

# re: Rejecting Dependency Injection Inversion 1/25/2010 3:46 AM Rogério

I agree with Jonathan (although I wouldn't "pass loggers down"): DI is often abused, leading to pointless complexity and code...

Testability shouldn't be an excuse to use DI, since how "testable" your code is depends on the mocking tool you use. In the Java world, we have free (and open source) tools that make writing unit tests for any kind of code easy.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/25/2010 6:09 AM Lincoln

Java has had a solid dependency injection framework for years with Spring, but now that has been standardized with CDI (JBoss weld is the reference imlementation, and JBoss Seam provides further extension.) I don't think that misuse is the norm, just as other have said, it's possible to misuse anything.

CDI/Weld is great because it's part of the Java EE framework as a standard, meaning one less place where configuration is required - complexity goes down.

With great power comes great responsibility.


Gravatar

# re: Rejecting Dependency Injection Inversion 1/25/2010 10:55 PM Mark Seemann

Good post, but I think that we, as the .NET community, have been pointing fingers at Uncle Bob for long enough without actually showing him how we can do better, so I went ahead and translated his example to C# and let Windsor loose on it:

blog.ploeh.dk/.../...yInjectionInversionInNET.aspx


Gravatar

# re: Rejecting Dependency Injection Inversion 1/26/2010 2:22 PM Mike

"CDI/Weld is great because it's part of the Java EE framework as a standard, meaning one less place where configuration is required - complexity goes down."

For those who do not know: CDI is JSR 299 Contexts and Dependency Injection for the JavaTM EE platform.

When are we going to get a community .NET specification thingy going? It's great the amount of frameworks for DI in .NET, but they are reinventing the wheel all of them. I think it's good to get behind a common spec.

Title  
Name  
Email
Url
Comments   
Please add 5 and 6 and type the answer here: