Friday, September 25, 2009

IUnityContainer and the Rabbit Hole

I'm working on an exciting project using Silverlight and the PRISM framework/Composite Application Library. It is perfect for our use as a rich, interactive line of business application that has a lot of features. We want to be able to quickly and easily extend areas of functionality (which the dependency injection and region management features of the framework provide very nicely) and have concerns about performance and size of the plugin downloads (which the load-on-demand for modules satisfies quite well).

One thing I noticed, however, was that in some of my layers of abstractions I was creating distractions. Consider something like this:

public class MyModule
{

   private IService _myService;
   private IEntityBroker _myEntityBroker;

   public MyModule(IUnityContainer container) 
   {
      _myService = container.Resolve();
      _myEntityBroker = container.Resolve(); 
   }
   ...
}

Can you see what's wrong with this right away? Does it leave you with a sinking feeling that we're not in Kansas anymore?

Fundamentally, the problem is that injecting the container was easy, and then it makes sense to resolve my references, but now I'm violating several principles of sound design. Primarily, why should my module even know or care that there is a dependency injection framework? That is the whole point of having a bootstrapper ... someone "up there" can see the land and wire everything in. Those of us "down here" just need to focus on what we do and the minimal tools we need to do it with.

In other words, what I really need in my module is a service and an entity broker. Forget about the container.

So now I simply removed the references to the unity framework from my module. I refactored the constructor to look like this instead:

...
public MyModule(IService service, IEntityBroker broker)
{
   _myService = service;
   _myEntityBroker = broker;
}

There, isn't that nicer? Now I don't have to have an inversion of control framework. I can just as easily send in a concrete instance, use a factory, or whatever else I want. If I do happen to use a framework, it will happily resolve the interfaces for me when I ask for an instance because it recognizes the signature of the constructor.

Unity is a great tool, but just be careful how far down the rabbit hole you decide to shove it. A great design will deal with all of the interfaces and components everything needs, and chose how to inject the concrete implementation later in the game. Never dirty your classes with knowledge of how they are being managed.

Jeremy Likness