Say you have a user who is intentionally dependent on the ProtonJ
implementation (e.g. hiram). He now needs to write code that looks like
this:

    Connection conn = discoveryMechanism(...);
    ProtonJConnection jconn = (ProtonJConnection) conn;

This is basically analogous to asking all collections users to dynamically
choose between ArrayList and LinkedList and then cast to the one that their
implementation actually requires:

    List list = discoveryMechanism(...);
    ArrayList arrayList = (ArrayList) list;

So by forcing the discovery and cast onto the user you are preventing them
from actually declaring their intention to require a specific
implementation to the compiler. Obviously this would be a ridiculous thing
to require for something like collections. Now of course whether our
situation is entirely analogous to collections is really dependent on some
of the questions I asked in the other thread about packaging/organization.
If intentionally depending on a specific implementation is a legitimate
thing for a user to do, then not only does the API need an entry point for
users to get started with, but each implementation also needs one, and the
pattern hiram suggests seems like an exceptionally good fit as it gives you
a very clear entry points for all three of ProtonJ, ProtonC, and generic
Proton.

On the other hand if our intentions are to use interfaces in more of a
JMS/JDBC style manner where the interface/impl split is really an
interface/*vendor impl* split (where by vendor I mean any independent
implementation), then that is a whole different story, and a discovery
mechanism makes more sense, although it doesn't really preclude having
simple and concrete ProtonJ/ProtonC entry points as hiram suggests.

And there is of course a third option which is that we don't want our users
to actually even need to be aware there are multiple implementations. We
only have them for our internal testing purposes.

I think each one of these options suggest different API choices, and right
now we aren't really following any one of them particularly well. We have
public portions of proton-j which would suggest that you should be allowed
to choose to depend on it. We have a very complex factory system which
would suggest we're going for something like multiple vender-style
implementations, and we certainly aren't hiding the fact that there are
multiple implementations, but we've provided no clear guidance on why a
user might choose one over the other.

--Rafael

On Fri, Aug 2, 2013 at 10:55 AM, Rob Godfrey <rob.j.godf...@gmail.com>wrote:

> Given the Proton class doesn't require the user to know which
> implementation they are using (but allows them to explicitly ask for a
> particular implementation type if they so desire) I'm a little confused how
> adding the requirement for the user to instantiate an implementation
> specific class actually helps the user.  Am I missing something?  There
> really is no need for a user to know about factories, etc...
>
> -- Rob
>
>
> On 2 August 2013 15:13, Rafael Schloming <r...@alum.mit.edu> wrote:
>
> > On Fri, Aug 2, 2013 at 4:44 AM, Phil Harvey <p...@philharveyonline.com
> > >wrote:
> >
> > > I agree that o.a.q.p.Proton is, overall, an improvement.  I was partly
> > > responsible for creating the ProtonFactoryLoader and XXXFactory
> classes,
> > > and acknowledge that they make life too hard for the user.
> > >
> > > This was a result of trying to meet the following design goals:
> > > 1. User code should not need to have a compile-time dependency on any
> > > proton-c/j/jni classes.  Given our current separation of the proton-api
> > > from the proton-impl/proton-jni modules, it means user code should only
> > > depend on proton-api at compile-time.
> > > 2. Classes from the various "top level packages", such as engine,
> > messenger
> > > etc, should be kept separate unless they really need to be together.
> > >
> > > I still believe in goal 1 (though this will be discussed at greater
> > length
> > > on the related thread [1]), but am relaxed about item 2.
> > >
> >
> > Thanks for describing the goals, it's helpful to have them written down.
> I
> > personally don't feel that the Proton class is violating (2) in an
> > important way so long as engine and messenger remain otherwise
> unentwined.
> >
> > I generally agree with (1) also, however I think it could use some
> further
> > refinement. At the root of (1) is the desire to make it clear and obvious
> > to developers if/when they are depending on the characteristics of a
> given
> > implementation rather than on a more abstracted interface. Probably the
> > most common example of this sort of thing within Java would be typical
> > collections usage of interface/impl splits, e.g.:
> >
> >     List foo = new ArrayList();
> >     ArrayList bar = new ArrayList();
> >     LinkedList baz = new LinkedList();
> >
> > The suggested pattern for the Proton class would be following this
> pattern
> > exactly:
> >
> >     Proton p = new ProtonJ();
> >     ProtonJ pj = new ProtonJ();
> >     ProtonC pc = new ProtonC();
> >
> > Now this pattern of course doesn't really speak to classpaths at all. The
> > classpath issue is really entirely orthogonal to the interface/impl
> > distinction. Right now we have separate classpaths, but a muddled
> > interface/impl distinction since the impl jar adds new interfaces into
> > packages belonging to the API jar, and the API jar has stuff in it that
> is
> > really part of a specific impl. Likewise, you can have a clear
> > interface/impl distinctions within a single jar as is the case with java
> > collections.
> >
> > I'd argue that the classpath thing is really a distinct goal/requirement
> > and is really more about a discovery mechanism for independent or third
> > party implementations. I don't personally feel that this is a necessary
> > requirement for us at this point, but I'm fairly relaxed if other people
> > would like to support it.
> >
> > Given the above refinement of (1) into (1a) interface/impl split and (1b)
> > independently implementable API, I would find it a bit odd to put the
> > ProtonJ/ProtonC classes into the API package since that would introduce a
> > dependency from the API package back to those impls (even if its only a
> > runtime dependency) and would effectively give those impls an elevated
> > position which in some sense is fine, but also seems contrary to the
> > independently implementable notion in the first place. It seems like what
> > you'd want in the API package is purely a generic discovery mechanism
> that
> > would work for any implementation.
> >
> > As I said above, I don't feel like such a discovery mechanism is really a
> > requirement for us right now. I think actually having a complicated
> > discovery/factory pattern is in some ways detrimental as it creates a
> > barrier to entry for all users when most don't care about the flexibility
> > it offers (at least right now) and if they do care about that flexibility
> > it is easy enough for them to build their own. In fact modulo exception
> > handling it is really just one extra line of code:
> >
> >     Class impl = Class.forName(System.getProperty("blah"));
> >     Proton p = (Proton) impl.newInstance();
> >
> > So I'd personally say go for the simple interface/impl split pattern that
> > everyone knows and is used to and don't worry about a generic discovery
> > mechanism until we actually have enough implementations for it to be
> > warranted.
> >
> > --Rafael
> >
>

Reply via email to