This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

Tooling: Developer assistance with OSGi Versioning policy

Jul 12th, 2008, 04:11 AM

I'm sorry, this post is gonna be a long one (I even need to split it into two comments ;-) ). I hope there's gonna be someone to read it nevertheless - as it includes some fears why I'm still unsure to introduce S2AP or OSGi in general into our development teams. Please tell me your opinions!

One of the bigger problems I see coming with the introduction of OSGi and S2AP in our development process is the required level of discipline of the developer and especially the consequences when the developer once fails having the discipline.
I'm talking about the versioning of modules and the dependencies among modules and their respective versions. This is something completely new to me and all of the developers around me and thus requires quite some change of mindset.
The good news is, that the S2AP Tooling in eclipse very well supports us while doing the change of mindset: It provides a dependency container which is capable of only seeing those Classes in the other project that I am really "exporting" there (great feature!) and will particularly have a look at the version I specified in the various MANIFEST.MF files of the depending projects. While this works well in my eclipse environment, it still does not prevent me from checking in code, which actually would require an increase of the bundle version number - and that's the required discipline I'm talking about. It is the responsibility of every developer to be aware of that fact!

Problematic Use Case
I'm having both bundles checked out in my eclipse workspace. Tooling makes sure, I'm only using Foo from Bundle A in Bundle B, which correctly imports version 1.0.0 of Bundle A.
Imagine now, that I do a change in Interface Foo. Be it a change that "by chance" does not break backwards compatibility (i.e. insert a new method) or a change of a method signature or even worse, the removal of a method from the interface.
In eclipse, I would typically do a refactoring - and thus, the depending bundle B will be updated automatically as well - no problem so far. I could even checkin that code. Continuous integration builds would work, bundles would be created, possibly even automatically deployed to my S2AP platform. As long as those two bundles are the only two depending on each other and as long as both are deployed (e.g. as part of a par package) at the same time, it might even work for a long time (not talking about hot replacement that might one day be of interest as well).
[...]

That bundle however, in my role as developer, does not interest me - thus I don't have it checked out in my eclipse. But it is running in some S2AP instance, together with Bundle A. I'm sure, you can imagine, what happens after deploying the "changed" bundle A into S2AP where bundle C is still unchanged running:
Bundle C's dependency to Bundle A with Version 1.0.0 is still satisfied. Thus dependency resolving successfully completes, Bundle A and C are restarted.
Now, at runtime, when Class BarBar of Bundle C is for the first time accessing a method of Foo - which does not exist any longer - it will horribly fail with the very interesting (and yet before OSGi possibly almost unknown) error: NoSuchMethodError.
And why does the problem occur? Because the developer of Bundle A (me) didn't correctly update the required Version information of Bundle A! I should have increased the "major" or "minor" version number, indicating, that it is no longer backwards compatible. That's what I mean with "required discipline".

The unfortunate thing about it is, that IMHO a problem which has such severe consequences should not just rely on all developers disciplines. I fear that even the best and most experienced developers will once in a while make a mistake and "forget" about the right version adaptation (btw. I didn't check in all details, but http://groups.google.com/group/spring-osgi/msg/bc96ce06c3ad1833 indicates such problems to have happened in the Spring DM surrounding already a year ago - so I'm not just talking about potential ghosts - it already happened).
It gets even more complex, when many changes have been done to the exported interfaces / classes. How can you make sure, you're increasing the right version digit before checking in? Or would you just always increase to major version, just to be sure?

My suggestion would be to let "us" decide, what versioning policy we want to use in detail. But "you" (the S2AP creators) - in the role of providing S2AP and thus THE entry point level tool to OSGi - may want to give us some best practises on how we *should* do a versioning policy.

In addition, I would very much welcome extended Tooling support, even though that might be quite complex to implement. That is: The Tooling could "track" the exported parts of my bundle: If I do changes to exported interfaces / classes, it could indicate, that very likely a versioning change is required as well. If it's really clever, it could even suggest what version digit I have to update due to my companys versioning policy.

Ok, now please tell me - what do you think?

Regards,
Kay

Comment

I think you are perfectly right that it is a matter of policy, and there are already pretty good guidelines about what is allowable in major, minor and micro version changes. Those policies only really apply, though, to situations where the boundary between API publisher and API client are further apart than in your example - e.g. where I am using a bundle that is published by some party completely external to my project, and all the changes always conform to the policy.

The problem is that if a bundle is being modified heavily, it is really not yet a published API, so you have to expect breaking changes. I think this is one of the best and least well used features of Maven - the dependency meta-data forces you to explicitly state that you are depending on a SNAPSHOT, and this has consequences for the development process. You do that for pragmatic reasons: you want to benefit from major changes, and you take responsibility for fixing anything that breaks in your own project as a result. It is baked into Maven and the philosophy behind the build and deployment process (the default behaviour for instance is to refuse to deploy a non-SNAPSHOT that contains dependencies on a SNAPSHOT). For this reason if no other I would still rate Maven highly as a CI and build tool (it might suck for other reasons, but at least it helps me to get some hard things right with relatively little effort).

