4

Problem

I have some problems to understand when and where exactly in my code I should use dependency injectors like Ninject.

Code

Let's say for example we have the following code:

//WITHOUT NINJECT:     
IMailSender mailSender = new MockMailSender();

//WITH NINJECT:
IMailSender mailSender = kernel.Get<IMailSender>();

This one is not a dependency injection so does it make sense to use Ninject in this scenario?

Another example shows how my code gets really messed up by using a dependency injector:

 public void CalculateRevenueRecognitions(IContract contract)
    {
        //WITH NINJECT
        var kernel = new StandardKernel(new DefaultModule());
        var arguments = new List<IParameter>
        {
            new ConstructorArgument("amount",contract.Revenue),
            new ConstructorArgument("date", contract.WhenSigned)
        };
        contract.AddRevenueRecognition(kernel.Get<IRevenueRecognition>(arguments.ToArray()));

        //WITHOUT NINJECT:
        contract.AddRevenueRecognition(new RevenueRecognition(contract.Revenue, contract.WhenSigned))));
    }

Question

When should I use a dependency injector?

  1. on constructor injections, parameter injection, etc.
  2. on object creation (do dependency injectors replace classical object creation with new?)
  3. are the others?

When shouldn't I use a dependency injectors?

MUG4N
  • 19,377
  • 11
  • 56
  • 83
  • After being brought on to a project using Ninject and gaining some basic familiarity with it, testing has become much easier for me. It was pretty difficult to get started with use cases and your example code should not be using it. I think of it more as you have a query class that you want to use that depends on database class that depends on a settings class and so on. You define those bindings in a ninject module and then request a query object and you get the other dependent classes injected for you. – jones6 Aug 23 '13 at 21:08
  • Its absolutely applicable to this code, as I've mentioned below, its configured in the wrong place. The majority of dependencies can be resolved when the application starts. – Mark Walsh Aug 23 '13 at 21:56
  • Using kernel.Get<> in business object methods seems off to me. I am still new to ninject so I guess I am wrong. I have only ever needed to use constructor injection so far. – jones6 Aug 23 '13 at 22:09
  • I don't get it. Everybody on the internet is writing about IoC-Frameworks today. Shouldn't this be an easy question to answer? Are there any rules when to use it and when you rather shouldn't use it. I am kind of lost... – MUG4N Aug 24 '13 at 01:24
  • You can use it in nearly every scenario. I've even wrapped 3rd party libraries in interfaces, bound and injected them. The links I posted in my answer tried to cover every possible application type. – Mark Walsh Aug 24 '13 at 12:37
  • 3
    I only add a tool to my tool-set when I feel the need for it, or maybe when my boss forces me :-). IMHO, if you don't really know what good it could give, you shouldn't use it. – Simon Mourier Aug 26 '13 at 09:54

3 Answers3

7

The basic premise is to not rely on concrete classes (like you said newing concrete classes) and to inject implementations (via interfaces). It depends on the specific task you're performing and under what conditions (Windows Service, WCF service, Asp.Net), but in most instances you have an interface with all the methods you wish to expose publicly, like so

public interface IBar {
    void DoStuff();
}

Then you then bind these to a specific class using Ninject i.e.

 Bind<IBar>().To<BarClass>();

So at startup Ninject goes and gets the configured implementation. The plus side to this is your implementation is configured, so it's really easy to swap to another implementation as long as it's implementing the interface. So if you had another class you wanted to now use instead of BarClass, you could just rebind to it i.e.

Bind<IBar>().To<NewBarClass>();

So wherever you need to use this NewBarClass, you'd pass it in like this

public class UserOfNewBarClass {

public UserOfNewBarClass(IBar newBarClass) {
}
   // Use the IBar interface
}

Also, you can mock out the interfaces when testing which means you can isolate single concrete classes and test them in complete isolation. You can do more complex things, which you can learn later like binding based off property values and conditional binding on what you're injecting into.

For entry points consult these

WCF - http://www.aaronstannard.com/post/2011/08/16/dependency-injection-ninject-wcf-service.aspx

MVC - http://www.shahnawazk.com/2010/12/dependency-injection-in-aspnet-mvc-3.html

Windows Service - Using Ninject with a Windows Service

It's quite hard to understand at first but the Container (in this case Ninject) figures out what implementation to inject based off the binding you specify . The end goal is to inject everything your class needs in order to perform it's methods so you can test it in isolation (it also helps keep the class clean and uncluttered). The preferred way is injection via constructor as the class will have all of its dependencies when it's created. Property injection is of course doable but as with properties, you can't really guarantee it to have been set.

Community
  • 1
  • 1
