Bob Lee, creator of Google’s Guice project (the Dependency Injection framework for Java) has twice left comments here urging me to check out his talk introducing Guice. I resisted this because a) I don’t do Java and b) I figured I’d had enough with a later video recommended by Nate. This afternoon, I broke down and watched it and I’m glad that I did.

It turns out that the things that grated on me from the first Guice video I viewed came mainly from Kevin Bourillion—mostly unfair comparisons to alternatives and boosterism. Bob is very personable, open and seems honestly intent on communicating both how Guice works and the reasons for their design choices. He’s also very clear when discussing real-world reasons for using Guice. I found the video both informative and refreshingly free of the taint of propaganda that so permeates a lot of the explanations of dependency injection I’ve encountered so far.

For one, there are several times where Bob describes the unit testing origins and impetus of Guice. One objection I raised in my original post on Dependency Injection is that people are largely talking around the major motivation unit testing plays in the adoption of dependency injection. At one point Bob shocked me when he actually said, "If there’s any reason to use [Guice], it is unit testing." Pardon me while I swoon.

Early on, Bob gave a list of benefits (and one detraction) to implementing dependency injection by hand. I’ve taken that list and expanded it a bit because it helped clarify my thinking on dependency injection. Below is a matrix that includes Bob’s original Factory example, his original evaluation of DI by hand, Guise DI (from what I can tell, I’m open to correction on this one), and TypeMock. To understand it, recognize that some of the items involve three practical objects: A client that calls a service that needs a service implementation. The service implementation is the piece you’d mock.

  Factory Manual DI Guice TypeMock
1. Tests bypass dependency manager (i.e. a factory-like entity) close check check check
2. Explicit binding (cannot create client without providing service implementation) close check check N/A
3. Reuse client with multiple service implementations close check check close
4. Client doesn’t have service implementation dependency at compile time close check check check
5. Service doesn’t have service implementation dependency at compile time close check check close
6. No factory needed to create either service or client close close check check
7. Architecturally neutral close close close check
8. No new dependency in non-test code check check close check
9. Able to mock code-generated or external objects without wrapping close close close check

This isn’t an attempt at a complete list, but it does identify the cleft points in the different strategies for me. The key to loose coupling is there in numbers 3 and 5 which is where TypeMock doesn’t achieve the architectural grace that DI can. The advantage that TypeMock enjoys is in numbers 7, 8, and 9. Guise comes close to achieving number 7, actually, but there’s enough of a learning curve needed to grasp the intricacies of DI in Guise (that could really bite you if you failed to fully understand their implications) that I wasn’t quite willing to give it to them.

Now, how you weight those factors for your projects (and you should be weighing them on a per-project basis) will help lead you to where you might be most comfortable. You can guess how I weigh them in relation to the majority of the projects I work on.