So, my opinion at least is that this is not an OSGi problem you have described, and it has almost nothing to do with S2AP. However, I hope our tools team are listening, and taking notes because there clearly are some tooling features that can help (as per the Maven example).

You are perfectly correct that OSGi, and S2AP for that matter, do not prescribe a versioning policy. The most common versioning policy (described in section 3.6.2 of the OSGi Core Spec. v4.1) is to increment the major version component to indicate a breaking change, but for an unstable API like that above, it might make more sense to increment the minor or possibly even micro version component to indicate a breaking change. Then importers would specify ranges such as [1,1.1) or [1,1.0.1). However, this really only moves the problem: developer discipline is still required to increment the appropriate version component on a breaking change.

Another approach for "true" APIs is to package them into a separate bundle and apply a stricter change process to that bundle. In the example above, an API was packaged with its implementation and so there is a greater probability that a breaking change could be made unwittingly by a developer. A stricter change process would be something low-key like requiring a buddy check of each change or, at the other end of the spectrum, having a review process by an "architecture board". Clearly the choice depends on the importance of the API and the impacts of failure.

Another observation is to ask how the above scenario would be handled today. Without some process or developer discipline, you would still get a NoSuchMethodError. So the lack of developer discipline is two-fold: (i) deleting a method of an API without tracking down all its users, and (ii) not updating the version number appropriately. From my perspective, the first of these is the more serious. After all, you can use OSGi without paying any attention to version numbers and you should get similar behaviour to using standard JARs files today. Using version numbers in a disciplined way simply adds a number of benefits including early warning of incompatibilities between exporters and importers.

I also agree that some tooling support would be great, so I'll bring this thread to Christian's attention to get his views.

since the early days of Spring IDE we were dealing with these kind of version management problems you are outlining. This problem is now even more complex as we create tools that build on top of Spring IDE like STS and the AP tools. Due to lack of tooling support (Eclipse 3.4 somewhat addresses this now) we needed to handle this by our own discipline and by strict rules.

Having said that I absolutely see a real value of providing support in our tools. The tooling could record all changes that are made in a bundle and could - based on explicit and user-definable version policies - suggest version increments.

Comment

Thanks for all your responses - I'm glad you read the long post and apparently recognized what I mean ;-)

@Dave, re "basic OSGi policy mainly applies on api's further apart": I fully agree. I'm happy that you pointed out that there *is* a difference. The difference between a "product provider" who's core business is, to take care of providing stable APIs (such as your own products like Spring Framework but also S2AP Tooling or all the eclipse platform / plugins etc.) and a team of developers, who just decided to split their monolithic application into modules (and were never before forced to really really think of APIs between those different application parts!).
For the first, OSGi is perfectly well suited. The latter though is faced with problems exactly as outlined in the beginning of this discussion.

IMHO, the effort required to learn OSGi / S2AP and introduce it into an existing infrastructure and development teams must not be underestimated. It is one thing to "dream" of an architecture which has everything that OSGi and S2AP provide (modularity, easy deployment, maintainability etc. etc.) and it is a completely different thing to convince development teams who got used to "the way it works now" and "migrate" an existing code base to OSGi. I am currently trying to do it - and the simple question I get all the time is: "That sounds awfully complicated (aka 'different'), is this really worth the hassle?"
I'm not sure myself yet. Is this really gonna bring me some profit, or is it just "added effort"?
I'm convinced though, that every single thing (documentation, how to's, best practises, examples but also Tooling support, possibility for smooth infrastructure migration etc.) you guys provide will make it less effort and more successful. IMO, if you want to be the guys to bring "us" OSGi then it is your duty to make very sure you give us, what's required to start using it.

In short: Fill the gap between what OSGi already provides and what average JEE developers really need in daily life and S2AP will be a success.

Comment

@Glyn, re "how the scenario is handled today".
I can tell you, how this scenario looks like in my current work place: We haven't arrived at the OSGi world at all yet. Thus it's as simple as you can imagine: There's only always one version of the code at a given time. For the whole release cycle until we "deploy", we all have to deal with all changes in that version.
To have some code sharing at least, we do have multiple "modules" (jar files). If an application consisting of a number of modules is built, all required modules are built, based on the same snapshot version of the code. Thus, if it compiles, there won't be such a thing as "NoSuchMethodError" at runtime.

This works a charm but has some fundamental drawbacks. It basically requires that releases are only done, when the code is "in sync", that means: All developers are finished with their features and have tested their code. It is just not possible - or at least very risky - to release an application "in-between" a release cycle. Thus, we're all tightly coupled to the release plan and to each other - especially from an organizational stand point.
This is exactly, what I'd like to split up. There are various possibilities to do so. One might be to work with various code "branches" at the same time. However, that is not really practical on the long run (and requires quite some permanent work and maintenace on the Continuous Integration side). Also, sometimes changes in a shared module *must* be used by various applications as soon as possible after the change. So, pure isolation is not the perfect solution.

Instead, it is my strong believe, OSGi / S2AP and "versioned bundles and par files" are the means to achieve the goal. I just don't know how exactly this will solve the problem, yet ;-)

@Christan: good to know that you "suffered" from this already - increases probability for an implemented solution in the tooling ;-) Jira created at
https://issuetracker.springsource.com/browse/PLATFORM-137