51

I've had a certain feeling these last couple of days that dependency-injection should really be called "I can't make up my mind"-pattern. I know this might sound silly, but really it's about the reasoning behind why I should use Dependency Injection (DI). Often it is said that I should use DI, to achieve a higher level of loose-coupling, and I get that part. But really... how often do I change my database, once my choice has fallen on MS SQL or MySQL .. Very rarely right?

Does anyone have some very compelling reasons why DI is the way to go?

  • 4
    I like all your reasons so far... I understand that it is mostly seasoned programmers that "get" DI. As I understand it DI is about quality. We, as programmers, want to produce the highest level of software we can -- and testing it helps. I've written ALOT of code over the years, and I'm happy to say that 10 years past, over 50 % of it is still running.. and that without DI. Maybe that helps you understand why I'm a bit reserved about DI ? –  Oct 16 '09 at 22:09
  • 1
    Obviously DI is new relatively speaking. So of course you can write high quality software without it - but with the advancement of things like testing frameworks and TDD, DI can make it a lot easier to write tests as well as write code that is maintainable for the future (coupling). – digiarnie Oct 16 '09 at 22:12

8 Answers8

56

Two words, unit testing.

One of the most compelling reasons for DI is to allow easier unit testing without having to hit a database and worry about setting up 'test' data.

Jason Whitehorn
  • 13,585
  • 9
  • 54
  • 68
  • 3
    So you are talking about de-coupling the database, and "fake it", by using some fake objects instead of changing my DB during my unit tests... hmm... sounds like a reasonable argument actually!! –  Oct 16 '09 at 21:58
  • But since it's a test-database, does it really matter that my database is updated?? –  Oct 16 '09 at 21:59
  • 7
    Your tests would run a lot faster without having to hit a real database. Plus when you are testing for specific cases you would have a lot easier of a time setting up those specific cases in a mock object versus having to worry if your test database is in a correct state or not. – Jason Whitehorn Oct 16 '09 at 22:01
  • May not need to be a test database. I've done tests where I pass in my own test data w/o interfacing with a database. It's more controlled but can help you focus on the logic afterwards. – JamesEggers Oct 16 '09 at 22:03
  • My tests speed is (sorry) completely irrelevant (unless you have something interesting to add here that I miss). To me, testing is testing... I don't give a %¤!& about my test's speed. Database-state on the other hand I can grasp -- Because... does my test fail because of the DB or the code I just put in... Very useful!!! That I must say is the best argument I have heard for DI so far...!! –  Oct 16 '09 at 22:13
  • 1
    In my opinion test speed and ultimately build speed is of utmost importance. Whether a solo developer or a large team, you want the ability to build your project as often as possible to maintain a successful build so people can continue to check in and check in often. People are more reluctant to check if "often" if the build is slow due to slow tests. – digiarnie Oct 16 '09 at 22:18
  • 2
    If you are developing using TDD (and you should!), then you run the test suite every 30 seconds. Then you cannot afford a runtime of more than a few seconds. – Flavius Stef Oct 16 '09 at 22:25
  • 24
    Unit testing does not require DI at all. If you need to replace the "real" database implementation, then set up a mock/fake implementation and test away... Granted, this isn't always doable for certain languages (eg, C++) or with certain mocking tools, but the fact that it often IS doable implies that unit testing, by itself, is not always a valid reason. – Rogério Jan 09 '10 at 20:27
  • THere are other ways to increase confidence in the code aside from unit-testing. If DI is only useful for unit-testing then projects without unit-tests (but that use something like design-by-contract) do not require DI, is that correct? –  Apr 23 '12 at 18:14
  • I agree with Rogerio. – Mick Dec 16 '13 at 03:52
  • 7
    Sorry but I don't think this answer is complete. Replacing DI by "mocking" in this text would make more sense. DI is useful for a lot more scenarios since it encourages loose coupling between components. – arviman Dec 28 '13 at 15:04
14

DI is very useful for decoupling your system. If all you're using it for is to decouple the database implementation from the rest of your application, then either your application is pretty simple or you need to do a lot more analysis on the problem domain and discover what components within your problem domain are the most likely to change and the components within your system that have a large amount of coupling.

