I finally get the point of inversion of control

I think I’m finally starting to understand the Inversion of Control principle (aka Dependency Injection). I had a hard time understanding most examples out there, because they appeared to be solving problems that didn’t even seem like real problems to me. For years I’ve been writing classes, testing them, and hooking them together. In many cases, I was already practicing inversion of control. The benefit I wasn’t seeing was the fact that you can separate the modules in your code and the connections between them.

traditional-vs-di

When you really commit yourself to breaking the problem down into manageable pieces, it does create more testable and reusable code. I already knew that, but when you starting using IoC, it really starts to drive that point across. It’s similar to the effect that unit testing has. When you start writing unit tests, you try to make your classes more unit testable. When you start using a dependency injection framework, you try to make your classes more open to injection.

So what is a dependency injection framework? It’s the glue that holds your pieces together. Without it, your classes would probably be dictating the classes that it depends on. With dependency injection, the application configuration tells the class what modules to use. A dependency injection framework separates the linking from the pieces.

ioc diagrams 

In the diagram on the left, it’s a typical tightly coupled design. Every class is hooked up directly to another class. This doesn’t mean that each class isn’t testable, but it’s a very rigid design (which isn’t necessarily avoidable). In general, the easiest unit testing was in the classes on the edges, since they have a usable surface area.

The diagram on the right is closer to what I’ve been creating while using a dependency injection framework. In the first pass, I create pieces that contain my business logic. Then, I can use the dependency injection framework to declaratively define how those pieces are wired together.

At this point, I would have a hard time NOT using something like this. While this concept isn’t new, the frameworks have recently become very mature. Personally, I’m using Spring.NET and loving it. One of my pet projects for package tracking,(SimpleTracking.com) has been rewritten using a modular, test first, dependency injected design philosophy. I was able to reduce the amount of actual code by quite a bit, increase my testing coverage, and decrease the amount of duplicate code.

Sold

I’m sold!

Kick It!

