Let your Inversion of Control tool work for you

If you are just starting out exploring use of an Inversion of Control tool (IoC), its very easy to go down the wrong path, and make things harder for yourself. Today I had a conversation with a bright developer who was feeling the pain because doing it all wrong. And just a month or so ago, I had the same conversation with another bright developer who was also doing it the same, wrong, way.

The problem may be that people misinterpret the intent of an IoC tool. It is seen simply as a configuration tool – a way to swap out classes using some magical XML or a DSL. The thought is that as long as your code gets all of its dependencies out of the container, you can change the behavior just by configuring the container.

And then you end up with code that looks like this:

public class OrderService : IOrderService
{
    private IRepository _repository;
    private ISystemClock _systemClock;

    public OrderService()
    {
        _repository = Container.Resolve<IRepository>();
        _systemClock = Container.Resolve<ISystemClock>();
    }
}

public class OrderController
{
    private IOrderService _orderService;

    public OrderController()
    {
        _orderService = Container.Resolve<IOrderService>();
    }
}

The OrderService needs an IRepository and an ISystemClock, so you pull them out of the container in the constructor. The OrderController needs an IOrderService, so you pull it out of the container in the constructor. You can now swap out actual implementations using some external configuration.

Except now you’ve got this annoying dependency on the magical Container class. And maybe the Container has a dependency on an external XML file.

And you discover that when you try to unit test your OrderService, you need to make sure you have a Container available, and that it has been configured to serve up whichever instances you want to use during testing.

Your simple, plain-old CLR object (POCO) now has this deadweight Container dependency dragging it down. The Container requires extra care and feeding, in the form of configuration, and now it has infected your entire codebase.

Hopefully, at this point you are feeling enough pain that you go seeking some advice, and hopefully you find out about auto-wiring.

Any IoC tool worth using will support auto-wiring dependencies for objects retrieved from the container. This means that the tool will build up all of the necessary objects needed to satisfy a request. This allows you to rewrite the above code as:

public class OrderService : IOrderService
{
    private readonly IRepository _repository;
    private readonly ISystemClock _systemClock;

    public OrderService(IRepository repository, ISystemClock systemClock)
    {
        _repository = repository;
        _systemClock = systemClock;
    }
}

public class OrderController
{
    private readonly IOrderService _orderService;

    public OrderController(IOrderService orderService)
    {
        _orderService = orderService;
    }
}

But where did the Container go? Exactly. The majority of your code should never have to deal with the container directly. Ideally, you make a single call to the container which builds up an object graph that implements your program. For a console application, you might make a call to the container once in your static Main method. For an MVC web application, you might make a call to the container at the beginning of each request to retrieve the appropriate Controller. The rest of your code is blissfully ignorant of the container. When something asks the container for an OrderController, the container will detect the dependency on the IOrderService. So it goes to build an OrderService, and detects the dependencies on the IRepository and ISystemClock. So it builds up those instances, and any dependencies they may have, and so on.

By the way, my colleague Jeremy Miller wrote this same post just a few months ago. But he assured me it was worth re-writing, because there are new people jumping on all the time, and they’re not likely to go back reading old blog posts. If you find yourself with the problem I describe above, go get the full details by reading his post about auto-wiring in StructureMap.

One thing that I’ll add is that I’ve heard a lot of talk lately that “container” is really a misnomer for what an IoC tool does, and that it should be more appropriately referred to as a “composer”. I think this argument has merit, and wonder if the name may be contributing to people going down the wrong path described above. A “container” sounds like something that stores a bunch of stuff for you, and it is your job to get stuff out of it, hence the explicit calls to the Container littered throughout your code. A “composer” sounds like something that takes little pieces of functionality in your application and puts them together into a usable whole. The bad code example above reflects “container” thinking. The better code example reflects “composer” thinking.

Related Articles:

This entry was posted in composition, structuremap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.agilification.com Jeff Doolittle

    Maybe we should call it the “magic-invisible-object-factory-that-you-should-not-call-directly”?

  • http://devordinaire.wordpress.com/ Afif

    Re:When something_asks_the_container for an OrderController…

    Going by your words above there still are some classes in our application that are coupled to the Container (or service locater). The way I understand this., every thing up to our services/controllers can be auto wired by the Container. But then all the clients (as in code/classes) using our controllers and services need to be coupled to the container to request these service and controller instances.
    Is my understanding right? Which would mean all our tests for the clients using these services and controllers would need to manage the container dependency. Is this correct? Or is there a way to work around this dependency too.
    Can you be a bit more specific in highlighting what are the classes you see that would be coupled to the container (or service locater).. what roles or responsibilities would they have?

  • Mike

    Good post, this is probably the most common mistake when starting to use an IoC container.