In a reaction to Uncle Bob's recent post on Dependency Injection Inversion, Colin Decker writes that he doesn't consider the use of the single Guice @Inject annotation particularly problematic. As I read it, the central argument is that

annotations are not code. By themselves, they do nothing.

I'll have to take that at face value, but if we translate this reasoning to .NET it certainly holds true. Attributes don't do anything by themselves.

I'm not aware of any DI Container for .NET that requires us to sprinkle attributes all over our code to work (I don't consider MEF a DI Container), but for the sake of argument, let's assume that such a container exists (let's call it Needle). Would it be so bad if we had to liberally apply the Needle [Inject] attribute in large parts of our code bases?

Colin suggests no. As usual, my position is that it depends, but in most cases I would consider it bad.

If Needle is implemented like most libraries, InjectAttribute is just one of many types that make up the entire API. Other types would include NeedleContainer and its associated classes.

Java annotations may work differently, but in .NET we need to reference a library to apply one of its attributes. To apply the [Inject] attribute, we would have to reference Needle, and herein lies the problem.

Once Needle is referenced, it becomes much easier for a junior developer to accidentally start directly using other parts of the Needle API. Particularly he or she may start using Needle as a Service Locator. When that happens, Needle is no longer a passive participant of the code, but a very active one, and it becomes much harder to separate the code from the Container.

To paraphrase Uncle Bob: I don't want to write a Needle application.

We can't even protect ourselves from accidental usage by writing a convention-based unit test that fails if Needle is referenced by our code, because it must be referenced for the [Inject] attribute to be applied.

The point is that the attribute drags in a reference to the entire container, which in my opinion is a bad thing.

So when would it be less problematic?

If Needle was implemented in such a way that InjectAttribute was defined in an assembly that only contains that one type, and the rest of Needle was implemented in a different assembly, the attribute wouldn't drag the rest of the container along.

Whether this whole analysis makes sense at all in Java, and whether Guice is implemented like that, I can't say, but in most cases I would consider even a single attribute to be unacceptable pollution of my code base.


Comments

In addition to its own annotations, Guice supports the atinject API. This minimal 6-class package contains only the stuff you need to import in your application code and nothing you don't. These are standard annotations supported by Guice and other Java dependency injection frameworks.
http://code.google.com/p/atinject/
http://atinject.googlecode.com/svn/tags/1/javadoc/javax/inject/package-summary.html
2010-01-28 03:08 UTC
Ninject does it's injection magic using an [Inject] attribute. I agree with you that sprinkling your code base with those attributes is problematic. Not only because of the direct dependency, but this switching IoC frameworks becomes much harder. The Common Service Locator project defines an interface for IoC implementations. This allows you to swap implementations. However, when your code is polluted with those attribute declarations, switching isn't easy anymore.
2010-02-04 15:09 UTC
I'm no expert in Ninject, but last time I checked, the [Inject] attribute was optional.
2010-02-04 15:41 UTC
Sorry to bother, but I'd like to know your opinion about TypeScript DIC containers. Since TS transpiles code into JS, no type information is available at runtime. Therefore, DICs need developers to decorate their classes with the container's special decorators, which is obviously different among various containers. However, there is no other choice for containers. As a suggestion, TS could define a built-in decorator that unifies DIC usages. I've created a suggestion on GitHub (See it here). I'd love to know your opinion on this issue and on my suggestion. Is there a better way?
2018-09-03 5:48 UTC

babakks, thank you for writing. While I'm aware of TypeScript and the overall design philosphy behind it, I've never written any TypeScript code, so I'm not really the right person to ask. As a general observation, though, I recommend Pure DI. Unless you have some rare and exotic requirements, a DI Container is almost never the best choice. DI Containers tend to create more problems than they solve.

In TypeScript, can't you compose object graphs by simply writing the necessary code? That's what I do in C#, at least...

2018-09-04 6:01 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or somewhere else with a permalink. Ping me with the link, and I may respond.

Published

Wednesday, 27 January 2010 19:36:34 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!
Published: Wednesday, 27 January 2010 19:36:34 UTC