Dead horse, meet flog

閲覧: 40 回
最初の未読メッセージにスキップ

Hani Suleiman

未読、
2007/03/21 19:31:532007/03/21
To: google...@googlegroups.com
I think this has been raised before, and I know that eventually this would
be doable via postprocessors and whatnot, but I do think this is useful
enough to merit discussing having it be in core (or default behaviour).

From the user's guide, I can use annotatedWith to specify what I'd like
injected based on my own annotations. This is a great and wonderful thing.

The problem is that I still need to specify @Inject, and the question
is...why? I've already created a custom annotation, the annotation already
is bound in my module, so I know when and where it'd be used, and that
usage will always be an injection. So why the duplication?

So my proposal is to not require @Inject on custom annotations. Thoughts?


Kevin Bourrillion

未読、
2007/03/21 19:57:032007/03/21
To: google...@googlegroups.com
Hello,

I remember when Bob and I discussed this.  First off, it's not always entirely clear-cut, as your custom binding annotation might be only on parameter 5 of 7; it's the whole constructor/method that needs to be injected, so @Inject belongs on the whole thing.

True, for field injection this is not the case.  But field injection is surely the crappiest of the three so who cares? :-)

Then there's the deeper issue.  Scanning blogs and this list, I know that it's an issue that not everyone really understands right now.  But Bob and I both felt that it's important to minimize the amount of naked "magic" that happens in a guice application.  People should be able to look at their code and understand what's going to happen.  Now the members of your class can be annotated with all manner of things, from @Override to @Transactional to @SuppressWarnings to @GuardedBy to @ReadOnly, etc. etc.  If your binding annotation were enough to make the member be injected, how would a typical developer coming across your code have any idea which are the injection points in it?  I remember Bob and I discussing this and deciding it's cleanest to have @Inject clearly labelling every injection point.

@Inject is *explicit*.  That's its whole reason for existing, and in my own project, I love it.

K

Dhanji R. Prasanna

未読、
2007/03/21 20:32:032007/03/21
To: google...@googlegroups.com
On 3/22/07, Hani Suleiman <ha...@formicary.net> wrote:


The problem is that I still need to specify @Inject, and the question
is...why?

It is self-documenting and clear that a field or parameter is injected by guice (without having to follow an arbitray number of custom annotations to look for @BindingAnnotation). I think that's useful. When there are several annotations on my fields, guice @Inject is easily evident--it is significant enough that I would want this to be a requisite behavior.

I've already created a custom annotation, the annotation already
is bound in my module, so I know when and where it'd be used, and that
usage will always be an injection. So why the duplication?

This is very persuasive. The only other possibility is if I wanted to share those custom annotations with some other semantic. Not sure if that is considered an abuse of @BindingAnnotation--perhaps if that could be made clear in documentation, the duplication argument would gain strength.


How about making @Inject optionally explicit? i.e.:

module.setInjectOptionExplicit(false);    //does not force @Inject

Hani Suleiman

未読、
2007/03/21 21:10:172007/03/21
To: google...@googlegroups.com
Kevin Bourrillion said:
> Hello,
>
> I remember when Bob and I discussed this. First off, it's not always
> entirely clear-cut, as your custom binding annotation might be only on
> parameter 5 of 7; it's the whole constructor/method that needs to be
> injected, so @Inject belongs on the whole thing.
>
Yes, and in this case, I'd use the whole thing.

> True, for field injection this is not the case. But field injection is
> surely the crappiest of the three so who cares? :-)
>

It's also not true for single param method injection, where most people
are likely to place the parameter on the method and not on the parameter.

> both felt that it's important to minimize the amount of naked "magic" that
> happens in a guice application. People should be able to look at their
> code
> and understand what's going to happen. Now the members of your class can
> be
> annotated with all manner of things, from @Override to @Transactional to
> @SuppressWarnings to @GuardedBy to @ReadOnly, etc. etc. If your binding
> annotation were enough to make the member be injected, how would a typical
> developer coming across your code have any idea which are the injection
> points in it?

Because in this case it's *my* annotation. It's not a random one I'm
getting from someone, it's my own, I defined it and so just as I know what
a PoopooManager does, I know what this custom annotation is. I'd say that
this is more verbose than it should be:

@Transactional
@SuppressWarnings
@Inject
@Blue
public void setWibble(...)

> I remember Bob and I discussing this and deciding it's
> cleanest to have @Inject clearly labelling every injection point.
>
> @Inject is *explicit*. That's its whole reason for existing, and in my
> own
> project, I love it.
>

