I know how to use dependency injection but I recognize no practical advantage for it
Asked Answered
K

4

6

It is about this (Inject the dependency)

private readonly ICustomerService _customerService;
public Billing(ICustomerService customerService)
{
   _customerService = customerService;
}

versus this (Create the dependency)

private readonly ICustomerService _customerService;
public Billing()
{
   _customerService = new CustomerService();
}

The latter sample so they say is bad because... it violates DI...of course nothing is injected... but what if DI would not exist, what is so bad that the CustomerService is created manually from the Billing class? I see no practical advantage concerning exchangeability of the Service interface.

I ask for a practical example with source code may it be a unit test or showing a practical solution why it is so much more loose coupling.

Anyone keen enough to show his DI muscles and why it has a practical right to exist and be applied?

UPDATE

So people have not to read all up I will write here my short experience:

DI as a pattern has a practical usage. To follow DI by not injecting all services manually (a poor mans DI tool so they say...) use a DI framework like LightCore/Unity but be sure you use the right tool for the appropriate job. This is what I did not;-) Developing a mvvm/wpf application I have other requirements the LightCore/Unity tool could not support they even were a barrier. My solutions was to use MEFEDMVVM with which I am happy. Now my services are automatically injected at runtime not at startup time.:-)

Kall answered 8/9, 2011 at 19:53 Comment(19)
@bzlm, why? When drinking your posts are more constructive.George
This sounds more like a rant and not a practical question. If other DI resources don't convince you, don't know that we can either.Chiou
@msfanboy, if you don't recognize a practical advantage of DI, don't use DI. Is there anyone forcing you to use it? Are you under pressure or something?George
What happens when ICustomerService has 4 dependencies of its own, each if which have another 4? The container will do everything for you if you let it.Finfoot
If nothing else, loose coupling will give you a warm fuzzy feeling inside.Flue
@Darin Not recognize something as practical good does not mean it can not help in my case.Kall
It's not so much exchangability, but makes it much, much easier to unit test each class independently, especially using mocking frameworks. In your later case, your unit tests for billing would be hard coded to use the customer service, if that service is down or returns different data depending on time, etc then it's hard to author good tests. The former, you can inject a mock of ICustomerService easily using a mocking framework and unit test all edge cases w/o needing to worry about CustomerService class.Chiou
@msfanboy, well, speaking from my experience DI helps me a lot to make layers of my code as weakly coupled as possible which leads to better maintainability and reusability of those parts in different contexts. Unit testability is also important for me. If all those things that I list are not important for you, then don't use IOC.George
What?? seriously, this was closed? This is a very good question. You can't close a question because it violates some esoteric value system. This should be addressed directly with a response. What's worse, I had a response ready to go.Raasch
Chapter 1 (available for free) of my book actually talks about five distinct advantages of DI: affiliate.manning.com/idevaffiliate.php?id=1150_236Soup
@cunningdave, you cannot have an objective response to this question. You cannot convince anyone that DI is good for him. It might be good for you but not good for someone else. DI is just a pattern. People have different understanding of good code.George
@cunningdave: if the question had been phrased more as a genuine interest and not a "what's the point" rant (whether that was the intention or not of the OP), it might have survived.Chiou
And I can say first hand that using DI has helper our project achieve much higher levels of code coverage than we had before. Also, if your issue is passing the dependencies in the constructor, that's not the only way to do DI, you can have property injection as well where your constructor creates a default implementation of the dependency but then you also have an internal property that your unit tests can access that would set the dependency to a mock object instead, or you can use containers, etc, many ways to do it.Chiou
I was in the middle of typing out a rather lengthy answer and then I was told the question was closed :-(Hitoshi
@James it was not my intention to rant.Kall
@msfanboy: understood, I was just postulating on the reasons the closers may have voted to close it. Keep in mind it's often hard to tell from text what the tone of the question was meant to be. Perhaps if it's rephrased more re-open votes will come.Chiou
@msfanboy: in particular, the phrases "many will shout now", "so theoretical that I could tell you elephants can fly having these tall ears", "so they say is bad" seems like you're arguing from incredulity. You're saying what you think DI people think instead of just asking, "why is this bad" politely and letting them answer it, then if they answer with what you deem a "canned" response ask them to expand upon it.Chiou
@James I have removed all that people could complain about or the more emotional stuff i hope it gets reopened.Kall
@msfanboy: Looks like it re-opened already :-)Chiou
C
4

