Why is coupling to dependencies with the new keyword considered bad?
Asked Answered
B

1

6

I've been using Dependency Injection for a while, and now I want to give a talk about IoC and DI to a group of new developers. I remember explaining it to one guy personally and he asked me:

"Why not just use:

private IMyInterface _instance = new MyImplementaion();

instead of going through all the DI trouble. "

My answer was: "Unit testing requires mocks and stubs." - but we do not write unit tests in my company so it did not convince him. I told him that concrete implementation is bad since you are tightly coupled to one implementation. Changing one component will cause change in another.

Can you give an example for such code? Can you give me more reasons why this code is bad?

It seem so obvious to me that I have trouble explaining it :-)

Brannan answered 14/12, 2014 at 8:28 Comment(2)
It actually depends and is situation basis why and when you need DI and not is what i think. But abstraction and DI is a good design principle.Sallie
Take a look at this great talk by Robert C. Martin about OO design. It talks about the Dependency Inversion Principle, which is the main driver behind Dependency Injection. Martin talks about the "Copy Program" (an example he used throughout the years) in which he explains what the problem of source code dependencies and class coupling is. We use DI to lower class coupling. Watch this talk, because this should be your main argument to your colleagues.Patsy
B
4

The problem with the following coupling

public class MyClass
{
    private IMyInterface _instance = new MyImplementation();
    ...

Means that any time MyClass is created (whether directly, or by an IoC container) is that it will always immediately create a concrete MyImplementation and bind its dependency _instance to this concrete implementation. In turn, it is likely that MyImplementation has other dependencies, which are also coupled this way.

Benefits of decoupling of classes such that MyClass is only dependent on interfaces to its dependencies, and not concrete implementations of the dependencies (i.e. the D of SOLID principles) include:

  1. for Unit Testing - As you've mentioned, in order to test MyClass in isolation, with new'ed dependencies, you would need to resort to nasty things like Moles / Fakes in order to mock out the the hard wired MyImplementation dependency.

  2. for Substitution - by coupling only to an interface, you can now swap out different concrete implementations of IMyInterface (e.g. via configuring your IoC bootstrapping) without changing any code in MyClass.

  3. for making dependencies explicit and obvious in your system, as the IMyInterface dependency may have further dependencies, which need to be resolved (and may need configuration considerations as well). If MyClass hides the IMyInterface dependency internally, it is not visible to the caller as to what the dependencies of MyClass are. Although in classic 1990's OO this was commonplace (i.e. encapsulation + composition), this can obscure the implementation as deployment of all dependencies still needs to be done. However, with coupling done on interface level (i.e. consumers of MyClass will do so only via IMyClass), the coupling-visible interface is IMyClass which will again hide the dependency on IMyInterface, since constructors are not visible on the interface).

  4. for configurable dependency lifespan control. By injecting IMyInterface, instead of newing MyImplementation, you are allowing additional configuration options with respect to the lifespan management of the MyImplementation object. When the original hardwired creation of MyImplementation was done on MyClass, it was effectively taking ownership of MyImplementation's lifespan with a 1:1 relationship between the two class instances. By leaving this to the IoC container, you can now play with other options of MyImplementation's lifespan, which might be more efficient, e.g. if MyImplementation instances are thread-safe, you may elect to share an instance across multiple instances of MyClass, for instance.

In summary, here's how I believe the refactoring should look suitable for IoC constructor dependency injection:

public class MyClass
{
    // Coupled onto the the interface. Dependency can be mocked, and substituted
    private readonly IMyInterface _instance;

    public MyClass(IMyInterface instance)
    {
       _instance = instance;
    }
    ...

The IoC container bootstrapping will define WHICH implementation of IMyInterface needs to be bound, and will also define the lifespan of the dependency, e.g. in Ninject:

 Bind<IMyInterface>()
     .To<SomeConcreteDependency>() // Which implements IMyInterface
     .InSingletonScope();
Brandon answered 14/12, 2014 at 8:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.