views:

88

answers:

2

Hi All,

How do you determine which classes should be constructed through an IOC container, and which ones shouldn't. I've worked on projects with both extremes and it seems like interfaces should only be used when the classs specifies a specific technoliogy like logging or data access?

Where do people draw the line between the two?

+3  A: 

I don't draw any line - the more, the merrier.

What happens is that the more you can manage to split up your API in small units, the closer you get to the Single Responsibility Principle, because everything that hides behind an interface will have a tendency to do only one thing, and do it well.

By injecting interfaces into implementation that implement new interfaces that are injected into other types, etc. you end up with a very flexible structure where you can vary implementation details at almost any level, and each collaborator is pretty simple in itself.

With a good DI Container and some sensible conventions, the DI Container will automatically take care of most of the wiring for you, so the configuration doesn't have to be extreme.

Mark Seemann
Frankly, it's hard to believe advice like this is serious. It totally contradicts the intent behind the original article on DI by Martin Fowler. Also, the implementation of a class already "hides behind an interface": the public interface of the class itself! I mean, a Separated Interface isn't needed for that. (Or did you mean "interface" in its general meaning?) In most cases, you simply don't need to "vary implementation details" through configuration - doing that by default is overdesign, and contradicts the true spirit of DI.
Rogerio
@Rogerio: The advice is serious, and I've been using this principle with great success for years. While I do respect Fowler, we don't have to take his every word as scripture. Do a web search and find out what the cutting edge .NET community thinks about Fowler's and Uncle Bob's views on DI. You may change your mind, then.
Mark Seemann
@Mark: ok, no need to take every word "as scripture", but the fundamental principle here, which is common to both DI and the "Service Locator" pattern, is to "separate configuration from use". IMO, when people use DI (or ServiceLocator) without a real need for that configuration, they are abusing it. And such abuse, just like the abuse of GoF patterns (which happens a lot), causes some serious harm in real projects, by increasing development and maintenance costs without bringing any tangible benefits. That is what concerns me when I see "radical" advice like this ("the more, the merrier").
Rogerio
@Rogerio: The more fine-grained the API, the easier it is to unit test. The easier it is to unit test, the better the quality of the unit tests. The better the quality of unit tests, the better is the maintainability of the code base. That is the real need that motivates me to say as I do. I find it to be very beneficial and not the least harmful.
Mark Seemann
Ah, but there is no direct relationship between a fine-grained API and use of DI. You can get your API as fine-grained as you can imagine without any use of DI at all. And have a full unit test suite, to the point of achieving 100% code coverage. In fact, it's even easier to do it without DI. Well, in Java at least.
Rogerio
If you don't use DI, then how do you achieve low coupling? (note that I'm not asking about the use of DI *Containers*, but of simple DI building blocks such as Constructor Injection.)
Mark Seemann
DI is not even supposed to help you achieve low coupling. It is supposed to help you separate the use of abstract interfaces from the configuration through which an implementation is chosen at runtime.If you need to avoid coupling a client class to the implementations of a given abstraction, you use a "plug-in": an abstract type defined in the same module as the client, with implementations defined in separate modules. To obtain the proper implementation instances at runtime, you can use DI or a "Service Locator".
Rogerio
Service Locator is an anti-pattern: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx I also don't agree with the rest of your statements.
Mark Seemann
Well, I value more the opinions of well known and respected book authors. Not to say I agree with them on everything, though.The problem with your article is that it describes serious abuse of Separated Interfaces and Plug-ins and then concludes that using Service Locator in such a situation would be bad. Yes, it probably would, but only because other "anti-patterns" were applied in the first place. A sane application would never need more than a few externally configurable components. DI and ServiceLocator are not intended to replace the "new" operator.
Rogerio
If you don't value my opinion, then why are you discussing this with me?
Mark Seemann
I only said I value the opinions of well known authors more. I don't think you fall in the category of "well known" yet, but I do value your opinion, just not as much :^}
Rogerio
+1  A: 

Classes to be instantiated by the DI container (assuming one is used) should be those that implement a Separated Interface, and that need to be chosen at runtime depending on the execution environment.

You may then ask: which classes should implement a Separated Interface, and which should not? There are basically two reasons to create a new separate interface:

  1. You need to break a dependency between two parts of the system (just avoid doing it simply because you can).
  2. You will have multiple independent implementations (keep in mind it's normally easy to introduce a separate interface later through refactoring, so "what-if" thinking should be avoided).

For reference, see: http://martinfowler.com/articles/injection.html#SeparatingConfigurationFromUse

Rogerio