Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Given a constructor that will never, ever, have to use any different implementations of several objects that it initializes, is it still practical to use DI? After all, we might still want to unit test.

The class in question initializes a few other classes in its constructor and the classes it uses are pretty specific. It will never use another implementation. Are we justified in avoiding trying to program to an interface?

share|improve this question
    
possible duplicate of Design for future changes or solve the problem at hand –  gnat Sep 23 '13 at 11:09
3  
KISS - is always the best approach. –  Mathew Foscarini Sep 23 '13 at 13:12
4  
In my opinion this question is more specific than the proposed duplicate. design-for-future-changes-or-solve-the-problem-at-hand, Therefore i vote to not close this –  k3b Sep 23 '13 at 14:58
1  
Isn't testability enough of a reason? –  ConditionRacer Sep 23 '13 at 15:53
    
Doesn't really sound like a duplicate so much as answering itself. If it will never, ever happen, designing for it isn't designing for future changes. Even architecture astronauts only design for changes that will never happen out of bad judgement. –  Steve314 Sep 23 '13 at 16:12
show 2 more comments

8 Answers

up vote 13 down vote accepted

It depends on how certain you are that "never, ever" is correct (during the time your app will be used).

In general:

  • Don't modify your design just for testability. Unit tests are there to serve you, not vice versa.
  • Don't repeat yourself. Making an interface that will only ever have one inheritor is useless.
  • If a class isn't testable, it's likely not flexible/extensible for real use cases either. Sometimes that's fine - you're unlikely to need that flexibility, but simplicity/reliability/maintainability/performance/whatever is more important.
  • If you don't know, code to the interface. Requirements change.
share|improve this answer
12  
Almost gave you -1 for "don't modify your design just for testability". To gain testability is IMHO one of the tops reasons for changing a design! But your other points are ok. –  Doc Brown Sep 23 '13 at 12:28
5  
@docBrown - (and others) I do differ here from many, and perhaps even the majority. ~95% of the time, making things testable also makes them flexible or extensible. You should have that in your design (or add that to your design) most of the time - testability be damned. The other ~5% either has odd requirements that prevents this sort of flexibility in favor of something else, or is so essential/unchanging that you'll find out pretty quickly if it's broken, even without dedicated tests. –  Telastyn Sep 23 '13 at 12:51
4  
may be sure, but your first statement above could be misinterpreted too easily as "leave badly designed code as it is when your only concern is testability". –  Doc Brown Sep 23 '13 at 12:56
1  
Why would you say "Making an interface that will only ever have one inheritor is useless."? Interface can work as a contract. –  kaptan Sep 23 '13 at 18:59
2  
@kaptan - because the concrete object can work just as well as a contract. Making two just means you need to write the code twice (and modify the code twice when it changes). Granted, the vast majority of interfaces will have multiple (non-test)implementations or at you need to prepare for that eventuality. But for that rare case where all you need is a simple sealed object, just use it directly. –  Telastyn Sep 23 '13 at 19:06
show 5 more comments

Are we justified in avoiding trying to program to an interface?

While the advantage of coding against an interface is pretty evident, you should ask yourself what exactly is gained by not doing it.

The next question is: is part of the responsibility of the class in question to choose the implementations or not? That may or may not be the case and you should act accordingly.

Ultimately, there's always potential for some goofy constraint to come out of the blue. You may want to run the same piece of code concurrently, and the possibility of injecting the implementation might help with synchronization. Or after profiling your app you may discover you want an allocation strategy different from plain instantiation. Or cross-cutting concerns come up and you don't have AOP support at hand. Who knows?

YAGNI suggest that when writing code, it's important not to add anything superfluous. One of the things that programmers tend to add to their code without even being aware of it, are superfluous assumptions. Like "this method might come in handy" or "this'll never change". Both add clutter to your design.

share|improve this answer
2  
+1 for citing YAGNI here as an argument for DI, not against it. –  Doc Brown Sep 23 '13 at 12:35
4  
@DocBrown: Considering that YAGNI can be used here, to also justify not using DI. I think that's more of an argument against YAGNI being a useful measure for anything. –  Steve Evers Sep 23 '13 at 15:29
1  
+1 for superfluous assumptions being included in YAGNI, which have hit us in the head a few times –  Izkata Sep 23 '13 at 15:29
    
@SteveEvers: I think using YAGNI to justify ignoring the dependency inversion principle precludes a lack of understanding of YAGNI or DIP or maybe even some of the more fundamental principles of programming and reasoning. You should only ignore the DIP if you need to - a circumstance in which YAGNI is simply not applicable by its very nature. –  back2dos Sep 24 '13 at 10:50
    
