Hello Allan,

    the others have explained many aspects of DI (as I understand it 
myself) but let me add something more about it.

First of all the DI or IOC pattern is around for a decade now. I came into 
contact with DI around 2002 or 2003 in conjunction with the Spring 
Framework. Martin fowler has some very informative articles around 
Dependency Injection (http://martinfowler.com/articles/injection.html from 
2004). 

You have in general three choices when it comes to objects (instances) your 
own object depends on. 

1. Your object can construct them itself.
2. Your object can pull them in itself (DependingObject.getInstance(), 
ServiceLocator.findObject("DependingObjectAddress") etc.)
3. The dependencies are pushed into your object using constructor or setter 
methods or fields.

This push and pull is the same as in Web Frameworks for instance. There are 
the MVC frameworks where the Controller constructs the Model that is pushed 
into the view to render and there are those component based web frameworks 
(Tapestry, Grails, Rails etc.) where the Components use Services to request 
(the pull) Model information.

So Guice is all about the push but can be used for the pull to by using 
Injector.getXXX(Key).

The main reason why I use IOC-container like Guice is that they provide a 
single point to manage the constructing of those dependencies. You split up 
everything in modules. You declare how and when your objects (services, 
singletons etc) are build. And also you have different scopes and custom 
annotation support. This all and of cause the raw speed (15ms for warm 
start) is a dream to work with. I used Tapestry IOC for years now and it 
was good beside this slow startup times (4+ seconds and 500ms for each 
test) and this interface proxy behaviour. 

*2)* Unless you need information from the outside of your object this 
simple creation of DateRange or Point or alike should be done by the object 
itself. Dependency injection shines when you need to manage your 
dependencies for reuse. Also it is good when you want to limit the 
'knowledge' of your object. You know the principle of describing (using) 
objects as abstract abstract as possible but implement them as concrete as 
possible (I can not rephrase the right rule of thumb, maybe the others 
can). Dependency injection is a way to keep knowledge out of your object.

A good example might be the web framework since it might be common 
knowledge. In a web framework we have requests that lead to a responses. 
Those requests come with request parameters. Those parameters are available 
from within the request object being provided by the Servlet container. So 
your object may receive the Request object by its constructor or when its  
service method is called. Now your object accesses that request object and 
gets the parameters it is looking for. Now you have some parameters that 
must be present since your object should be only invoked if the request 
path and parameters are in place for it to do its work. Since you want to 
fail fast here, you add some checks that those parameters are present and 
if not the code fails with an appropriate exception.

Now you have 20 such objects being actually components (small parts) of 
your web page. Every object is doing the same. So we just extract a common 
abstract parent class that does provide the code for checking and getting 
those parameters. This way we follow the DRY principle and avoided lots of 
code duplication. This design is well but also stiff. 

Every time we want to add another source of information to our components 
we have to add this functionality to the abstract base class those classes 
extend. 

With dependency injection we just add a custom annotation support for each 
of those sources. In a web framework your component might receive 
information from component parameters (specified by the parent's template), 
request parameters, path parameters, model attributes, parent component / 
page properties, even databases, configuration etc. 

Adding this all makes everything even more stiff. You can not add another 
aspect like security, database (session for instance) etc that easily to 
your component. With Guice you just wrote yet another custom annotation. 
Having @Parameter, @Property, @RequestParameter, @Model, 
@ComponentParameter @Inject etc. makes it easy. Adding the @Required 
annotation let your custom member injectors fail with exception if the 
parameter/model etc is not available for injection.

You see with dendency injection you remove the required knowledge and make 
it plugable enabling you to write more modular and therefore easier to test 
software.

*3) *About your third point. Sure there is something to it. But what you 
describe is defensive programming. I was into it also but today I consider 
a too defensive programming style to be harmful in terms of flexibility and 
also the way I think about a certain design. Often it feels stiff and 
narrowed (something like focused but with a negative touch). My defensive 
programming style was quite extreme around 2003 where those state vs 
behaviour testing war raged. I used Mocks to even test interaction between 
objects those days, I used fail fast (Assert.notNull etc) and such.

This has all changed. Since jUnit hit the streets I do software testing. 
Since at least 10 years I do test-first with great joy. So if I write 
software for inhouse or own projects where I am (or persons who share my 
knowledge about the software) are in fact the end user, I do not use much 
defensive programming. I also do not test extensively in terms of doing 
white box testing that much trying to catch every potential path that might 
lead to a bug or misuse. The more I learned how and where test works and 
where are the usually pitfalls, I am quite relaxed when it comes to defect 
detection. 

Also even if I spot a bug I do not correct it unless I face it in a failing 
test case or it is harmful. If the defect is obvious or I am certain I will 
see it again when the time is correct, I just let it be. Often I corrected 
defects and possibilities and downstream the whole stuff was refactored out 
or even rewritten becoming different. That might be curious but its what it 
is. 

If you change a defect to early you drive your code in a certain direction 
that I would have not done if I have not spotted the defect by accident. I 
just accept that I write defect software and that I can rely on the test 
suite and the way I write my tests (and others here too) make it high 
quality and almost defect free and it is more value to have code evolving 
freely along with the tests necessary at the moment.

So if you can rethink about defensive design. Defensive design has its 
merits when you design a library for broad usage where you do not want your 
user to dive into the code and familiarize with its inner working. But if 
you work on code where you want your users to understand whats going on, 
just do not fail fast. It is a necessary learning experience that is not 
harmful if you have a test suite at hand you can use to check the actual 
behaviour of a class. And of cause I do defensive coding from time to time 
where it is appropriate but it is just a principle I use and not a first 
class design goal.


Am Montag, 11. November 2013 16:03:56 UTC+1 schrieb Alan Darkworld:
>
> 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.
>
>
> *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.
>
>
> *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 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).
>
>
> 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].
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