As Sam mentioned. It is absolutely possible (and my prefered way) to inject all dependencies into the constructor. This way the class can easily be created without DI in a unit test. And take a look at assisted injection.

On 11/11/2013 04:35 PM, Sam Berlin wrote:
Hi Alan,  some thoughts inline below.



On Mon, Nov 11, 2013 at 10:03 AM, Alan Darkworld <[email protected] <mailto:[email protected]>> wrote:

    Hello everyone,

    I've been working with Java for several years now and I'm always
    open for new ideas to improve code quality. But I do have some
    serious doubts about dependency injection (more on that later).
    However, as large frameworks such as Eclipse 4 and Xtext employ it
    successfully, I'm trying to get used to this new idiom. When
    walking through some tutorials, several questions appeared:


    *1)* The Injector becomes a sort of "main static factory" for the
    entire application. However, Guice does not instance-control the
    injector - in other words, Injector#getInstance is not static. How
    do you share your injector across all classes in your application
    such that it's easy to access? The easiest thing I can think of is
    to create it once at the start of the program and then make it
    available through a static field, but that just doesn't feel
    "right" to me.


This isn't really the right angle. This line of thought is more akin to non-DI programming -- where you have a single static "service locator", and other pieces of code call out to that locator and ask for objects. That isn't what DI is about. DI is about ensuring that your objects only care about exactly what they need and nothing more. No dependencies on this big "whale" objects. You construct your injector and get the "entry point" of your application (e.g, something like MyApp.class), and MyApp has its dependencies injected, its dependencies have theirs injected, etc... recursively all the way down. No class ever needs to look back at the Injector, because the Injector has already figured out each specific dependency and knows how to create the class properly.

(There are, of course, some advanced use-cases where you may need the Injector... but those are typically for extension-like circumstances, and not in common usages. In those cases, you simply list the Injector as another dependency and it will inject itself. No statics required.)


    *2)* I can see that DI is handy if all objects have no-argument
    default constructors. But most of the time, this is not the case,
    especially with immutable objects that need to check their
    invariants in their constructor. Consider for example an immutable
    "DateRange" class with the invariant "start date < end date". The
    only valid constructor for this class has two parameters (the
    dates), yielding a client code like:

    long start = calculateStart(); // calculates the start time based
    on user input (result is dynamic)
    long end = calculateEnd();  // calculates end time based on user
    input (result is dynamic)
    DateRange period = new DateRange(start, end); // throws
    IllegalArgumentException if start > end), need to replace this
    line by Depencency Injection

    How would something like this translate into the Dependency
    Injection idiom? I can clearly see DI working for the Java Beans
    pattern, but what about the immutable case? I've had a look at the
    Guice Documentation, but I couldn't spot an answer to this.


Simple bean-like classes like DateRange aren't things that should be injected. Those are just simple data classes. There's no need to get fancy and do anything with dependency injection there. DI is more useful when there's actual dependencies -- "start"/"end" and other user-supplied parameters aren't things that are injected. If the entire class is made up of user-supplied values, then it isn't something DI should handle.

I'm not sure where you found that DI is useful for no-args constructs. DI isn't very useful there. DI is useful when you have constructors that take system-supplied arguments (e.g, ExperimentManager depends on ActiveExperiments and RpcSystem).

(And again, there are cases where you may have an object that depends on some mix of user-supplied & system-supplied values. For those cases, there's an extension called AssistedInject <https://code.google.com/p/google-guice/wiki/AssistedInject>... but that's more advanced usage.)



    *3)* For many years, several books (including the excellent
    "/Effective Java/") have gone to great lenghts explaining how to
    keep our class invariants safe from both malicious access and
    careless programmers (including client use and subclassing). By
    applying DI, we forfeit the control over our fields, we give up on
    encapsulation. From my point of view, with DI the focus has
    shifted from "/This class will work, no matter how much you
    mistreat it/" to "/It works if you treat it right, otherwise it's
    your own fault/". What implications does that have for software
    quality? We sure gain a lot in terms of configurability (create a
    new subclass, introduce it in the module and you're all set), but
    what do we lose with respect to safety and contracts? This is
    actually my main concern about DI and the very reason why I can't
    yet wrap my head around it. Can somebody provide a reason why my
    concerns are without cause? Please do!


I'm not sure what leads you to that conclusion. You can still easily check invariants with DI. In fact, it's easier to check with DI because, by injecting your dependencies, your class is stating upfront: I care about <this>, and <that>. With a service locator pattern, it instead either says nothing or says: I care about <something that may be inside that that>. So your tests don't know exactly how to construct it, and casual readers of the code have to analyze the entire class for usage instead of just looking at the constructor.


    I do have some more concerns about DI, but the three stated above
    are the ones which really prevent me from getting into it. I'd be
    grateful if someone could explain how to do it the right way (for
    1 and 2), or why I'm wrong (for 3).


Have you watched the video <https://www.youtube.com/watch?v=hBVJbzAagfs>on the Guice front page? Bob & Dhanji do a very good job of explaining how it works.

sam



    Thanks,


    Alan
-- You received this message because you are subscribed to the Google
    Groups "google-guice" group.
    To unsubscribe from this group and stop receiving emails from it,
    send an email to [email protected]
    <mailto:google-guice%[email protected]>.
    To post to this group, send email to [email protected]
    <mailto:[email protected]>.
    Visit this group at http://groups.google.com/group/google-guice.
    For more options, visit https://groups.google.com/groups/opt_out.


--
You received this message because you are subscribed to the Google Groups "google-guice" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice.
For more options, visit https://groups.google.com/groups/opt_out.

--
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to