On May 25, 2011, at 6:06 PM, Matt Wringe wrote:
>> Except that Ids don't have all the same formats so that
prevents
> generic methods. For example, you couldn't have
> ContentRegistry.getContent("warName", "portletName") because
that
> would conflict with ContentRegistry.getContent("invokerName",
> "portletHandle") for the WSRP case.
But that is just an implementation detail.
The devil is in the (implementation) details… :)
applicationRegistry.getPortletRepository(LOCAL).getPortlet("warName",
"portletName");
applicationRegistry.getPortletRepository(wsrp.SELF).getPortlet("portletHandle");
Except that getPortlet(String, String) wouldn't make any sense on a local
PortletRepository and the getPortlet(String) version wouldn't make any sense on the
remote version.
[well, I guess if wsrp uses portletHandles, I need to relook at how
my
portlet repository class currently works]
One of the point of using Ids is that the same method works in all the different contexts.
So you don't need subclasses for specific cases, you might just need (if at all)
different implementations of the same interface.
> Bypassing the Id object would only work in non-ambiguous cases
and
> I'm fine with doing so.
We can always write the api so its going to be non-ambiguous with
respect to this.
By making special cases all over the place, yes. Which is what I'm trying to avoid.
Keeping the API coherent and consistent, avoiding special cases for different content
types.
> However, there are cases where it wouldn't work. Also, again, it
> would mean that each method that needs to work with an identifier
> would need to first perform the intermediate step (though obviously
> that code could be mutualized internally, but if we're going this
> step, why not have Ids? ^_^).
> Plus, T getElement(Id<T> id) would allow us to have typesafety at the
> id and returned value level, something you wouldn't be able to do with
> getElement(String... ).
> This is a valid point. However, it's still not a very strong argument
> against Id as separate objects. What is the big issue in your opinion
> with having separate Id objects?
Its cumbersome to always have to think and create ids to do something,
when it can be done more directly without them. Its also confusing if
some elements require these ids while others don't (ie a category
doesn't need a separate id class, since it can be differentiated by a
string).
I don't think it makes sense to have things like
Id id = Id.generateId("foo", "bar");
Element element = something.getElement(id);
instead of just:
Element element = something.getElement("foo", "bar");
because you're assuming that getElement will always be able to construct an
unambiguous identifier given 2 strings, which as I've shown already doesn't work
with WSRP.
Ok, so lets say we need to have more complex ids:
PortletId pId = Id.generatePortletID("foo", "bar");
WSRPId wId = Id.generateWSRPPortletId("foo", "bar");
GadgetId gId = Id.generateGadgetID("foo", "bar");
Portlet portlet = getApplication(pId);
Portlet portlet = getApplication(wId);
Gadget gadget = getApplication(gId);
We can still handle it using something like:
getApplication(Application.Portlet, "foo", "bar");
getApplication(Application.WSRP, "foo", "bar");
getApplication(Application.Gadget, "foo", "bar");
That last one could be a solution but it's not any cleaner than
getApplication(Id<Portlet> id) which will also have the benefits of allowing us to
do: Portlet portlet = getApplication(Id<Portlet> id) which your other solutions
(apart from enumerating all possible cases) don't.
but in this case I would argue that we use
getPortlet("foo", "bar") and
getGadget("foo","bar"). But for the wsrp case, its get a bit more
tricky
(which is why I have multiple portlet repository classes).
Well, WSRP needs to be treated as a first class citizen. And we need to make an API that
would also accommodate other kinds of content without to have to change it and make new
special cases. Enumerating over the known cases at a given point won't give us a very
future-proof API and lead into issues where code will make assumptions that new content
types we might support might not follow. I understand that we shouldn't try to plan
for every possible scenarios under the sun but with what we currently have the String as
Id approach is already showing limits when encapsulating identifiers in a separate object
wouldn't cost much and lead to easier evolution of the API if needed.
Another (and probably last) thing I will say in favor of encapsulating identifiers in a
separate object is that it makes it more natural to use artificial identifiers (think SSN)
instead of natural ones (think last name). Using artificial identifiers has lots of
benefits, one of which being stability in the face of renames, which is an important
property for a REST API (you don't want your URIs to change just because you've
renamed an entity to something else). It also allows objects to be identified via other
things than a name if needed (get a user id based on an OAuth token for example) and the
API won't change since it will still deal with the Id class instead of needing to add
yet another version of the get methods to accommodate the new modality. Obviously,
that's not necessarily something we want/need to support but considering that the cost
of using Ids instead of Strings is pretty low, I have yet to see a really compelling
argument not to.
And with this, I won't argue about the value of having separate Ids anymore. I think
I've made my point. I agree that using Strings looks simpler but I worry that it might
actually make implementing the API more complex and less future-proof when the cost of
using separate Ids seems pretty low.
Cordialement / Best,
Chris
==
Principal Software Engineer / JBoss Enterprise Middleware Red Hat, Inc.
Follow GateIn:
http://blog.gatein.org /
http://twitter.com/gatein
Follow me:
http://metacosm.info/metacosm /
http://twitter.com/metacosm