Great stuff.

Great stuff.
http://www.loosecouplings.com/2011/01/dependency-injection-using-di-container.html

Comments

  1. but not for delphier,atlease not now

    ReplyDelete
  2. Nick Hodges I've read everything out there about the service locator being an anti-pattern and there's still something I don't quite get.  I have a feeling this could turn into a long debate, but let's start here... why is using InjectConstructor better than, say, passing the dependency into the constructor as a parameter and using the [inject] attribute so that Spring resolves the dependency for you?  I would also apply this question to DI frameworks that bind dependencies via external configuration.  I would expect most people that are anti-DI frameworks dislike it because the lack of dependencies can blow up at run time if the dependency isn't registered with the container, but the same would happen with the example in your blog.  If you fail to call InjectConstructor, you'll still be missing the dependency.  So what did you gain?

    ReplyDelete
  3. Constructors shouldn't have parameters.

    ReplyDelete
  4. Well that rules out constructor injection, eh?

    ReplyDelete
  5. Well, they can - but they shouldn't. Bad for class hierarchies.

    ReplyDelete
  6. How do you handle dependencies then?

    ReplyDelete
  7. Create, then inject - f.x. by using factory methods.

    ReplyDelete
  8. So for each class with dependencies you have a special use factory that knows how to compose it's dependencies?

    ReplyDelete
  9. Lars -- sorry, but the notion that constructors shouldn't have parameters is........nuts.

    ReplyDelete
  10. Nick Hodges still waiting on a reply to my original question :-)

    ReplyDelete
  11. I'll get you, don't worry.  Right now, it's NBA time!

    ReplyDelete
  12. Nick Hodges haha, no worries, any touchdowns yet? :-)

    ReplyDelete
  13. NBA?  Pfft.  Try the NHL instead :)

    ReplyDelete
  14. Lars Fosdal Sorry... but NO. Constructor injection should be favoured over property injection at least for those dependencies that are not optional. Also regardless DI container or not you should write your code in a way you can still do "poor mans DI" (aka manual DI).

    Ron Lawrence InjectConstructor is just another way of specifying constructor injection which you can also do by specifying the Inject attribute or letting the DI container look for the most satisfying constructor.

    ReplyDelete
  15. Stefan Glienke - Why favour constructor injection?  I've always been drilled that parameterless constructors are the "one true way".

    ReplyDelete
  16. If its a required property, an assert will do the trick in a Getter.  If you want to prevent changing the property after initial initialization, you check in the Setter if the property is already assigned.  IMO, having a parameterized Create can be an issue in a polymorphic class hierarchy.  It will require a descendent class to know the DI type, which otherwise could have been completely hidden.  But - no rule without exception - whatever works.

    ReplyDelete
  17. I find that dependency abstraction is very interesting topic and there's so many opinions out there.  I asked Nick Hodges the original question because when it comes down to it, I'm not seeing the terrible downsides to the service locator pattern that you don't get by using injection via a DI framework.  The biggest complaint I hear and read about the service locator pattern is that the class "API" is unclear, and the consumer of the class can't easily tell which dependencies are baked into the class he is consuming.  I can buy that constructor injection helps this a bit, in that you can view the signature of the constructor for the dependencies.  That's all well and good, I don't know if that makes the service locator pattern the spawn of the devil, but sure, using injection via the constructor is a bit better.  The other argument I hear against the service locator pattern is that the DI framework will often blow up at runtime if the dependency cannot be resolved.  I get that too, but I'm yet to see a DI framework that solves that.  Regardless of using a service locator, inject attribute or external binding.  

    So in the end is the service locator really as evil as the cool kids want to call it?  I don't think so.  And nobody has yet convinced me of that.  

    PS Lars Fosdal , I'm still trying to understand how your factory method of injection works.  It's not clear to me if you're advocating a factory per composition?  And, how are you removing the factory dependency from the class that needs the composition?  You're surely not asking a factory for the factory.  You're surely not advocating a factory and can compose everything and you're surely not passing all your factories from the root of the application.  

    PPS, so far IME, using constructor injection with a DI framework appears to be the best way to manage dependencies.  You get the benefit of the dependencies being pretty clear, you get the benefit of not having to "manually" resolve your dependencies and the only downside I can think of would be missing dependencies... but we've solved that in my shop, so it's a non issue for us.

    ReplyDelete
  18. Ron Lawrence If you are using a service locator you are basically just cloaking a constructor call and trading the strong reference to the class you are constructing for the strong dependency on your service locator.

    Using a service locator is violating the LoD because let's face it you either use the service locator as singleton (singletons are bad, hmkay!?) or are passing in the service locator as a dependency and then why not simply pass the dependency itself (or a factory incase you need lazy initialization)

    I am not saying there are no scenarios where a service locator might be the way to go. In legacy code you simply cannot switch everything to be perfectly designed in a complete DI way. In that case a service locator is a nice way to plug in DI into existing code without changing that code to much.

    For more information see:
    http://misko.hevery.com/2008/07/30/top-10-things-which-make-your-code-hard-to-test/

    ReplyDelete
  19. Ron --

    To answer your original question, Constructor injection is preferable in all cases.  And it is preferable to use the Container (NOT the Service Locator, they aren't the same thing.....) to ensure the creation of those dependencies, either by calls to InjectConstructor or use of the [Inject] attribute.

    Put another way, you should be able to replace all the calls to ServiceLocator with an [Inject] attribute somewhere.

    I remember that the GTS Codebase had a lot of this in it:

    procedure TMyClass.BlahBlah;
    var
      Thing: IThing;
    begin
      Thing := ServiceLocator.GetService;
      Thing.DoThat;
    end;

    And as Stefan says, that is really a glorified call to Create, and is almost hard coding the dependency.  You can put a name in there to make it more flexible, but in reality, the IThing instance ought to be passed into the class via the constructor and stored appropriately. 

    In that way, you'll be using Constructor Injection almost everywhere, and then the Container will do all your creating for you way back at the beginning of the program.

    Does that answer your question?

    ReplyDelete
  20. Nick Hodges I understand what you're saying, I guess I'm not seeing the evil of the service locator vs the inject attribute.  Both tie you to something.   Both in essence hand you the wallet.  The only difference I'm seeing is that injecting via the constructor (and the inject attribute) make it more clear which dependencies are being injected, whereas using the service locator requires some digging.  So why is the dependency on the global container better than a dependency on a service locator?

    PS, I miss being able to yell these conversations across the hall!

    ReplyDelete
  21. Stefan Glienke do you inject the dependencies into the constructor via a DI framework?

    ReplyDelete
  22. Ron --

    (Just pretend I'm yelling....)

    The dependency on the container is very thin and exists only at the root of the application (in the DPR file for Delphi folks).  You can construct your entire application with only the single reference to the container if you use "Poor man's" constructor injection everywhere and then reference the container at the root.

    The container creates the graph completely away from your code, and you don't have to depend on the ServiceLocator, and the dependency on the container is basically behind the scenes and not part of the code proper.

    ReplyDelete
  23. Nick Hodges  was going to give you a hard time until I got to the end of your reply.  Having [inject] in front of all your constructors still very much ties you to the framework - one can argue just as much as the service locator does. But, those details are slightly more hidden using that method of injection vs writing the code to resolve the service.  I agree there.  

    In the end, I agree with constructor injection via Spring - I'm mostly giving you a hard time because I don't think the service locator is as evil as some say.  Maybe that's because I look at 3+ million lines of code daily with dependencies baked right into everything, so when I see a service locator call, I think to myself 'wewwww, at least I can mock that thing".

    ReplyDelete
  24. Ron Lawrence No offense but I wonder if you actually read the article Nick linked because there it explains that actually for your code there is not a single difference if you are using manual dependency injection or a DI container and that is infact the ultimate goal (the underlined parts). A DI container is just a tool to save you from manually writing tons of wiring up code.

    The Spring DI container does not require any additional code to your classes. It can work perfectly fine without any attribute because it will find the most satisfying constructor on its own. However attributes are just part of the RTTI and thus metainformation that the container can use. And that is the reason why I suggest not to inject things that cannot be injected manually (you can inject private fields with the container f.i.)

    "when I see a service locator call, I think to myself 'wewwww, at least I can mock that thing"

    As I said previously. A service locator might be an improvement to spaghetti code because you have a certain entry point to manipulate things - i.e. mock them. But in that case you actually have to mock the service locator to return a mock because actually the service locator is just the deliveryman for the piece you really want. If you are following Misko Heverys guide on how to write clean code you will find out that it still is bad code if you need to mock something to return a mock. Because you could have injected that thing in the first place without having that hardcoded deliveryman. And then you could have just injected a mock without any additional work.

    It is a process to change the way of thinking about software architecture but once you got that you will see how easy these pieces become - and I am not talking about heavily overengineered frameworks some people fear when someone talks about design patterns and software practices.

    ReplyDelete
  25. Stefan Glienke I have to admit, I can't follow most of what you're trying to say.  First, I did read Nick's blog post.  Second, using the inject attribute does tie you to Spring (or something else that implements the attribute), and third, you don't have to mock a service locator to mock the contents of it.  All these things are so obvious to me I'm not even sure where the disconnect is.

    ReplyDelete
  26. Ron Lawrence I guess we are talking about different things. I am referring to the post on loosecouplings.com Nick linked above and not about the post on his own blog. Again: the Inject attribute is not needed to do constructor injection with the spring4d container. But if you specify it you of course have a dependency (not to the container though but to the Spring.Services unit the attribute is specified in).
    And yes: if you have something A that returns something B and you want to mock B you first have to mock A to return a mock for B. (see http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf - "Flaw: Digging into Collaborators")

    ReplyDelete

Post a Comment