Imagine that CustomerService connects to your CRM system and your database. It creates a whole bunch of network connections to retrieve data about the customer and maybe reads additional things from the database to augment that before returning the data to the Billing class to use in its calculation.

Now you want to unit test Billing to make sure the calculations it's making are correct (you don't want to send out wrong bills right?)

How will you unit test Billing if its constructor is tied to a class that requires connections to a real CRM system and database? Wouldn't it be better to inject that dependency as an interface, easily allowing you to provide a mock version for your tests?

That is why DI is useful.

Clearheaded answered 9/9, 2011 at 7:59 Comment(7)
1.) "How will you unit test Billing if its constructor is tied to a class that requires connections to a real CRM system and database?" Why should I not be able to provide a real database connection for my unit test? 2.) With "unit test Billing" do you mean test the public methods of the Billing class?Kall
Unit tests are supposed just to test how you expect your code to operate. There should be one test for one thing. They shouldn't have any database connections as that would mean you're testing more than one thing (the code works and the connection to the databse works, and that the databse returns the correct data). If the method your testing is doing more than one thing, the chances are you could refactor it into multiple funtions, which could be tested independantly. Microsoft unit test the .net framework so you dont need to worry about unit testing your connections to the db.Anatolia
A unit test that requires a database backend is not a unit test, it's an integration test between the application and the dbms..Agretha
@Matt In the company I work for they said we do unit testing our services. What we do for example in a GetCustomerTest method is inserting data with pure sql statements and then use the customerService.GetCustomer(id) method to assert the the customer.Id for equality. YOU say this is not unit testing but integration testing? Well then I have to say this to my colleagues.Kall
@Kall please do, and you can use this table for reference :) qastation.wordpress.com/2008/04/11/…Agretha
@Clearheaded your answer is just slightly better than Matts ;-) and to answer my own question it seems I have no practical usage for it but this needs to be determined 100% in another question because of my existing application architecture.Kall
@Clearheaded What I still found out for my individual needs is that using a DI tool like LightCore/Unity did not help me in developing a mvvm/wpf application where every class and its interfaces were injected at startup time and all the code in the Ctor run always even when not clicked by the user. DI as a pattern is good, but I used the wrong tool which I just wanted to try out for fun. I use now MEFEDMVVM again which uses MEF where you can inject services too even into datatemplated ViewModels what I needed :)Kall
A
5

Understanding the how and understanding the why are very different things..

One of the biggest benefits of DI is for unit testing. In your second example it's impossible to unit test Billing without also testing CustomerService (and also testing any further dependencies in the chain). In that case you're not unit testing, you're integration testing! If you want a good rationale for using DI, you need not look any further than a rationale for unit testing..

Agretha answered 9/9, 2011 at 7:59 Comment(2)
I did not understand your last sentence, can you rephrase please?Kall
DI provides loose coupling which enables true unit testing. You can view DI as a unit test enabling pattern. The reasons to do unit testing are also reasons to use DIAgretha
C
4

Imagine that CustomerService connects to your CRM system and your database. It creates a whole bunch of network connections to retrieve data about the customer and maybe reads additional things from the database to augment that before returning the data to the Billing class to use in its calculation.

Now you want to unit test Billing to make sure the calculations it's making are correct (you don't want to send out wrong bills right?)

How will you unit test Billing if its constructor is tied to a class that requires connections to a real CRM system and database? Wouldn't it be better to inject that dependency as an interface, easily allowing you to provide a mock version for your tests?

That is why DI is useful.

