Friday, January 22, 2010

What's the issue with @Inject?

Reading Uncle Bob's recent post about dependency injection frameworks, I noticed that quite a few people seemed to be treating the use of Guice's @Inject annotation in their application code as a reason to prefer other DI frameworks to Guice. For the most part, none of them provided any explanation for why using the annotation in application code was a problem other than "I don't like it". Even ignoring the fact that JSR-330 standardizes the only annotations and the one interface from Guice that are used in application code and will be usable with Guice 2.1, I find it difficult to understand these points of view. What's the issue people have with it?

Why it's good

@Inject is just one annotation that, in a typical concrete class, will be used on one constructor and MAYBE a couple setters. It allows dependencies to be injected without any explicit configuration of the Spring XML form while retaining safe and predictable behavior by ensuring that injections always take place using the exact constructors and methods you want to use. It saves you from ever having to specify anything using strings, making it possible to refactor and rename classes and methods without any risk of breaking your DI configuration... I think this is an extremely important point. It generally doesn't allow anything unexpected to happen.

Tied to the framework?

I feel like the knee-jerk reaction to using @Inject in classes is that by doing that, you're somehow tying yourself to Guice. As Uncle Bob put it,

I don’t want to write a Guice application. Guice is a framework, and I don’t want framework code smeared all through my application. [...] I don’t want to have @Inject attributes everywhere [...]
I understand that when he says this, Uncle Bob is arguing against using DI frameworks in general. Ignoring that argument for now and accepting that DI frameworks are worth using, the fact is that if you're using a DI framework, you are tying yourself to it. It's how your application is configured, unless you're doing all the work to create an alternate way of wiring the application together in which case... why? If you choose to switch to another DI framework or stop using a DI framework entirely (and how likely are either of these, really?) it is going to involve some work to remove the existing configuration and write the new configuration. And removing a bunch of @Inject annotations would be an absolutely trivial part of that.

Annotations are not code

I think it's important to note that annotations are not code. By themselves, they do nothing. You can use a class even without the annotations on its elements available on the classpath. When writing tests, you can completely ignore them. Guice's annotations will also never be in the body of your code, meaning you should generally be able to ignore them when reasoning about how a class behaves. One comment I read (from a Spring XML user) stated that the commenter considered annotations "just as bad" as code and likened the @Inject annotation to providing your classes with the ApplicationContext (Spring's central container interface). This is, of course, way off base. Providing programmatic access to the central container ties the code itself to the DI framework. The class can then use the framework's code directly to get access to any object it wants, anywhere in its code. Testing the class would require configuring a container and looking through the class to see what needs to be in it. The framework becomes a Service Locator framework. The @Inject annotation imposes no such thing.

In general, I think the benefits provided by Guice and the configuration safety provided by the use of @Inject far outweigh the at most minor annoyance of placing an annotation or so per injectable class. In future posts I'd like to talk more about what I like about dependency injection and Guice.