I don't like constructor based dependency injection.
I believe that it increases code complexity and decreases maintainability, and I'd like to know if there are any viable alternatives.
I'm not talking about the concept of separating implementation from interface, and having a way of dynamically resolving (recursively) a set of a objects from an interface. I completely support that. However, the traditional constructor based way of doing this seems to have a few issues.
1) All tests depend on the constructors.
After using DI extensively in an MVC 3 C# project over the last year, I find our code full of things like this:
public interface IMyClass {
...
}
public class MyClass : IMyClass {
public MyClass(ILogService log, IDataService data, IBlahService blah) {
_log = log;
_blah = blah;
_data = data;
}
...
}
Problem: If I need another service in my implementation I have to modify the constructor; and that means that all of the unit tests for this class break.
Even tests which have nothing to do with the new functionality require at least refactoring to add additional parameters and injecting a mock in for that argument.
This seems like a small issue, and automated tools like resharper help, but its certainly annoying when a simple change like this causes 100+ tests to break. Practically speaking I've seen people doing dumb things to avoid changing the constructor rather than bite the bullet and fix all the tests when this happens.
2) Service instances get passed around unnecessarily, increasing code complexity.
public class MyWorker {
public MyWorker(int x, IMyClass service, ILogService logs) {
...
}
}
Creating an instance of this class if only possible if I am inside a context where the given services are available and have automatically been resolved (eg. controller) or, unhappily, by passing the service instance down multiple chains of helper classes.
I see code like this all the time:
public class BlahHelper {
// Keep so we can create objects later
var _service = null;
public BlahHelper(IMyClass service) {
_service = service;
}
public void DoSomething() {
var worker = new SpecialPurposeWorker("flag", 100, service);
var status = worker.DoSomethingElse();
...
}
}
In case the example is not clear, what I'm talking about is passing resolved DI interface instances down through multiple layers from no reason other than at the bottom layer they are needed to inject into something.
If a class does not depend on a service, it should be have a dependency on that service. This idea that there is a 'transient' dependency where a class doesn't use a service but simply passes it on is, in my opinion, nonsense.
However, I don't know of a better solution.
Is there anything that provides the benefits of DI without these problems?
I've contemplated using the DI framework inside the constructors instead as this resolves a couple of the problems:
public MyClass() {
_log = Register.Get().Resolve<ILogService>();
_blah = Register.Get().Resolve<IBlahService>();
_data = Register.Get().Resolve<IDataService>();
}
Is there any downside to doing this?
It means that the unit tests must have 'prior knowledge' of the class to bind mocks for the correct types during test init, but I can't see any other downsides.
NB. My examples are in c#, but I've stumbled into the same issues in other languages too, and especially languages with less mature tooling support these are major headaches.