views:

190

answers:

6

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?

+7  A: 

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
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!!
CodeMonkey
But since it's a test-database, does it really matter that my database is updated??
CodeMonkey
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
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
CodeMonkey
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
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
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.
Rogerio
+1  A: 

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
Could you elaborate on the terms "stub" and "mock" ... I presume "mock" is what I referred to as "fake"-objects
CodeMonkey
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
+3  A: 

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
+2  A: 

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
+1 for mentioning how DI/IoC Container frameworks can replace the evil Singleton pattern!
TrueWill
A: 

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
A: 

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.

Rogerio