Monday, January 25, 2010

Dependency Injection: One step back.

Ayende had some interesting feedback here from an blog from Uncle Bob about why developers shouldn't use IOC containers.

Most modern IOC containers can be configured to auto-inject dependencies via constructor injection. The benefit of using this approach is that it's essentially configure & forget. Provided that you don't mess up the configuration, the container should continue to detect and provide dependencies. There are two things that I don't really like about this though:

#1. From a test-ability perspective, you need to provide mocks or stubs for all dependencies when testing code.

#2. When things get a bit out of sync you're chasing Null Reference Exceptions, and I *loathe* NullReferenceException.

An alternative that I've been exploring is going back to using the IOC container as more of a service locator/provider via Property-based dependencies. This is kept nice and tidy using a partial class for the dependency definitions.

The benefit of this approach is that my unit tests only need to provide dependencies that are actually used for the functionality being tested. Dependencies can also be effectively "lazy-loaded" as necessary since they will be located and provided only the first time they are referenced. The second part to this is to be sure that the IOC container is covered by a facade. This keeps out the tight coupling to a single IOC provider, and allows you to be sure that test fixtures configure a stub container that throws exceptions to expose unexpected new dependencies.

I find this approach also blends into legacy code a lot easier than constructor injection. Existing legacy code can construct instances of re-factored classes as per normal. The only re-factoring you need to do is to strip out the "newing" and substitute it with the IOC provided properties.

No comments:

Post a Comment