aries-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Alasdair Nottingham <>
Subject Re: Semantic Versioning tool
Date Fri, 30 Sep 2011 20:30:57 GMT

Alasdair Nottingham

On 30 Sep 2011, at 17:11, Jeremy Hughes <> wrote:

> On 30 September 2011 15:00, Alasdair Nottingham <> wrote:
>> Hi
>> I think David is right on this one. If we look at ConfigAdmin as an example.
>> The ConfigAdmin interface contains two interfaces (well it contains more,
>> but two of import to my example):
>> ConfigurationAdmin
>> ConfigurationListener
>> A ConfigAdmin implementation implements ConfigAdmin. In this example adding
>> a method to ConfigurationAdmin constitute a "compatible" change. i.e. a user
>> of the service does not care. However adding a method to
>> ConfigurationListener would constitute a major version change. This is
>> because ConfigurationAdmin is to be used by clients of the spec and
>> ConfigurationListener to be implemented by them.
>> It really relates whether the implementor of the interface is a "provider"
>> or a "user" of the package. I'm not sure this is well explained :(
> I think it's "provider" vs "consumer". It strikes me the paper needed
> to distinguish between changes to provider implemented interfaces and
> consumer implemented interfaces in this way because there's never been
> any advice to separate interfaces used in these distinctly different
> ways, into separate packages. And because there *are* packages with
> these two types of interface in the same package, particularly in OSGi
> standard packages, the advice had to be what it is - so that adding a
> method to EventAdmin, causing a minor version increment to the
> package, wouldn't unnecessarily break consumers of EventListener, for
> example.
> If provider implemented interfaces were always in different packages
> to consumer implemented interfaces, the rule could just be: if the
> interface author changes the interface in a binary compatible way that
> requires implementors to make changes, then the minor version should
> be incremented; (also, of course, major version increments for binary
> incompatible changes). The problem is, there *are* packages out there
> that need to be versioned which include interfaces both for consumers
> and providers.

While this is an option it is not one that fills me with enthusiasm. It is a Hugh change to
the way we design and use packages. Typically types in a package have cohesion and, as an
example, a listener, event and the type you register it with has cohesion. I think we need
to work with existing conventions rather than try to force new design schemes.

> Sigh. So pragmatically the only way to go is to
> introduce a new mechanism as you suggest below to indicate which
> interfaces are for consumers and which for providers. I think though,
> it would be useful for the annotation mechanism to be standardized.

I agree, the OSGi alliance uses an @noimplement tag to mark types that a client uses, rather
than implements. I think I've also seen an @userimplements tag for the opposite. I think we
can also look for common naming conventions like XYZListener would probably be user implemented.
The issue with javadoc tags is that you need the source which you might not have. 

>> How we "detect this" might be tough, but we have a good starting point. We
>> could look at the source for javadoc tags @userimplements or we could
>> provide annotations, or allow configuration to say "this is user
>> implementable stuff".
> Yeah, all of these work for me.
>> Alasdair
>> On 29 September 2011 14:30, Jeremy Hughes <> wrote:
>>> On 29 September 2011 12:25, David Bosschaert <>
>>> wrote:
>>>> On 29 September 2011 11:58, Jeremy Hughes <> wrote:
>>> [snip]
>>>>> I think it's on a package level, not a technology level.
>>>>> To quote the white paper (executive summary):
>>>>> "A package can contain an API. There are two types of clients for
>>>>> these API packages: API consumers and API
>>>>> implementation providers. A change in the second (minor) part of the
>>>>> version signals that the change is
>>>>> backward compatible with consumers of the API package but not with the
>>>>> providers of that API. That is,
>>>>> when the API package goes from version 1.5 to 1.6 it is no longer
>>>>> compatible with a provider of that API but
>>>>> consumers of that API are backward compatible with that API package."
>>>>> An implementer of BlueprintListener is an API implementation provider.
>>>>> A single class can be an API implementation provider of
>>>>> BlueprintListener while being an API consumer of other blueprint
>>>>> packages. I don't believe the whitepaper describes the subtlety you
>>>>> allude to. Have I missed something?
>>>> And again, I may have missed something here too :) The situation that
>>>> I'm describing here is that *within* a single package (e.g. the
>>>> org.osgi.service.blueprint.container package to stay with our example)
>>>> one could be a consumer while still implementing an API provided by
>>>> that package.
>>>> That's why when in our example when
>>>> org.osgi.service.blueprint.container.BlueprintContainer gets a new
>>>> method only the minor version of the package needs to be increased (as
>>>> consumers don't implement this interface) but when
>>>> org.osgi.service.blueprint.container.BlueprintListener gets a new
>>>> method the major version of the package needs to be increased as
>>>> consumers do implement this interface, but given they're a consumer
>>>> should be allowed to specify a version range like [1.0.0, 2.0.0).
>>> I see what you mean and the whitepaper discusses this scenario in the
>>> 4th para of p8:
>>> "An interesting problem for exporters is the policy applied to
>>> interfaces that are implemented by the consumers of the API. For
>>> example, in the OSGi framework, the Bundle Activator interface is not
>>> implemented by a framework provider but by consumers of the framework
>>> API: bundles. A change in such an interface will not be backward
>>> compatible with any consumers of the API and therefore requires a
>>> change in the major part of the version. API designers must therefore
>>> be acutely aware of the usage pattern of their interfaces and try to
>>> prevent making changes to interfaces that are implemented by the
>>> consumers of the API. Any change in an interface that is implemented
>>> by a consumer of the API breaks backward compatibility for all
>>> consumers."
>>> Oddly, this conflicts with the 2nd para of p8:
>>> "Tools will be able to detect syntactic violations of the semantic
>>> versioning by comparing a previous version and the new version."
>>> A tool cannot determine whether an interface in an exported package is
>>> being exported for consumers or for implementers. There's no standard
>>> way of doing so. Moreover, if there was, it wouldn't be enforceable at
>>> compile time without changes to the compiler. A tool doesn't have
>>> visibility to all the possible importers of the package. It therefore
>>> cannot say whether a package is being used by consumers or
>>> implementers ... or both!!
>>> IMHO the whitepaper attempts to protect consumers too vigorously. A
>>> better arrangement would be for the exporter to modify the minor or
>>> major version based on changes to the interface(s) in the package
>>> rather than what an importer might decide what to do with it. (since I
>>> already mentioned declaring what an importer can / cannot do with it
>>> is unenforceable). There's nothing wrong with consumers being mindful
>>> of what packages they import for interfaces they wish to implement and
>>> set their import version ranges appropriately.
>>> So:
>>> a) the white paper is in conflict with itself para 2 vs 4 on p8
>>> b) what is proposed in para 4 cannot be implemented by tools, so will
>>> be ignored by tools providers and will eventually fall by the wayside
>>> I guess now, I'm posting to the wrong list as this should be a
>>> discussion with the paper's authors ;-)
>>>> Cheers,
>>>> David
>> --
>> Alasdair Nottingham

View raw message