This argument only works if you never want to write apps or frameworks for
other people. Using @Inject is great and perfect for 'final' code, for
anyone who writes libraries that need to be reused, using a hard
dependency on guice is not a sensible option. Nobody wants to add a hard
dependency just to support guice, but everyone wants to be able to support
it for end users who find it appealing.

Anyway, Bob assures me that all this stuff will be possible with the post
processor stuff in 1.1, so if that works as hoped then it'd take care of
this use case.

Ben

未読、
2007/03/21 22:04:302007/03/21
To: google...@googlegroups.com
Removing hard dependency on Guice would be very nice. But I think it is not just annotatedWith. In fact, I feel one should be able to use @Resource or whatever annotation (or even naming convention like setter injection)  to control the injection point.

And that should be as easy as a MemberPredicate interface:
interface MemberPredicate {
  boolean isInjectable(Member member);
}
@Inject, @Resource, @MyInject or even custom naming convention can all be just implementations of MemberPredicate.


On 3/21/07, Hani Suleiman <ha...@formicary.net> wrote:

Gregory Kick

未読、
2007/03/22 15:42:172007/03/22
To: google...@googlegroups.com
There seem to be a few different issues and a few different threads
that all seem to espouse this belief that guice should be infinitely
flexible in how and where it performs injection. Ben wants a
pick-your-own injection point mechanism and Stephen from the other
thread can't figure out how @Inect "reached 1.0 without you guys
seeing it as a problem." Do we really want to go down this road?
While it's one thing for Hani to argue against redundancy (not that I
mind the extra @Inject from time to time), it's another to remove so
much of the form that you end up with some amorphous blob of injection
for which you have to hunt for the class has decided to inject an
object when the third letter of a given method is capitalized. If I
wanted to spend that much time figuring out where things were being
injected, I'd go back to reading Spring config files. And yeah,
that's an overreaction, but I spend enough time reading other people's
code to know that I'd much rather see *everybody's* unambiguous
annotation than *their* unfamiliar convention even if we have to
sacrifice an extra @ to the god of verbosity and an import to the god
of conformity.

Ben

未読、
2007/03/22 16:35:212007/03/22
To: google...@googlegroups.com
I think the maintainability issue is overstated.

On one hand, when I'm reading a class designed with dependency injection (DI), I'm not bothered for not seeing "how it is injected in the bootstrap process" from the source code of that class. Why do I care? And I call that "separation of concern". --- I'm not saying that requiring a @Inject is a sin, but not requiring it is definitely not a bad thing.

On the other hand, when looking at the bootstrap code (spring xml file, Guice module, plan old java factory), I do care that everything happening should be visible to me (meaning, no invisible magic please). I love Guice for its static typed, simple bootstrap code, not for the @Inject spell all over the component classes.

So what I don't get is, how is the following Guice module code confusing at all?

//use default @Inject.
bind(Interface1.class).to(Impl1.class);
//use @Resource for java EE 5 entity classes that we don't want to bother adding @Inject to them.
bind(Interface2.class).to(Impl2.class).withAnnotation(Resource.class);
//use setter injection for any pojo
bind(Interface3.class).to(Impl3.class).injectedBy(new SetterInjection());

Could I please ask for a concrete use case where this "infinite" flexibility is used in a reasonable way but still causes confusion?

It's true that anything can be abused. But stopping people from doing useful things in fear of it might be abused with some crazy hack? I'm sure if that should be the rationale.

Gregory Kick

未読、
2007/03/22 22:30:212007/03/22
To: google...@googlegroups.com
On 3/23/07, Ben <ajoo....@gmail.com> wrote:
> I think the maintainability issue is overstated.
>
> On one hand, when I'm reading a class designed with dependency injection
> (DI), I'm not bothered for not seeing "how it is injected in the bootstrap
> process" from the source code of that class. Why do I care? And I call that
> "separation of concern". --- I'm not saying that requiring a @Inject is a
> sin, but not requiring it is definitely not a bad thing.

I'd say that not requiring it is a bad thing. You're right that you
don't care how something is injected, but you most certainly would be
concerned with what is being injected. You don't run into the issue
too much with constructor and setter injection, but when I look at a
class I should be able to tell the difference between methods for
injection and just plain methods.

There's also a bit of a usage contract written when you design for DI.
This obviously doesn't apply to constructor injection, but in every
other case, @Inject says that my class expects that these things are
set via whichever methods in order to be ready for use. Otherwise,
how do you tell the difference between any random property and a
dependency? Go back to the module and figure it out?

