Today a conversation sparked off on Twitter, started by Jimmy Bogard and Matt Hinze, and then carried on by myself and Glenn Block. The basic starting point was what the difference was between using an IoC container like Windsor or StructureMap and using MEF (the Managed Extensibility Framework)
I started off by answering a question from Jimmy, he wanted the one paragraph sales pitch for MEF that didn’t include technical terminology … I guess he was asking why MEF is a better option than one of the IoC containers we all love and hopefully all use religiously.
My key answers were:
MEF allows you to write your application as a series of much simpler mini applications, and have those brought together to create a much great whole
IoC container = service level components, MEF = Autonomous Components. A MEF "part" will probably use an IoC container
This sparked some comments from Glenn where he wanted to clarify that sometimes an IoC container is the right choice, sometimes MEF is, and sometimes both are. Luckily we are both pragmatic, so not much to disagree with there. He pointed to two of his blogs on the subject, I recommend reading them highly, they will do a much better job than I could at explaining the detail of the decision points, Should I use MEF for my general IoC needs? and Should I use MEF with an IoC container?
What’s Wrong With IoC Containers?
What an IoC container is very good at is low level control of your code, your dependency graphs, your lifestyle management, and gives you great low level ways to deal with facilities, factories, decorators and AOP. In just about any code base that goes past spike stage, I use an IoC container of some sort, it is just a fools errand to try and write and application without one these days. The keyword “new” is in my code smells book.
However, what an IoC container is pretty poor at is enforcing boundaries. Sure you could use an IoC container to write much larger applications, but as Glenn rightly pointed out, the central configuration becomes a headache. In fact, the central registration can rapidly become the equivalent of using global variables, you never really know what is using what as everything has access to everything else.
Most of the containers give you the capability to have child containers to try and deal with this situation, and while they do limit the global access issue, they are pretty hard to manage in their own right, and you can without some proper thought end up with a spaghetti mess of containers replacing your spaghetti mess of components.
An Architectural Solution To The Problem
To me, MEF is an architectural solution, while an IoC container is a code level solution. They both have their places in an application, but what MEF is exceptionally good at is creating process boundaries.
One of the core underlying principles of good use of an IoC container is that you only ever reference a container at a process boundary – in most applications that means it is probably referenced in your bootstrapping code inside your web application (maybe Global.ascx), or inside an HttpModule around your web services, but from that point on, your code should never reference the container again – the magic of an IoC container comes from relinquishing all object construction and dependency graph resolution to it.
But this means in a larger application, you may end up with massive containers with hundreds of registered components, and in reality most operations will only use a small handful at a time.
In most larger systems you would naturally have parts of the system you want to devolve into discrete components, or Autonomous Components. Doing this with an IoC container starts to lead you down an architectural design geared around the limitations of the IoC container, and not necessarily driven by good architectural principles.
What MEF allows you to do is to break the system apart easily, or as Glenn referred to it, MEF allows you to easily create composite applications. These composite parts can operate as Autonomous Components, in almost total isolation from the core application, and therefore they provide a natural boundary without having to use things like web of WCF service layers just for that purpose. Oddly the MEF terminology that Jimmy wanted to avoid in his original question was “part” and yet it fits naturally in this context.
As I started off by saying, I would almost always end up using an IoC container in any application I was to write, even a fairly small scale one. If we look at these MEF parts as now being Autonomous Components, and therefore operating as mini applications, it now becomes apparent that they will themselves need a way to create service components and dependency graphs, and while MEF could in theory do a lot of that, it’s just not the best fit for the job.
So it’s pretty certain that inside your MEF part you will be using yet another IoC container for object resolution, but now you don’t have a massive central registry, but one specifically geared to the MEF part in question.
And this pattern can recurse if needed, each time providing a clean boundary within your application.
A Real World Example
The last “large scale” system I worked on where I had the opportunity to put some of these ideas into practice was an insurance portal. This portal was responsible for providing insurance quotations, but across a massively diverse and inconsistent set of products.
The solution we came to in the end was a combination of all of the above principles – we had a web application that held a Castle Windsor container in Global.ascx, that container was responsible for instantiating everything from controllers backwards, and all of the service components they used.
But some of those controllers needed to call our product plugins, and in this case we actually used Castle Windsor to use MEF to instantiate the plugins (MEF parts). Within each product plugin we had another set of bootstrapping code that had it’s own instance of a Castle Windsor container, and it’s own registry specific to that plugin.
The plugins were actually used by a number of points in the application, some in process, and some out of process, either on other servers or just behind service or service bus boundaries – what MEF allowed us to do was create an independently deployable package that was self contained and self sufficient, without the need for managing masses of registration information – trying to use an IoC container for this would have been a mini-nightmare, but with MEF it was almost a pleasure.
12-18-2009 6:50 AM