@back2dos: The supposition that DI is useful because of 'maybe-requirements' and "who knows?" is precisely the train of thought that YAGNI is intended to combat, instead you're using it as a justification for additional tooling and infrastructure. –  Steve Evers Sep 24 '13 at 17:17
show 5 more comments

It depends on various parameters but here are a few reasons why you could still want to use DI:

  • testing is quite a good reason in itself I believe
  • the classes required by your object might be used in other places - if you inject them it enables you to pool the resources (for example if the classes in question are threads or database connections - you don't want each of your classes to create new connections)
  • if initialising those other objects can fail, code higher up the stack will probably be better at dealing with problems than your class which will then probably simply forward the errors

Bottom line: you can probably live without DI in that case but there are chances that using DI will end up in cleaner code.

share|improve this answer
add comment

When you design a program or a feature, part of the thought process should be how you are going to test it. Dependency Injection is one of the testing tools, and should be considered as part of the mix.

The additional benefits of Dependency Injection and using interfaces instead of classes are also beneficial when an application is extended, but they can also be retrofitted to the source code later quite easily and safely using search and replace. - even on very large projects.

share|improve this answer
add comment
 > Dependency Injection worth it **outside** of UnitTesting?
 > Are we justified in avoiding trying to program to an interface?

Many answers to this question can be debated as "you might need it because .." as YAGNI if you do not want to do unittesting.

If you are asking what reasons beside unittests require to program to an interface

Yes, Dependency Injection worth it outside of UnitTesting if you need inversion of control. For example if one module implementation need an other module that is not accessable in its layer.

Example: if you have the modules gui => businesslayer => driver => common.

In this scenario businesslayer can use driver but driver can not use businesslayer.

If driver needs some higherlevel functionality you can implement this functionality in businesslayer which implements an interface in common layer. driver only needs to know the interface in common layer.

share|improve this answer
add comment

Yes you are - firstly, forget about unit testing as a reason to design your code around the unit test tools, it is never a good idea to bend your code design to fit an artificial constraint. If your tools force you to do this, get better tools (eg Microsoft Fakes/Moles that allow you many more options for creating mock objects).

For example, would you split your classes up into only-public methods just because the test tools do not work with private methods? (I know the prevailing wisdom is to pretend you don't need to test private methods, but I feel this is a reaction to the difficulty in doing so with current tools, not a genuine reaction to not needing to test privates).,

All in all it comes down to what kind of TDDer you are - the "mockist" as Fowler describes them, need to change the code to suit the tools they use, whereas the "classical" testers create tests that are more integration in nature (ie test the class as a unit, not each method) so there is less need for interfaces, especially if you use the tools that can mock concrete classes.

share|improve this answer
3  
I don't think the prevailing wisdom that private methods shouldn't be tested has anything to do with the difficulty of testing them. If there were a bug in a private method, but it didn't affect the object's behavior, then it doesn't affect anything. If there were a bug in a private method that did affect the object's behavior, then there's a failing or missing test on at least one of the public methods of an object. –  Michael Shaw Sep 23 '13 at 18:37
    
That comes down to whether you test for behaviour or state. The private methods need to be tested in some way, obviously, but if you're a classical TDD person, you'll test them by testing the class "as a whole", the test tools most people use are focussed on testing each method individually... and my point is the latter are effectively not testing properly as they miss the chance to perform a full test. So I agree with you, while trying to highlight how TDD has been subverted by how some (most?) people do unit testing today. –  gbjbaanb Sep 24 '13 at 8:17
add comment

Dependency Injection also makes it clearer that your object HAS dependencies.

When someone else goes to use your object naively (without looking at the constructor), they will find that they will need to set up services, connections, etc. That were not obvious because they didn't have to pass them in to the constructor. Passing in the dependencies makes it clearer what is needed.

You are also potentially hiding the fact that you class may be violating SRP. If you are passing in many dependencies (more than 3), your class may be doing too much and should be refactored. But if you are creating them in the constructor, this code smell will be hidden.

share|improve this answer
add comment

I agree with both camps here and the matter is still open for debate in my opinion. YAGNI demands that I not tackle changing my code to fit supposition. Unit testing is not a problem here because I firmly believe that the dependency will never, ever change. But if I was Unit testing as intended to begin with, I would have never reached this point anyway. As I would have slimed my way into DI eventually.

Let me offer another alternative for my scenario specifically

With a factory pattern I can localize dependencies in one place. When testing I can change implementation based on context, and that's good enough. This doesn't go against YAGNI because of the benefits of abstracting several class constructions.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.