DI is most useful when you're aiming for code reuse, versatility and robustness to changes in your problem domain.

How relevant it is to your project depends upon the expected lifespan of your code. Depending on the type of work you're doing zero reuse from one project to the next for the majority of code you're writing might actually be quite acceptable.

An example for use the use of DI is in creating an application that can be deployed for several clients using DI to inject customisations for the client, which could also be described as the GOF Strategy pattern. Many of the GOF patterns can be facilitated with the use of a DI framework.

DI is more relevant to Enterprise application development in which you have a large amount of code, complicated business requirements and an expectation (or hope) that the system will be maintained for many years or decades.

Mick
  • 6,527
  • 4
  • 52
  • 67
  • It is also useful during rapid development if you seek flexibility (because you wish to conduct experimentation). You can easily hookup different views, data structures, menus, control schemes and what not. It basically (if I understand and use it correctly), allows you to manage "dependencies" in a more flexible and organized manner with less boiler-plate code noise. Of course it could be misused and somehow make code more complicated potentially. – AturSams Jun 26 '17 at 13:05
6

Even if you don't change the structure of your program during development phases you will find out you need to access several subsystems from different parts of your program. With DI each of your classes just needs to ask for services and you're free of having to provide all the wiring manually.

This really helps me on concentrating on the interaction of things in the software design and not on "who needs to carry what around because someone else needs it later".

Additionally it also just saves a LOT of work writing boilerplate code. Do I need a singleton? I just configure a class to be one. Can I test with such a "singleton"? Yes, I still can (since I just CONFIGURED it to exist only once, but the test can instantiate an alternative implementation).

But, by the way before I was using DI I didn't really understand its worth, but trying it was a real eye-opener to me: My designs are a lot more object-oriented as they have been before. By the way, with the current application I DON'T unit-test (bad, bad me) but I STILL couldn't live with DI anymore. It is so much easier moving things around and keeping classes small and simple.

froh42
  • 5,190
  • 6
  • 30
  • 42
  • 1
    +1 for mentioning how DI/IoC Container frameworks can replace the evil Singleton pattern! – TrueWill Oct 16 '09 at 22:34
  • Most DI framework I see has at least 2000+ lines of code, that seems like a lot of code. Also, it doesn't seem like you can use the framework without modifying existing code. In your experience, is it easy to swap a DI framework for another? – Boon Jun 03 '14 at 21:15
  • @TrueWill Why is the Singleton evil while the DI version of it, good? – AturSams Jun 26 '17 at 13:07
  • 1
    @zehelvion Much of it comes down to testability - DI makes it easy to isolate and unit test. DI also makes dependencies explicit; Singleton usage can be hard to see. From an implementation perspective, DI lets you create (effective) Singletons from simple classes (Single Responsibility). See also https://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons – TrueWill Jun 26 '17 at 13:46
  • Yeah, I think this sums it up: http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ You don't want complex construction / initialization strewn about your code and instead prefer to have it organized and easy to change. – AturSams Jun 26 '17 at 14:18
4

While I semi-agree with you with the DB example, one of the large things that I found helpful to use DI is to help me test the layer I build on top of the database.

Here's an example...

You have your database.

You have your code that accesses the database and returns objects

You have business domain objects that take the previous item's objects and do some logic with them.

If you merge the data access with your business domain logic, your domain objects can become difficult to test. DI allows you to inject your own data access objects into your domain so that you don't depend on the database for testing or possibly demonstrations (ran a demo where some data was pulled in from xml instead of a database).

Abstracting 3rd party components and frameworks like this would also help you.

Aside from the testing example, there's a few places where DI can be used through a Design by Contract approach. You may find it appropriate to create a processing engine of sorts that calls methods of the objects you're injecting into it. While it may not truly "process it" it runs the methods that have different implementation in each object you provide.

I saw an example of this where the every business domain object had a "Save" function that the was called after it was injected into the processor. The processor modified the component with configuration information and Save handled the object's primary state. In essence, DI supplemented the polymorphic method implementation of the objects that conformed to the Interface.