14 Comments so far »

  1. Kevin Berridge said,

    Wrote on June 6, 2008 @ 10:53 am

    I use the Dependency Inversion Principle and Dependency Injection but I haven’t made the leap to an IoC framework.

    One reason why is that I was afraid defining the dependencies between my objects in an external configuration file would make it really hard to figure out what was going on in my code. For example, you can’t “right click, go to definition” anymore. I wrote about this a bit here.

    Have you run into anything like that at all since you’ve been using Spring.NET?

  2. superjason said,

    Wrote on June 6, 2008 @ 2:00 pm

    Kevin, I haven’t run into that yet, but I could see that happening.

    Have you been following the law of Demeter? I think that would certainly help. Each class is really only concerned with it’s siblings, which are interfaces. Since they’re interfaces, it shouldn’t really care about the implementations.

  3. Kevin Berridge said,

    Wrote on June 6, 2008 @ 4:25 pm

    I am familiar with the law of Demeter. And you’re right in principle that the classes shouldn’t care about the implementations. But I’ve found that in practice I usually care.

    For example, sometimes you’re just debugging and trying to figure out what went wrong. If you’re stepping through, you’re good. But if you’re reading, it’s easy to get lost.

    Also, interfaces can’t describe everything. Will the class handle it’s exceptions or throw them? Will the class close the db connection or leave it open for me? Will the class check that parameters are not null, or assume that I’ve already checked for that?

    These little things aren’t important in the big scheme of things, but they’re crucial when you’re trying to make software work.

    It’s quite possible I’m making a bigger deal out of this than it really is though. My fear is just that IoC (and DI) can make your code more complicated just for the sake of testing. I’d really love to hear (now and over time) what you think about that.

  4. Jared said,

    Wrote on June 9, 2008 @ 7:21 am

    > Also, interfaces can’t describe everything. Will the class
    > handle it’s exceptions or throw them? Will the class close
    > the db connection or leave it open for me? Will the class
    > check that parameters are not null, or assume that I’ve
    > already checked for that?

    I’m not overly familiar with .NET (I do mostly Java…) but in my experience, an interface SHOULD define these things. The whole point is that the interface needs to define how a client should interact with it. If there are “implementation details” that you need to know to invoke an interface, then they’re not really implementation details. A method should define (at the very least, using comments) what exceptions that method should throw, what it will do with resources passed to it, and what are valid parameters.

    So, I’d say that these things are very important in the big scheme of things - you need this information in order to invoke a method. Therefore, if this information is not included in the interface, then you can’t really code to the interface, can you?

  5. Riccardo said,

    Wrote on June 9, 2008 @ 7:33 am

    hello Kevin,
    IMHO the problem you have is with your IDE, non IOC itself; the IDE I use (different language, though…) lets you step to the implementation wih just one more click, indeed a very little complication vs. a very big advantage.
    Also things like “check that parameters are not null” should be stated in the docs from the interface if they are relevant; so again not IOC’s fault, but programmer’s.

  6. Renato said,

    Wrote on June 9, 2008 @ 9:52 am

    I’d have to agree with Jared. The operations should define how the methods will behave. Using something like Design by Contract helps a lot with this. The final state of the db connection can be defined as a postcondition. The validity of a null parameter can be described as a precondition. And so on.

  7. bminews.com said,

    Wrote on June 9, 2008 @ 10:02 am

    Inversion of Control…

    Discussion about the Inversion of Control design pattern for making modular software….

  8. Kevin Berridge said,

    Wrote on June 9, 2008 @ 10:12 am

    You are all of course correct. You should put comments on things to describe requirements like these. Of course that doesn’t guarantee implementors will follow them, or that the comments will remain up to date, but that’s beside the point.

    My argument is, if you weren’t using IoC you wouldn’t have to worry about any of this. You would simply write your code and be done with it. It’s only because you’re allowing for arbitrary implementations to be passed in (through DI) that any of this is important. If you intended for many implementations to be used, it makes sense to worry about this. But when you’re doing it simply so you can test, is it worth it?

    @Riccardo: I’m curious. Are you talking about stepping through while you’re Debugging, or a “go to definition” type feature when you’re just browsing the code?

    Thanks everyone for the responses! It’s been very educational for me. I should also point out that I agree with all of you, and that in real life I actually use DI (though not IoC). I mainly just wanted to spur a discussion about the possible downsides.

  9. Riccardo said,

    Wrote on June 10, 2008 @ 10:16 am

    @Kevin
    Well I don’t know if this applies also to .net, but in java (with most IDE’s) you can look through the stack trace, you can use step filters to avoid stopping at DI framework proxies when you debug; or you can also go to a specific implementation instead of going to method definition while browsing code.
    I also found this discussion very interesting and I agree that DI is to be used wisely; I also think that the chance to test code easier is alone worth most downsides of DI.
    Thanks to everyone, specially to the author which wrote a very good post.

  10. Steven Harman said,

    Wrote on June 11, 2008 @ 8:50 pm

    @Kevin,
    I have to agree with some of the others - the problem you’re describing is not one with the pattern, but with your IDE.

    A weak IDE is not a valid reason to dismiss the Dependency Inversion Principle, nor any of the related SOLID principles (i.e.- Separation of Concerns, Single Responsibility Principle, Liskov Substitution Principle, Law of Demeter, etc…). Following these principles leads to more loosely coupled, highly cohesive code which easily delivers more value than is lost due to the code navigation issues you’ve described with your IDE.

    Plus, as a .net guy, likely writing code in Visual Studio - you can easily overcome those navigation issues with ReSharper.

  11. Egil said,

    Wrote on June 12, 2008 @ 3:35 am

    Jason, thanks for this, I finally get the principle. I would love to see some example code to get my head around it even more.

    Regards, Egil.

  12. superjason said,

    Wrote on June 12, 2008 @ 7:21 am

    Egil, great idea. I have a GREAT example too! Subscribe to my feed so you don’t miss it. I’ll try to shot for posting it tomorrow.

  13. A Dependency Injection example with Spring.NET said,

    Wrote on June 13, 2008 @ 8:32 am

    [...] requested, here is a real world example of how I used dependency injection to simplify a project, increase modularity, and subsequently increase [...]

  14. Kevin Berridge said,

    Wrote on July 24, 2008 @ 11:39 am

    I forgot to post back here, its mostly too late now, but I’ll link my response anyway: http://kevin-berridge.blogspot.com/2008/06/ioc-and-di-complexity.html

Comment RSS · TrackBack URI

Leave a Comment

Name: (Required)

E-mail: (Required)

Website:

Comment: