Semantic Versioning IMHO mostly cares about Consumers (which are many bundles) 
as Providers usually need to be changed for any kind of API change and are only 
a few bundles compared to the many consumer bundles.
So yes, although changing a consumer interface requires recompilation of the 
provider bundle that is usually desired (especially if the class is closely 
related to a provider type class in the same package).

So I guess the best practice is rather:
- Put closely related classes in the same package
- Don't let the package contain too many classes (because obviously the fewer 
classes share one package version the less of a risk for unnecessary 
recompilation of consumers)

Konrad


> On 30. Jun 2021, at 06:54, Carsten Ziegeler <[email protected]> wrote:
> 
> You can regard provider type as the implementor of the api of a package 
> whereas everything marked as consumer type is implemented by users of that 
> api.
> 
> So yes, if you make any changes to that package, add a new interface, add a 
> new method etc., you need to adjust the implementor.
> 
> For example, if you add a new consumer interface, it will break the 
> implementor - but it is highly likely that the implementor needs to do 
> something with that new interface, like picking up all services implementing 
> that new interface and eventually invoking those. So it is natural that the 
> implementation needs to be updated.
> 
> Of course, if the change is about static utility code, then yes this is not 
> breaking the implementor. But I consider this an edge case.
> 
> You can't make changes to a consumer type (unless you add a default method to 
> an interface) as this will break all clients.
> 
> So again, many use cases for putting consumer and provider type interfaces 
> into a single package are totally valid and good api style.
> 
> Moving api artifically into separate packages just because of the fear that 
> changes require to update the implementation, can create a bad api experience.
> 
> Side note, if you have api and the implementor in the same module, the whole 
> discussion goes away. Which is another fun discussion :)
> 
> Regards
> Carsten
> 
> 
> Am 29.06.2021 um 22:48 schrieb Eric Norman:
>> Hi Konrad,
>> Can you confirm that mixing your 3rd scenario (as below) with any of the
>> other 3 within the same bundle also results in the narrow version range for
>> that imported package?
>> @ProviderType                   1.1.0                           yes
>>  [1.1, 1.2)                              Provider
>> The point being that as soon as you implement any ProviderType interface in
>> your bundle then you can't add new (unrelated?) classes to that exported
>> package or change any ConsumerType classes in that exported package because
>> those changes would result in a bump of the exported minor version number.
>> The imported package range for any bundles that were built against the
>> previous release would no longer match the narrow version range exported by
>> the new release.
>> This is the scenario that was discussed with SLING-10031
>> On Tue, Jun 29, 2021 at 12:28 PM Konrad Windszus <[email protected]> wrote:
>>> Hi, sorry for the confusion here, I think I may be just wrong.
>>> 
>>> From the standard policies from Bnd I do no longer think mixing Consumer
>>> and Provider in one package can lead to breaking users of the API more
>>> easily.
>>> 
>>> Let's quickly recall what the rules are:
>>> 
>>> Rules for Exported Versions
>>> ====
>>> 
>>> ConsumerType
>>> Every binary incompatible change requires an increment on the major
>>> version.
>>> 
>>> ProviderType
>>> Every binary incompatible change requires (at least) an increment on the
>>> minor version.
>>> 
>>> Rules for Imported Versions
>>> =====
>>> 
>>> For each interface/ non final class it is stated, whether it is supported
>>> to be implemented/extended by Consumers (and providers, the default) or by
>>> Providers only. That information together with the information whether the
>>> interface is just used or really implemented determines the version-range
>>> of the import-package statement:
>>> 
>>> Annotation on class/interface | Version Implemented | Import-Package
>>> Version Range | Versioning Policy
>>> @ConsumerType                   1.1.0                           yes
>>>  [1.1, 2.0)                              Consumer
>>> @ConsumerType                   1.1.0                           no
>>> [1.1, 2.0)                              Consumer
>>> @ProviderType                   1.1.0                           yes
>>>  [1.1, 1.2)                              Provider
>>> @ProviderType                   1.1.0                           no
>>> [1.1, 2.0)                              Consumer
>>> 
>>> Those policies can be overwritten via the instruction
>>> http://bnd.bndtools.org/instructions/consumer_policy.html and
>>> http://bnd.bndtools.org/instructions/provider_policy.html.
>>> From those rules I cannot construct a usage which would point at splitting
>>> Consumer and Provider types.
>>> 
>>> I think my confusion initially came from
>>> https://github.com/apache/felix-dev/blob/057bb85d7d496671755cd53cffc9e91a17c1d17c/tools/osgicheck-maven-plugin/src/main/java/org/apache/felix/maven/osgicheck/impl/checks/ConsumerProviderTypeCheck.java#L115
>>> @Carsten: Do you remember why that usage leads to an error in
>>> osgicheck-maven-plugin?
>>> 
>>> Konrad
>>> 
>>> 
>>> 
>>>> On 29. Jun 2021, at 20:23, Eric Norman <[email protected]> wrote:
>>>> 
>>>> I haven't looked at this too closely, but do you think that there could
>>> be
>>>> some benefit to keeping them in separate packages if you expect the
>>>> consumer and provider apis to evolve at a different pace?
>>>> 
>>>> If I recall correctly, the bundles that import and use stuff from a
>>> package
>>>> that contains both consumer and provider classes may get a too specific
>>>> range for the import package range.
>>>> This has to do with bndlib choosing the "provider-policy" instead of the
>>>> "consumer-policy" when calculating the version ranges.
>>>> 
>>>> From what I read, the default definitions for bnd are:
>>>> 
>>>> -consumer-policy ${range;[==,+)}
>>>> -provider-policy ${range;[==,=+)}
>>>> 
>>>> 
>>>> 
>>>> Specifically, the import-package item can end up with a narrow range as
>>>> something like org.apache.sling.whatever; version="[2.4, 2.5)" for the
>>>> importing bundles which can leads to troubles when the next minor change
>>>> requires the exported package to get bumped to "2.5.0" since that
>>> exported
>>>> package number no longer satisfies the import package range.  This would
>>>> mean that all the "importing" bundles would have to change as well and
>>> you
>>>> end up with a cascade of new releases just for some minor change in the
>>>> "consumer" part of the exported package even if the changes were trivial
>>>> and backward compatible.
>>>> 
>>>> Regards,
>>>> -Eric
>>>> 
>>>> 
>>>> 
>>>> On Tue, Jun 29, 2021 at 8:54 AM Carsten Ziegeler <[email protected]>
>>>> wrote:
>>>> 
>>>>> I don't think that not mixing consumer and provider interfaces is a best
>>>>> practice.
>>>>> 
>>>>> The OSGi specs - which I think are usually following best practices -
>>>>> are mixing them. For example event admin where the event admin interface
>>>>> is in the same package as the event handler.
>>>>> 
>>>>> The markers actually help putting those interfaces into the same
>>>>> package. In above example you can change the event admin interface
>>>>> without breaking the event handler.
>>>>> 
>>>>> The framework api does the same, confgig admin etc.
>>>>> 
>>>>> It's good to split packages based on purpose and usage. For example to
>>>>> move SPI interfaces into a separate package.
>>>>> 
>>>>> Regards
>>>>> Carsten
>>>>> 
>>>>> Am 29.06.2021 um 16:49 schrieb Bertrand Delacretaz:
>>>>>> Hi Konrad,
>>>>>> 
>>>>>> On Tue, Jun 29, 2021 at 3:04 PM Konrad Windszus <[email protected]>
>>> wrote:
>>>>>>> - Please don't mix Consumer and Provider interfaces in the same
>>> package
>>>>>>> (
>>>>> 
>>> https://github.com/apache/sling-org-apache-sling-sitemap/tree/master/src/main/java/org/apache/sling/sitemap/generator
>>>>>>> and
>>>>>>> 
>>>>> 
>>> https://github.com/apache/sling-org-apache-sling-sitemap/tree/master/src/main/java/org/apache/sling/sitemap/builder/extensions
>>>>> )
>>>>>>> as that enforces updates to break more consumers than necessary....
>>>>>> 
>>>>>> Could you elaborate on that? The issue is not obvious to me.
>>>>>> 
>>>>>> More generally, I think it would be useful for us to document best
>>>>>> practices around Consumer and Provider interfaces.
>>>>>> 
>>>>>> If someone has links to such best practices that would be great,
>>>>>> otherwise feel free to add some notes in response to this message and
>>>>>> I'll write something up for https://sling.apache.org/
>>>>>> 
>>>>>> -Bertrand
>>>>>> 
>>>>> 
>>>>> --
>>>>> --
>>>>> Carsten Ziegeler
>>>>> Adobe Research Switzerland
>>>>> [email protected]
>>>>> 
>>> 
>>> 
> 
> -- 
> --
> Carsten Ziegeler
> Adobe Research Switzerland
> [email protected]

Reply via email to