JamesEggers
  • 12,885
  • 14
  • 59
  • 86
3

Dependency Injection gives you the ability to test specific units of code in isolation.

Say I have a class Foo for example that takes an instance of a class Bar in its constructor. One of the methods on Foo might check that a Property value of Bar is one which allows some other processing of Bar to take place.

public class Foo
{
    private Bar _bar;

    public Foo(Bar bar)
    {
        _bar = bar;
    }

    public bool IsPropertyOfBarValid()
    {
        return _bar.SomeProperty == PropertyEnum.ValidProperty;
    }
}

Now let's say that Bar is instantiated and it's Properties are set to data from some datasource in it's constructor. How might I go about testing the IsPropertyOfBarValid() method of Foo (ignoring the fact that this is an incredibly simple example)? Well, Foo is dependent on the instance of Bar passed in to the constructor, which in turn is dependent on the data from the datasource that it's properties are set to. What we would like to do is have some way of isolating Foo from the resources it depends upon so that we can test it in isolation

This is where Dependency Injection comes in. What we want is to have some way of faking an instance of Bar passed to Foo such that we can control the properties set on this fake Bar and achieve what we set out to do, test that the implementation of IsPropertyOfBarValid() does what we expect it to do, i.e. return true when Bar.SomeProperty == PropertyEnum.ValidProperty and false for any other value.

There are two types of fake object, Mocks and Stubs. Stubs provide input for the application under test so that the test can be performed on something else. Mocks on the other hand provide input to the test to decide on pass\fail.

Martin Fowler has a great article on the difference between Mocks and Stubs

Russ Cam
  • 124,184
  • 33
  • 204
  • 266
2

I think that DI is worth using when you have many services/components whose implementations must be selected at runtime based on external configuration. (Note that such configuration can take the form of an XML file or a combination of code annotations and separate classes; choose what is more convenient.)

Otherwise, I would simply use a ServiceLocator, which is much "lighter" and easier to understand than a whole DI framework.

For unit testing, I prefer to use a mocking API that can mock objects on demand, instead of requiring them to be "injected" into the tested unit from a test. For Java, one such library is my own, JMockit.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • +1 for mentioning servicelocator. I think sometimes DI seems overkill when people only use the "service location" aspect of it. – Pure Function Apr 15 '13 at 11:14
1

Aside from loose coupling, testing of any type is achieved with much greater ease thanks to DI. You can put replace an existing dependency of a class under test with a mock, a dummy or even another version. If a class is created with its dependencies directly instantiated it can often be difficult or even impossible to "stub" them out if required.

digiarnie
  • 22,305
  • 31
  • 78
  • 126
  • Could you elaborate on the terms "stub" and "mock" ... I presume "mock" is what I referred to as "fake"-objects –  Oct 16 '09 at 22:02
  • 2
    By stub I was just referring to replacing any dependency with something "else" for testing. By mock I mean using a library such as jmock or mockito (if you're using java of course) to create a proxy where you declare expectations on that "mock" object. You could also possibly create a dummy version of a class by implementing the dependency's interface. – digiarnie Oct 16 '09 at 22:07
  • When u mock object, do u register it in the di registery or simply pass the dummy object in? through constructor for example. – liang Feb 13 '14 at 12:38
0

I just understood tonight. For me, dependancy injection is a method for instantiate objects which require a lot of parameters to work in a specific context.

When should you use dependancy injection? You can use dependancy injection if you instanciate in a static way an object. For example, if you use a class which can convert objects into XML file or JSON file and if you need only the XML file. You will have to instanciate the object and configure a lot of thing if you don't use dependancy injection.

When should you not use depandancy injection? If an object is instanciated with request parameters (after a submission form), you should not use depandancy injection because the object is not instanciated in a static way.

  • I asked this question many years ago, and I have learned a lot since then. What you are describing would be solved well by using an IoC-container, and inject the created object using DI. So for instance, you configure your "complicated" object in the IoC container's registry, and "request" an instance of that which you inject in the code where you need it. I agree that that is also a valid reason for using DI. –  Oct 18 '16 at 18:32