Twitter github

Jigsaw Versioning is Ridiculous

There was some activity on the JSR 294 mailing list this morning. The Jigsaw team came down from the mountains and has informed us that…

javac can compile source files belonging to modules inferred from the
modulepath and will enforce full module-private accessibility Real Soon
Now. Long-standing issues with bootstrapping the JDK have also been
addressed, such that modularized JDK libraries are used properly and
early in the build.

The libraries are modularized by mechanisms in the Jigsaw module system
including but not limited to recursive virtual modules, per-method
dependencies, packages split across modules, and structured
arbitrary-length versions.
Sun finds these mechanisms useful for
compatibly restructuring vanilla packages in the JDK, and believes they
are applicable to clients of the JDK also.

Clearly, the Jigsaw model goes some way beyond “named and versioned
JARs”. How it overlaps with the OSGi model – designed for new, dynamic,
service-oriented applications – is not clear. Since both Jigsaw and OSGi
are defined in the first instance outside the JCP, it does not appear
that JSR 294 is well-positioned to define a module system that unifies
them. It would be a lowest-common-denominator design with
well-intentioned but irksome compromises. There has been no clear
support in the EG for the Simple Module System proposal, and I would
like to take it no further.

I just about stopped reading when I hit the “structured arbitrary-length versions” feature.

I dug a bit deeper in the Jigsaw Javadoc to see what this means exactly…

Jigsaw Version

Nice… “Vaguely Debian-like version strings, for now.”

I had my rant on software versioning in general last week… this is a terrible idea in my book. Maybe I’m just in a bad mood because my inbox is under attack by Stephanie Meyer who happened to release a book with the same title as my favorite open source project. In module systems, version numbers should encode compatibility to keep us sane when developing and talking about things. Let me give you an example from OSGi land. Let’s say you’re writing an application and need to depend on log4j…

Require-Bundle: org.apache.log4j

You go to deploy your bundle and things work great. Your users are happy. Now you have a colleague take your bundle and deploy it into another system and you get a bunch of crazy exceptions. What happened? Well, first you didn’t specify a version range on your depending for log4j so basically your assumption is that your bundle would work with any version of log4j. At development time, you were using log4j 1.1 and the first system you were deploying to happened to use log4j 1.1 too. However, when your colleague went to reuse your bundle (since we can easily do that now since we have modules), things blow up because the system they went to deploy your bundle happened to have log4j 1.2… and the log4j development team unknowingly broke binary compatibility with the new release. To fix this problem… you can simply scope your depending on log4j…

Require-Bundle: org.apache.log4j;version=[1.1, 1.2)

Let’s use another example from OSGi land… commons collections. Let’s say you needed commons collections… you were developing with version 2.1 and you decided to be smart and scope you version range this time because you thought you learned your lesson.

Require-Bundle: org.apache.commons.collections;version=[2.1, 2.2)

Next what happened was that the commons collections development team released version 3.0 and declared it to be binary compatible with the 2.1 version. The potential environments your bundle can be deployed to is limited based on the scoped dependency above… even though your bundle would work fine in an environment where the commons collections 3.0 version was floating around. The ability to reuse your bundle was reduced.

The crux of the problem here is that you don’t know how to scope your version ranges and in particular… versions really don’t convey anything to you as a module developer. In OSGi land, there’s a four segment version and a mantra of encoding compatibility in your version number. Each segment of the version means something. To get a good idea of how to handle versioning on a large scale, we have a fantastic set of guidelines regarding versioning bundles at Eclipse. If everyone followed the same set of versioning guidelines, you can properly setup your dependencies and as a developer, you immediately can see meaning between what you’re developing against and what you may consume in the future.

My recommendation to the Jigsaw team would be to reconsider their stance on treating module versions like nothing. I would like to see binary compatibility encoding in version numbers and given the fact that Maven is moving to the OSGi versioning scheme… Jigsaw might as well also. It would be nice in Java if we had a consistent way to talk about the versions of software we develop for people to reuse.