>
> On the other hand, when looking at the bootstrap code (spring xml file,
> Guice module, plan old java factory), I do care that everything happening
> should be visible to me (meaning, no invisible magic please). I love Guice
> for its static typed, simple bootstrap code, not for the @Inject spell all
> over the component classes.
>
> So what I don't get is, how is the following Guice module code confusing at
> all?
>
> //use default @Inject.
> bind(Interface1.class).to(Impl1.class);
> //use @Resource for java EE 5 entity classes that we don't want to bother
> adding @Inject to them.
> bind(Interface2.class).to(Impl2.class).withAnnotation(Resource.class);
> //use setter injection for any pojo
> bind(Interface3.class).to(Impl3.class).injectedBy(new SetterInjection());
>
> Could I please ask for a concrete use case where this "infinite" flexibility
> is used in a reasonable way but still causes confusion?

it's once you get into the whole injectedBy part. yeah, we can all
figure out setter injection, but what happens when somebody decides to
make a new form of injection named CustomInjection that applies a
regex to method names? How long am I going to spend trying to figure
out where it gets applied? How long until some stray method
accidentally matches? What about conflicts? Isn't this an open
invitation for nondeterministic modules?

>
> It's true that anything can be abused. But stopping people from doing useful
> things in fear of it might be abused with some crazy hack? I'm sure if that
> should be the rationale.

My point isn't that the world is going to come crashing down if it
gets opened up to something like this. I think that the people having
this conversation are all pretty capable of using something like this
without too many ill effects. Unfortunately, I don't think it has to
be a "crazy hack" to end up not behaving the way it was intended and I
don't see it as a solution that will work well without either serious
forethought or debugging. It's a pessimistic view, but an injection
mechanism that, by design, doesn't have expected behavior is pretty
difficult to predict.

Plus, Guice has wonderfully clear error messages that point to exactly
what the problem is most of the time. How specific can you be about
how to solve a problem when you didn't create it?

Ben

未読、
2007/03/22 23:44:272007/03/22
To: google...@googlegroups.com


I'd say that not requiring it is a bad thing.  You're right that you
don't care how something is injected, but you most certainly would be
concerned with what is being injected.  You don't run into the issue
too much with constructor and setter injection, but when I look at a
class I should be able to tell the difference between methods for
injection and just plain methods.

How many times do you use an "any method" injection? To me, most of the time ctor injection is good enough.
And even if I do inject by method, the method name and javadoc usually serves better than an annotation.

init(Service serivce) clearly speaks for its purpose. I do not need an annotation to remind me what it is. We've been writing code all the time without annotations, and I never feel a need for a special annotation to serve as a documentation.

it's once you get into the whole injectedBy part.  yeah, we can all
figure out setter injection, but what happens when somebody decides to
make a new form of injection named CustomInjection that applies a
regex to method names?  How long am I going to spend trying to figure
out where it gets applied?  How long until some stray method
accidentally matches?  What about conflicts?  Isn't this an open
invitation for nondeterministic modules?

Are you saying that Guice should be created to stop people from doing all kinds of stupid things?
What about Guice complain about somebody using a "xyz123" as a method name? What about forbidding a method with more than 1000 lines of code?
What about Guice checking the Provider implementation to make sure it does not use regex or base64 to obfuscate the code? Or as Provider potentially gives programmer ability to shoot themselves, we 'd better off just removing it from Guice?
What about checking the user Module so that it is not created with some fancy reflection code and class loader tricks that will be nightmare to maintenance?

Also, doesn't bind(A.class).to(AImpl.class).injectBy(new CustomInjection()) tell you where it gets applied?

My experience so far, has been that advanced features of a framework are most of the time ignored by programmers. And when they are used, they are used by experts who know what they are doing.


My point isn't that the world is going to come crashing down if it
gets opened up to something like this.  I think that the people having
this conversation are all pretty capable of using something like this
without too many ill effects.  Unfortunately, I don't think it has to
be a "crazy hack" to end up not behaving the way it was intended and I
don't see it as a solution that will work well without either serious
forethought or debugging.  It's a pessimistic view, but an injection
mechanism that, by design, doesn't have expected behavior is pretty
difficult to predict.

And that's exactly what I want to see. A "not crazy hack" that can end up as a tragedy. As I can tell, we are most of the time use case driven. So it'd be very helpful if other than wild imagination, a real use case can be given to support the pessimisticism.


Dhanji R. Prasanna

未読、
2007/03/23 0:03:132007/03/23
To: google...@googlegroups.com
On 3/23/07, Ben <ajoo....@gmail.com> wrote:


How many times do you use an "any method" injection? To me, most of the time ctor injection is good enough.
And even if I do inject by method, the method name and javadoc usually serves better than an annotation.

init(Service serivce) clearly speaks for its purpose. I do not need an annotation to remind me what it is. We've been writing code all the time without annotations, and I never feel a need for a special annotation to serve as a documentation.