Clearheaded answered 9/9, 2011 at 7:59 Comment(7)
1.) "How will you unit test Billing if its constructor is tied to a class that requires connections to a real CRM system and database?" Why should I not be able to provide a real database connection for my unit test? 2.) With "unit test Billing" do you mean test the public methods of the Billing class?Kall
Unit tests are supposed just to test how you expect your code to operate. There should be one test for one thing. They shouldn't have any database connections as that would mean you're testing more than one thing (the code works and the connection to the databse works, and that the databse returns the correct data). If the method your testing is doing more than one thing, the chances are you could refactor it into multiple funtions, which could be tested independantly. Microsoft unit test the .net framework so you dont need to worry about unit testing your connections to the db.Anatolia
A unit test that requires a database backend is not a unit test, it's an integration test between the application and the dbms..Agretha
@Matt In the company I work for they said we do unit testing our services. What we do for example in a GetCustomerTest method is inserting data with pure sql statements and then use the customerService.GetCustomer(id) method to assert the the customer.Id for equality. YOU say this is not unit testing but integration testing? Well then I have to say this to my colleagues.Kall
@Kall please do, and you can use this table for reference :) qastation.wordpress.com/2008/04/11/…Agretha
@Clearheaded your answer is just slightly better than Matts ;-) and to answer my own question it seems I have no practical usage for it but this needs to be determined 100% in another question because of my existing application architecture.Kall
@Clearheaded What I still found out for my individual needs is that using a DI tool like LightCore/Unity did not help me in developing a mvvm/wpf application where every class and its interfaces were injected at startup time and all the code in the Ctor run always even when not clicked by the user. DI as a pattern is good, but I used the wrong tool which I just wanted to try out for fun. I use now MEFEDMVVM again which uses MEF where you can inject services too even into datatemplated ViewModels what I needed :)Kall
A
2

DI Comes in useful, when you want to pass different implementations of the Interface to your class, for example: Unit Testing.

Say your Billing constructor is an MVC controller's constructor, and your CustomerService took some form of IDataContext as a parameter.

Global.asax

// Does the binding
ICustomerService binds to CustomerService
IDataContext binds to EntityFrameworkContext

CustomerService

private IDataContext _datacontext;   
public CustomerService(IDataContext dataContext)   
{   
   _dataContext = dataContext;  
}

public AddCustomer(Customer entity)   
{   
  this._dataContext.Customers.Add(entity);
  this._dataContext.SaveChanges;   
}   

MVC Controller

private ICustomerService _customerService;
public Billing(ICustomerService customerService)
{
   _customerService = customerService;
}

public ActionResult NewCustomer()
{
  Customer customer = new Customer(){ Name = "test" };
  this._customerService.AddCustomer(customer);

  return View();
}

Say you wanted to unit test your Services, or Controllers. You would pass in the CustomerServices, but you would pass in a fake implementation of the EntityFrameWorkContext. So a FakeDbContext, that implements IDataContext, is passed to customer services.

The FakeDbContext may just store the entities in Lists or a more elaborate storage mechanism, the point being, you can inject different implementations of dependencies, which allows you to alter the behaviour of one component without having to modify your code elsewhere.

Anatolia answered 9/9, 2011 at 8:6 Comment(1)
Ok this could be a reason to use the DI pattern but I have never been in such a scenario maybe therefore its so hard to understand.Kall
U
1

In my experience it is not only about avoiding integration test (but that is a very important point too). Instantiating classes on the inside can create a lot of work unit testing. A class like CustomerService might depend on an open Database connection, configuration files, services being available and a lot of other stuff, that you should not have to know about, when your job is to test the Billing class only.

That being said, sometimes it is a pain always to inject everything. Injection frameworks might lighten that load, but I'm not at big fan. Another kind stackoverflow user pointed me to what he called "poor mans injection". Basically it consists of two constructor overloads: One constructor with the injected interface, and one without. The one without does nothing but instantiate a concrete class that implements the interface, and pass it to the other constructor. It goes something like this:

public class Billing
{
  ICustomerService _customerService;

  public Billing():this(new CustomerService()) {}

  public Billing(ICustomerService customerService)
  {
    _customerService = customerService;
  }
}

This way you have an way to inject when testing AND a way to construct the class with a default implementation of the interface. Not everybody loves this pattern, but I find it practical for some scenarios.

Ungula answered 9/9, 2011 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.