DIY-DI

The “dependency injection” (DI) technique is a way to improve testability and maintainability of object-oriented code. Typically adoption of dependency injection is coupled with adoption of a dependency injection framework, such as Guice or Spring. These materials show how dependency injection can be accomplished without any framework. The same benefits provided by frameworks can be realized using “do-it-yourself” (DIY) handcrafted code. This model is named DIY-DI, pronounced die-die.

Update (May 29, 2010): I added a comparison with Guice and more polished code snippets to the DIY-DI manual.

34 thoughts on “DIY-DI

  1. Pingback: Do it Yourself – Dependency Injection

  2. Rusty Wright

    Page numbers would have been nice on the pdf, in case I drop them and they’re not stapled and get out of order.

  3. Rusty Wright

    Sorry; before I criticized I should have thanked you for such a nice write up!

    Thanks again; this is very helpful.

  4. Böszörményi Péter

    Hi!

    I have a question about the article. In step 5 you removed the parameters from BookingService’s buy method, and added to the constructor. This modification introduced an – in my opinion – unnecessary state to BookingService. From this point, if i want to use this service, i always have to create a new instance (cannot share the instance across multiple invocation), and i always have to deal with the constructor’s parameters. Wouldn’t it be easier to use the BookingService’s earlier form (from step 4)?

    ps: Sorry for my english, it’s not my native language.

  5. Chad Parry Post author

    Péter, the intention in step 5 was to make it easier to acquire a BookingService. I know that’s counter-intuitive, because of the reason you describe. The BookingService dependencies are not easy to construct. So callers would be over-burdened if they always had to say:
    BookingService.buy(Account.getCustomerAccount(accountKey), new Trade(symbol, quantity), commission);
    Most would prefer:
    booking.buy();
    Plus, those callers would prefer the looser coupling with accounts, account keys, trades, symbols, quantities and commissions.

    Fortunately, in a DI-infected application, that extra BookingService state does not tend to create a problem. Anyone that needs a BookingService simply asks the injection framework for one, and a fresh instance is provided. If multiple instances were undesirable, then the BookingService could be left like in Step 4, and the request-specific state could be moved to a BookingClient class instead. Then BookingClient would have constructor parameters for accounts, trades, commissions and the BookingService instance.

  6. Nuttanart

    I love this silde. I was finding for example like this a half year. DIY-DI, refactoring approach to make code testable and combing some OO principles. Better than many selling books. Thanks.

  7. Petter Måhlén

    Hi,

    Great ideas and very clearly expressed! I have a couple of questions, though:
    – In your Injector examples, you always create new instances of the things that you inject. For a lot of object graphs you’ll probably want to reuse the same instance of some objects and inject that into multiple other objects. In such a case, would you typically cache that instance in the scope (making it mutable) or in the injector class or is that some third thing?
    – I’m not quite with you on the “don’t use mock objects” issue. Could you elaborate on that? It feels like it is quite common that one object wants to trigger something to happen in a collaborator. Of course, the data exchanged between the objects can be represented as primitives/value objects, but the actual event of triggering something cannot as far as I can figure. I guess that could be made a part of the wiring up, but that seems like it would hide important and testable business logic. Using mock objects feels like the best way to check that sort of thing.

    Cheers,
    Petter

  8. Pingback: Tweets that mention Black Sheep » DIY-DI » Print -- Topsy.com

  9. Chad Parry Post author

    Petter, my thoughts on caching mirrored yours. I didn’t get into it on the slides, but you can see the description of a clean technique in the DIY-DI.pdf. Look for the section titled “Caching” near the bottom of page 11.

    Mocking is still necessary in some cases, like where the production objects need to perform operations in a certain order. So maybe the best advice is, “Think twice when you find yourself using mock objects.” I find that the more DI code I write, the more I use functional programming idioms. Pure functional programs still have complex interactions but they typically do it in a way that could be tested without mocks. For example, suppose you write a class that configures a static logger. You could have that class produce a token, as a proof that configuration was performed. Then any classes that need the log configured can ask for that token as a dependency, rather than calling the log configurator directly.

  10. Vlad Dumitrescu

    Very nice written and explained!

    Do you happen to have any thoughts about using this with OSGi (or more precise with Eclipse plugins)? My first impulse is to use plugin scopes, but there is also the Eclipse platform with its tens of singletons and static stuff…

  11. Chad Parry Post author

    Vlad, the concept of Eclipse plugin scopes probably doesn’t overlap with the concept of DI scopes. I think that’s just an example of how the term has been overused. The plugin scopes contain static state, so hardcoded references to them would make testing difficult. You could use DI for developing a plugin though. Write your own scope and injector classes like in the DIY-DI manual. Then you can also write helper methods in the injector class to provide each of the static resources in the Eclipse plugin environment.

  12. Vlad Dumitrescu

    Thanks for the suggestions. An Eclipse application usually involves several plugins and this is where it feels tricky. I think that what I meant with ‘plugin scope’ is what you mean by “your own scope”. The conclusion, I suppose, is that it’s not trivial.

  13. JB

    In your PDF manual you say to make trivial doGet and doPost methods for a servlet implementation. I can see how those methods would construct a RequestScope object using the passed in HttpServletRequest and HttpServletResponse objects. I can see how to get a SessionScope from HttpServletRequest.getSession but how do I get my ApplicationScope object?

  14. Pingback: DCI Better with DI? | Petter's Blog

  15. Stephen

    I like the idea of framework-less DI–you might also check out:

    http://sonymathew.blogspot.com/2009/11/context-ioc-revisited-i-wrote-about.html

    Which doesn’t have as much static factory/glue methods, with the trade off of a per-class Context interface that is implemented by each app/request/etc. scope class.

    Personally, I’ve been doing cheap framework-less DI and just passing the ApplicationScope-style class directly to constructors. It is not as decoupled as DIY-DI, but works well, and typically means no glue code, and no providers, as objects have access directly to the ApplicationScope when they need it.

  16. Peter

    Thanks, this is a great article and I almost agree with all of it!

    Like Petter I do not completely agree with you on mock objects. When I think of a depedency graph the leaves will always be some kind of service (be it a webservice or any other I/O). So I definitely want to mock those services.

    But even if we’re not speaking of the leaves, but instead speak of some object anywhere in the dependency graph, I usually do not want to test these objects with all their dependencies down to the bottom, but instead inject mock objects after a certain layer. Three layers of dependecies usually pose enough complexity to be tested independently in a unit test. So I inject mocks below that layer.

    I’d be curious to hear your opinion on this.

    Thanks,
    Peter

  17. Chad Parry Post author

    Peter, I would also use mock objects in the scenarios you described. I agree that mocks will give you better testability than if your tests depended directly on un-mocked services. But–to go one step further–what if you could simplify your dependency so that your test didn’t need either a mock or an un-mocked service? For example, what if you could replace a dependency on a file system service with a simpler dependency on a POJO that contains file data? What if you could replace a dependency on an authentication service with a dependency on the Boolean value returned by such a service? Every time you are willing to refactor your production code to follow the Law of Demeter, you’ll find that you get more testability and you need fewer mock objects. (Look at the “Mock objects” section in the DIY-DI manual, which illustrates how a dependency on a service can be moved to the glue code where it won’t interfere with testing).

  18. Peter

    Thanks for your answer, Chad. I would like to pick up your example with the file system service and the POJO. Doing it this way means that you can read in the file (or at least open it) during the creation phase of your application (where you don’t/can’t unit test). This is true for things like config files etc. But I think it’s a very special case and not applicable in general. Whenever this is possible, I follow this rule though.

    Your suggestion also seems to imply that one should use a more procedural way of programming, because you first query for data and then pass it around. It would not follow the “Tell, don’t ask!” principle that is usually promoted in object-oriented programming. Would you agree?

    Having said that, I guess we roughly agree on the topic, I just don’t think that one can completely get rid of mock objects. And so I’m a little bit bothered by the sentence “Ideally a unit test won’t use any mocks or stubs or fakes or dummies”. Sometimes I want to test with a mock object if something was written to a database and I think a mock is a good way to do it.

  19. Chad Parry Post author

    Peter, for better or worse, DI leads you towards a more functional style of programming. Your typical service objects have one method and no persistent state. Your data is immutable. You don’t really follow all the OO patterns anymore, because they don’t fare as well when you are writing tests.

  20. WW

    Hi Chad,

    I commented previously on Misko’s blog. I wrote a non-trivial piece of code and I’m convinced the factory methods should not be static.

    In the simple case, our top level code then looks like this:

    Factory factory = new Factory( scope );
    Processor processor = factory.getProcessor();
    processor.process();

    We are working in a hosted-service environment and different customers want different things. Therefore, this code actually becomes:

    Factory factory = newFactoryForCustomer( customer, scope );
    Processor processor = factory.getProcessor();
    processor.process();

    Where newFactoryForCustomer() returns different instances depending on the customer. These instances extend a base factory. When a customer wants something special, we override an inject*() method in their specific factory.

    I also noticed that I ended up with alot of classes containing a constructor and a single method. Many of these ended up implementing Provider. I was comfortable with this because the coupling is very loose, and they are easy to replace with test doubles.

    Cheers,
    Will

  21. Chad Parry Post author

    @WW, mainly I’m glad that you found something that works for you. As far as I understand your plan, you start off with a static method invocation, “newFactoryForCustomer,” and then from there you invoke instance methods on the result. I like to do the same thing. I would probably write it, “Factory factory = injectFactory(applicationScope, customerScope);” but I think both accomplish the same thing. Thanks for sharing your technique.

    My code also ends up containing a lot of one-method classes. Sometimes I’m tempted to just make them static methods, so I don’t have to write boilerplate code for all the class’s fields. The only reason I don’t is so that the application will still be marginally testable if someone with a non-DI client tries to reuse my code. In a pure DI application, static methods can still be testable as long as they are only called from the glue code, not the business logic.

  22. WW

    >My code also ends up containing a lot of one-method classes. >Sometimes I’m tempted to just make them static methods, so I >don’t have to write boilerplate code for all the class’s
    >fields.

    I didn’t really understand that. I consider static an evil reserved for main(). Most of our business logic classes consist of a constructor (which just stores values in member variables) and a single method that does something. Our entity/value classes have a constructor and getters. Sometimes they have setters as well. The factory classes contain many protected inject*() methods. Nothing is static except where our code is invoked from externally.

    What type of class are you talking about that you would make static? Factory, entity or service?

  23. Chad Parry Post author

    Normally static methods are evil because the calling code becomes untestable. But what if the static is only called from the glue code? In that case, it only looks evil because we are trained to hate it, but it is perfectly safe. Instead of having a constructor that stores multiple arguments into fields, you could have have a static method that takes all those parameters directly. It would cut down on boilerplate code.

    It’s only safe to do that if the injector is calling the static method and giving the result to the application code. Specifically, you can’t do it if the class containing the static method were ever going to be injected into the application code itself. And you also can’t ever do it if you want interoperability with non-DI code, which is what usually dissuades me.

    Let me know if my thinking on this seems unclear, and I could put together a code sample.

  24. WW

    If you end up nesting scopes within each other, your static injector code may unusable from the outer scope. I don’t trust myself to predict the future, and whenever you use static you are saying you’re only ever going to use it like that. Hence, you only use it when forced to by the calling code (including the JVM).

    I know you’ve said the injector code is untestable, but I do have tests where the object under test is provided to me by the factory. In this case, I sometimes extend the factory with an anonymous class from the test and override inject methods to use as test doubles.

    PS. If you haven’t seen the New Zealand move Black Sheep, you should watch it, it’s a classic.

  25. Pingback: Dependency Injection | Mathieu ROIG - Portfolio

  26. Joel

    Chad,

    Despite your lucid explanation, I am unclear on where to place initialization logic that is more complex than your positional arguments example.

    Let’s say that some business class constructors need an open database connection, among other things. I think that the database connection belongs in the application scope (in a small batch program).

    A configuration file contains the detail of the database connection: username, password, host, port, etc. The configuration file also contains other information needed by the program.

    In the Unix tradition, the configuration file may be specified by a command line argument, located in the user’s home directory, or located in some common location.

    Value object scopes, trivial constructors, and glue code injectors do not seem to provide a place for the logic needed to locate, read, and validate the configuration file; and to open the database connection.

    Please enlighten me.

  27. Denis

    Hi Chad.

    As other readers noted, i found your presentation and articles are to be one of the most coherent and complete introductions on how to transform a ‘legacy’ code to be more testable and how dependency injection pattern is useful for such a purpose.

    I believe by providing the more complete example to the most other which are found around a web, especially showing how to actually separate the glue (creation) of objects from logic.

    yet, like a few other readers who commented here and over at Misko’s page, i am finding the static methods inside the injector a bit discombobulating… Even though discussions about Providers/ScopeCache etc are more than helpful. I understand that it is from your extensive experience you are suggesting to use this technique and to rely on the fact that the glue code doesn’t need to be unit tested due to its simplicity…

    I feel that if you would have provided actual examples of how you would implement the tests for different classes it would help to reduce some ambiguity and doubts???

    also if you could have had explored the non-static Injector and got into more details comparing both approaches???

    I am trying to apply DI for examples in other languages: mostly C++ and Python, i wonder if you have ever thought of how the structure you presented would be different in C++… I was wondering if the Providers would be subtly different… even if we disregard that in C++ additional complexity is presented due to the intended design ambiguity of who owns a particular instance (whether inject would return pointer, shared pointer or scoped pointer, etc).

  28. Rodion

    Hi Chad,

    I’m writing to thank you for this article as it helped me to move from “I know principles of TDD but don’t know how to apply them to the monstrous legacy codebase” to effective usage of unit tests in my code. DYI-DI was like a missing bridge between theory and practice.

  29. home biased

    It’s a shame you don’t have a donate button! I’d definitely donate
    to this excellent blog! I guess for now i’ll settle for bookmarking and
    adding your RSS feed to my Google account.

    I look forward to brand new updates and will talk about this site with my Facebook group.
    Talk soon!

Leave a Reply

Your email address will not be published.