Use-cases for version ranges?
Nicolas Lalevée
nicolas.lalevee at hibnet.org
Sat Nov 19 02:49:47 PST 2011
Le 19 nov. 2011 à 05:32, cowwoc a écrit :
>
> Brian Pontarelli wrote:
>>
>> I think the two fundamental issues I have with ranges are:
>>
>> 1. At any given time I can only be certain my code will work with one
>> version of a dependency. That is the version I compile and test against.
>> Therefore, as a developer, I should only define that version in my
>> dependencies meta-data.
>>
>> 2. There should not be any magic upgrading of my dependencies at run or
>> build time. Someone should be forced to specifically upgrade one of my
>> dependencies and only for a really good reason. They should also be forced
>> to test that upgrade to ensure it will work.
>>
>> Without module isolation, this problem was much more difficult because
>> there could only be one version of a JAR on the classpath and therefore
>> build tools needed to understand how to safely upgrade JARs. Some build
>> tools did this better than others.
>>
>> With true isolation, this is less of an issue, making single versions even
>> easier to use.
>>
>> Issues come back into play when modules export modules or with circular
>> dependencies. These mimic the classpath behavior, which in my opinion is
>> best solved via compatibility rather than ranges.
>>
>
> I can't speak for module isolation (care to explain what you mean?) but I
> agree wholeheartedly with your two points. Whether we support version ranges
> or end-user overrides, can we all agree that developers can only be expected
> to certify that their code works with a single version of a dependency?
>
> If so, the question becomes: what mechanism is best suited for allowing
> someone other than the original developer to change the dependency
> version... One approach is version ranges. Another approach is end-user
> overrides. I don't understand what module isolation refers to but I suspect
> that's a third option.
I'm not sure either how module isolation would help either. But I think there's solution we don't want to see because we fear duplicates, redundancy, this is error prone: having two dependency descriptors.
But as Neil already wrote it: "At build time we need to compile against a single specific version so that we have repeatable builds. [...] At runtime however we need to have the flexibility to substitute a single compatible version." Since we want to declare two very different things, I don't think of no other way than having two kinds of declaration. And note that these two declarations will be used at very different times. The first will be used while we construct the classpath (to build or to deploy), the other by the jvm at runtime to ensure modularity.
I think I have a solution. I'm experimenting it with Ivy (which is good at building classpath) and OSGi (which is good at runtime dependencies). A project in development would have an ivy.xml in which I would declare the dependency I want to build, test, run against. It could looks like a dependency on commons-logging 1.0. I make Ivy resolves and retrieves my dependencies against an OSGi repository (I'll explain why later), so I get my jars in a lib folder.
Then I need to make my project runnable in an OSGi environment, so I need an other descriptor. I need to redeclare my dependency in a MANIFEST ? Actually no since OSGi dependency model is nicely integrated in the Java environment, no extra namespace, just java packages. So my dependencies are already declared by my java import in every of my classes. And there's nice tools (bnd, bundlor) to compute the MANIFEST automatically. So no burden. In the MANIFEST I would then have a dependency on the package org.apache.commons.logging.
Last but not least, the release of the project. Since I don't want the users of my project to be tied to the dependencies I chose in my ivy.xml, I shouldn't publish it. Instead, users should be aware of what my project is requiring, which API must be fullfield: the information is in the MANIFEST. The end users should fulfill the requirement on the package org.apache.commons.logging by either the implementation bundle commons-logging or the bundle jcl-over-slf4j. So I'll publish only the OSGi metadata, hence my project should be publish to an OSGi repository.
And the development cycle is closed.
There's one thing to note about the Ivy resolve against an OSGi repository. As the OSGi Bundle Repository spec draft nicely state: "SHALL NOT be required to produce identical sets of resolved resources throughout every phase of the development process." Since the inherent "flexibility" nature of the dependency declaration of an OSGi bundle, two resolves at different times may result in two different classpath. Hence the Ivy resolve would be done only one to build a classpath. And only do it again on dependency change. In Eclipse world, this is what is called an target platform.
This is the best dependency management I have found so far. I have to admit it is theoretical, Ivy's model is not yet ready to understand OSGi dependency model.
A last note on the solution on overriding dependencies. This really looks like a hack to me. The developer of a module A declare a dependency on module B and we say, no, it's actually module C. For me it it like changing the visibility of a method from private to public via introspection.
Nicolas
More information about the jigsaw-dev
mailing list