Mark Walsh
  • 3,241
  • 1
  • 24
  • 46
  • I am all with you here and so far I understand the concept. But this does only work if your BarClass is really a new object like (var bar = new BarClass()) but what is if the object has been created long before and is then injected into a class. Does it make sense to use Ninject for the consuming class then? – MUG4N Aug 23 '13 at 20:27
  • 1
    I've updated since you've commented but I'll try to expand. Ninject should really have everything resolved before your application starts. What is the context you're trying to use it in, i.e. what type of application? Perhaps I can be a bit more specific. – Mark Walsh Aug 23 '13 at 20:32
  • Sorry Mark but you are just repeating the user guide from Ninject. My question is not how to use Ninject but when to use and when not to use it. I really appreciate your effort, though. – MUG4N Aug 23 '13 at 20:37
  • I wasn't repeating it, the Ninject guide uses the notion of weapons to try and describe it, these are all my words. I'd personally inject a factory into the constructor of whatever needs to new up a new object. This wouldn't be a concrete instance but would be an implementation I've bound to. The concrete implementation would new up the object i.e. new SomeConcreteClass();. My comments also describe when, why and how to use dependency injection. I can't think of a single instance where I've not been able to use dependency injection. – Mark Walsh Aug 23 '13 at 20:39
  • I think the biggest problem you've got is that you're putting your bindings in your actual implementations of objects. All of the configuration and bindings should be done before the application starts so you can let Ninject resolve these for you. Only in fringe cases should you have to go and get the concrete implementation from the kernel yourself. The Ninject tutorial doesn't really mention that this is quite an anti-pattern as you're tying yourself to your DI container. If it were a timeline: DI configuration > Application Start > Classes are instantiated with bound implementations. – Mark Walsh Aug 23 '13 at 20:46
  • Thank you for your last comment that is the stuff I am looking for – MUG4N Aug 24 '13 at 01:18
  • 1
    Then you've got the idea. You're configuring stuff in your business logic when this should all be bound way before your code even reaches this point. – Mark Walsh Aug 24 '13 at 09:34
3

I have extensively used dependency injection frameworks in the past. Hell I even wrote one (which performs registration and resolution lightyears faster than Ninject, although I was happy to borrow it's fun unit test model of Ninjas, KiteShields Shuriken, etc.)

These days I hardly ever use a dependency injection framework. Because if I've learned one thing from the use of (heavy) frameworks it is the following:

you have a technology problem. you search and experiment with frameworks that are going to solve the problem for you. you select one and use it everywhere.

now you have 2 problems. your dependency injection framework just caused you to take on a big dependency for your entire codebase.

There is a great SkillsMatter presentation by Greg Young (http://skillsmatter.com/podcast/agile-testing/simple-is-better) on frameworks with statements and opinions that may seem a bit on the extreme side, but quite a few of them, I have learned the hard way, I do agree with.

Alex
  • 13,024
  • 33
  • 62
  • Thank you for sharing your opinion against IoC-Frameworks I will take a look at your reference – MUG4N Aug 24 '13 at 01:24
  • 2
    I think most would argue that having one dependency on something that's relatively easy to swap out is better than potentially thousands of concrete dependencies in your code. This is quite a contradictory opinion and not one that is shared by a great number of developers. If your codebase is passing references to the container then you're best rethinking your architecture. – Mark Walsh Aug 24 '13 at 14:54
  • @MarkWalsh I did not argue that it is unimportant to manage your dependencies. I was expressing the opinion that if you design well, you do not need a framework to do that for you, because you will inevitably end up with dependencies to it, and the "magic" it does will cost you. Have you actually had a look at the presentation I linked to, that shows you one way of achieving that? Also I can't be bothered with "what most argue". I find it works better if I think about the cleanest way to solve a problem instead of looking for a "what most argue" recipe. – Alex Aug 24 '13 at 15:06
  • 1
    Your answer makes it sound like it's hard to decouple your chosen framework if you want to change it. It's not, not if you design your architecture properly. None of my application code is polluted by my Ninject code, everything is resolved at runtime. If I wanted to use Spring, the binding modules are the only place I'd have to change. There needs to be a line in the sand, I find purists like Greg seem to go to the Nth degree just to prove they're not dependant on X. – Mark Walsh Aug 24 '13 at 15:24
  • @MarkWalsh my comments relate to the fact that generally one will (either consciously or not) make compromises/allowances in one's design based upon what the framework can/cannot do for you. It hides where the dependencies actually are and when they are needed. Case in point: the recommended constructor dependency injection: inject all of the dependencies an instance might need during its lifecycle, even when some are only required for specific method calls. This tends to lead to brittle designs with constructors taking a huge list of "Services" that only a few of their methods depend on. – Alex Aug 24 '13 at 16:23
  • 1
    Yes, if your classes are doing too much that would become a problem. Then again, your classes shouldn't really be doing that much as per the single responsibility principle. – Mark Walsh Aug 24 '13 at 16:58
  • I agree completely with @Mark Walsh. It's totally possible to abstract away the container and it's services behind yet another interface, making it simple to switch out your container for something else. The problem comes when you depend on the "fancy" extras beyond the simple IoC/DI concepts, like Ninject's contexts. – Steve Aug 29 '13 at 18:59
  • @Steve ... which many developers end up doing because often the reason to select one framework instead of a different one are the "fancy extras". Problems are then often compounded by the "if you got a hammer ..." syndrome. I rarely see projects performed by teams of a size of more than a few developers where this kind of "abuse" does not take place. In my experience, most problems can be solved in a cleaner way without using an IoC framework. It does require you to create truly independent components/subsytems with very limited wiring that is convention instead of configuration based. – Alex Aug 29 '13 at 21:02
  • Agree with @MarkWalsh. IMO most common IOC containers do a great job. Why re-invent the wheel and increase your development and testing effort? – nixon Aug 30 '13 at 06:13
1

The thing is, I can't now imagine a scenario where I would just use dependency injection on its own. I'm more familiar with situations where you use Inversion of Control (IoC container which uses DI). In such cases, your code is actually very clean, because you don't have to call the injector for instances. The IoC container will do it for you.

So I would consider, if it is not better to use IoC/DI instead of using just DI. In the end, many successful frameworks use this combination, non of them use just one of the pair (assuming that they use DI at all, because there is actually another pattern which is possible to combine with IoC).

Ondrej Janacek
  • 12,486
  • 14
  • 59
  • 93