These are all your preferences, surely you dont mandate them on the rest of us at the sacrifice of type-safe, self-documenting metadata? ;)


Are you saying that Guice should be created to stop people from doing all kinds of stupid things?
What about Guice complain about somebody using a "xyz123" as a method name? What about forbidding a method with more than 1000 lines of code?
What about Guice checking the Provider implementation to make sure it does not use regex or base64 to obfuscate the code? Or as Provider potentially gives programmer ability to shoot themselves, we 'd better off just removing it from Guice?

Absolutely it should stop people from doing stupid things in its domain as far as is possible. For methods withs funky names and improper formatting there are other domain toolkits like checkstyle. If provider can be restricted in some way to prevent stupid things happening (such as returning any Object) then it should. That's why it's parameterized!

What about checking the user Module so that it is not created with some fancy reflection code and class loader tricks that will be nightmare to maintenance?

not in its domain if you decide that is necessary.

Also, doesn't bind(A.class).to(AImpl.class).injectBy(new CustomInjection()) tell you where it gets applied?

No, it doesnt tell me anything about the dependency. It only tells me about what is available in the global injection pool. I have to lookup the module everytime I want to know what a field's semantic is--how is this any different to trawling xml bean descriptors? The module's purpose is not documentation, it is type-safe dependency binding at runtime.

And that's exactly what I want to see. A "not crazy hack" that can end up as a tragedy. As I can tell, we are most of the time use case driven. So it'd be very helpful if other than wild imagination, a real use case can be given to support the pessimisticism.

Every one of the requirements Ive seen so far for these use cases are for hiding away guice under the covers. I believe a SPI would be a worthwhile solution here, where you're free to configure the internals of guice (then make it clear to your client code that you're NOT using guice as the DI provider, just as a reflectiong and wiring engine like pico).
Someone else from apache also agreed with the spi philosophy for supporting a spec impl. Is this not a reasonable solution when you can say your use cases are stretched well beyond the guice contract?

Ben

未読、
2007/03/23 0:30:352007/03/23
To: google...@googlegroups.com

These are all your preferences, surely you dont mandate them on the rest of us at the sacrifice of type-safe, self-documenting metadata? ;)

I guess I don't get the reason behind the "not requiring an annotation on a method is not type-safe".claim.

And it may be your preference to use an extra meta data to document something that is already self-documenting, but probably not everybody's. IIt is not me who's mandating a universal, "safe" preference that everybody should follow. Quite the opposite, what I'm trying to say is that everybody has their own preference and they probably make sense, you don't treat them like kids and tell them not go anywhere just so they don't get kidnapped.

Absolutely it should stop people from doing stupid things in its domain as far as is possible. For methods withs funky names and improper formatting there are other domain toolkits like checkstyle. If provider can be restricted in some way to prevent stupid things happening (such as returning any Object) then it should. That's why it's parameterized!

Indeed, anything that is pluggable opens up a door to bad code. Module and Provider are two examples. Why not just drop Provider so that Guice is safer? And even parameterized is not safe. There's something called "cast" that can easily screw you up if I really _want_ to do something bad.



not in its domain if you decide that is necessary.

Why do you think it is Guice's domain to worry about people writing bad impl code for Provider/Module/Injection? Bottom line, I can always just write "1/0" if my purpose is to destroy the app, right?



Also, doesn't bind(A.class).to(AImpl.class).injectBy(new CustomInjection()) tell you where it gets applied?

No, it doesnt tell me anything about the dependency. It only tells me about what is available in the global injection pool. I have to lookup the module everytime I want to know what a field's semantic is--how is this any different to trawling xml bean descriptors? The module's purpose is not documentation, it is type-safe dependency binding at runtime.

 

I thought this is "java code" and that is different than xml? And why do you lookup the module to understand a field's semantics? Isn't that solely defined by the class that defines the field?

Of course the module's purpose is dependency binding, that's why we don't look anywhere else if we are concerned about how dependencies are bound.

 

And that's exactly what I want to see. A "not crazy hack" that can end up as a tragedy. As I can tell, we are most of the time use case driven. So it'd be very helpful if other than wild imagination, a real use case can be given to support the pessimisticism.

Every one of the requirements Ive seen so far for these use cases are for hiding away guice under the covers. I believe a SPI would be a worthwhile solution here, where you're free to configure the internals of guice (then make it clear to your client code that you're NOT using guice as the DI provider, just as a reflectiong and wiring engine like pico).
I do not see the requirements as to hide away Guice. That is not the point. The key is for Guice to be able to work with Java EE objects using @Resource, to work with plain old java object using whatever is the best for the objects.


全員に返信
投稿者に返信
転送
新着メール 0 件