<div dir="ltr"><div><div><div><div><div>Hi Stephan,<br><br>>Behavior, however, is critical and complicated to test, having a<br>
>contract that makes guarantees here would indeed be useful<br><br></div><div>A contract that guarantees this would be amazing. I think we are on the same page, but just wanted to illustrate how bugs make this an intractable problem for versioning:<br><br></div>If bug fixes that change behavior would cause MAJOR version bumps, the introduction of bugs that change behavior must also cause a MAJOR version bump. Thus you need to know if you have added a bug or not before doing a release. Failure to identify a bug means the release of versions that do not follow the versioning scheme, which means we can not actually use the version to reason about compatibility.<br><br><span>>> 3. Since this is an internal versioning scheme, it may not be easy to<br>
>> compare our versions with external project versions that use SemVer.<br>
><br>
</span>>Why would we want to do this?<br><br></div>My original thought was dependency convergence - but for that the versions comparisons are between artifacts with the same versioning system, so all you need is internal consistency. So this may not actually be important.<br><br>><a href="http://sentimentalversioning.org/" target="_blank">http://sentimentalversioning.org/</a><br><br></div>This page is great. I either hadn't read it or had forgotten it, so thanks for sharing!<br><br>> <a href="https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e" target="_blank">https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e</a><br><br></div>I think the author of this post slightly misunderstands the use of SemVer. I completely agree with some of the content ('If you expect SemVer to solve your problems for you, you will be disappointed'). But the author seems to blame SemVer for failing to account for changes in behavior, when really the failure was in their use of SemVer.<br><br></div>In the intro of <a href="http://semver.org/" target="_blank">http://semver.org/</a> is the phrase: "For this system to work, you first need to declare a public API." If a developer doesn't declare API to include behavior then they can't expect behavior to respect SemVer. If they decide API does include behavior and then follow SemVer, then behavior would be guaranteed between compatible versions - assuming they updated the version appropriately when changing behavior.<br><br>>Instead, we should try to build pom-fiji including all<br>
>downstream modules *overriding* or *upgrading* their dependency versions<br>
>to the highest possible. Do you have something like this already or do<br>
>you have an idea how that could be done?<div><div><div><div><div><br></div><div>We have been throwing around the phrase "Melting Pot" for a while. This is our dream: to have a Jenkins job that pulls the full SciJava software stack and tests everything together based - i.e. build <a href="https://github.com/fiji/fiji/blob/86622adda86e786dac01e8f7339cba5cb772b50b/pom.xml">Fiji's pom</a> and test. This would check for dependency convergence as you outlined, and make whatever guarantees of behavior we can automate.<br><br></div><div>There is a <a href="https://github.com/scijava/scijava-scripts/blob/aab7cfe805638efc25615fdd7c78cedaae3c7197/melting-pot.sh">script started to do this</a>, but no tests incorporating it that I know of yet. But it sounds like we're on the same page, that this is how our software should be tested.<br><br></div><div>With this in mind, my proposal is:<br><br></div><div>* Define "API" for our software to be limited to public interfaces, classes and methods, but not behavior. This is what will be covered by SemVer.<br></div><div>* Develop Melting Pot tests to validate behavior and dependency convergence<br><br></div><div>Unless there are any objections to this, I will update <a href="http://imagej.net/Architecture#Versioning">http://imagej.net/Architecture#Versioning</a> to explicitly define API as such, and summarize the concerns that have been raised in this discussion - including how the Melting Pot will make everything happy.<br><br>>we're doomed.<br><br></div><div>Probably!<br><br>>Thanks for all the energy that you're putting into this!<br><br></div><div>You too!<br><br></div><div>Best,<br></div><div>Mark</div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Mar 27, 2015 at 10:06 PM, Stephan Saalfeld <span dir="ltr"><<a href="mailto:saalfelds@janelia.hhmi.org" target="_blank">saalfelds@janelia.hhmi.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Mark,<br>
<br>
>[...] but not the traditional definition of public API[1,2].<br>
<br>
This is what worries me because for most things that are less trivial<br>
than addition, `traditional' definitions are not available, i.e.<br>
`unintended' is not well defined.<br>
<span class=""><br>
> Just to make sure we're on the same page - when you say "changes the<br>
> output", I assume you mean "changes the behavior but not the API - i.e.<br>
> return type is unchanged"<br>
<br>
</span>In a typed language yes, what about Python? What I mean is indeed<br>
change in behavior---correct. I proposed to treat change in behavior as<br>
change of API because that would enable to reason about compatibility.<br>
If we enable PATCH upgrades to change behavior but only require `compile<br>
time' compatibility (which limits the scope of PATCH to statically typed<br>
and compiled languages which, I think, was not intended), then all we<br>
can reason from seeing a PATCH upgrade is that the stuff will compile,<br>
and somehow run, no guarantees about behavior. That's not very helpful<br>
because compiling and running stuff isn't expensive to just try.<br>
Behavior, however, is critical and complicated to test, having a<br>
contract that makes guarantees here would indeed be useful.<br>
<span class=""><br>
> In that case, I think it would be cleaner to just eliminate the PATCH<br>
> number - because every bug fix necessarily changes behavior, right? So with<br>
> this scheme, MAJOR increases = "existing behavior has changed", and MINOR<br>
> increases = "new behavior is available".<br>
><br>
<br>
</span>Not necessarily. Performance improvements, crash-fixes, compatibility<br>
adjustments to upgraded dependencies (!) would fall into PATCH. But I<br>
see that even crashes could be used by dependents as part of the API...<br>
we're doomed.<br>
<span class=""><br>
> Some problems with creating this versioning scheme:<br>
> 1. MAJOR versions will increase rapidly. This is aesthetic, but one that<br>
> people can react very negatively to - and can certainly be confusing if<br>
> people don't expect MAJOR version bumps to cover bug fixes.<br>
<br>
</span>Right---but SemVer is already counterintuitive compared to romantic<br>
versioning where a MAYOR upgrade is associated with a lot of new<br>
features, not breakage.<br>
<span class=""><br>
> 2. It's one more thing for external developers to learn. We can't just say<br>
> "we use SemVer".<br>
<br>
</span>Very true.<br>
<span class=""><br>
> 3. Since this is an internal versioning scheme, it may not be easy to<br>
> compare our versions with external project versions that use SemVer.<br>
<br>
</span>Why would we want to do this?<br>
<span class=""><br>
> 4. There will be false negatives for MAJOR version compatibility<br>
> comparisons (instead of what could be considered false positives with<br>
> SemVer)<br>
<br>
</span>I wouldn't call them false but conservative or overly cautious. It<br>
would tell you when compatibility is not guaranteed which is useful.<br>
<span class=""><br>
><br>
> Unfortunately, #1 above alone makes it very unlikely that we would want to<br>
> adopt this use of version numbers.<br>
<br>
</span>I understand and fully agree. But SemVer with PATCHES of `unintended<br>
behavior' or other sentimental or romantic versioning schemes (I am<br>
stealing these terms from<br>
<br>
<a href="https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e" target="_blank">https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e</a><br>
<br>
and<br>
<br>
<a href="http://sentimentalversioning.org/" target="_blank">http://sentimentalversioning.org/</a><br>
<br>
which are both exciting reads) aren't useful to reason about<br>
compatibility. We should therefore not use them to reason about<br>
compatibility which you correctly state in the following...<br>
<span class=""><br>
> But what you're trying to do here -<br>
> ensure compatibility - is fantastic and something that would be great to<br>
> have.<br>
><br>
> So let's take a step back and look at what guarantees we do and do not have<br>
> right now:<br>
><br>
> + We have reproducible builds (release couplings, which requires -some-<br>
> versioning scheme to be used)<br>
> + We have API compatibility (SemVer)<br>
><br>
<br>
</span>No---there is no strict API compatibility when using PATCH to fix<br>
`unintended behavior'. Happened with ImageJ many times over the last<br>
years: API compile-time compatible that would qualify as PATCH upgrade,<br>
behavior different, plugins delivering crazy output, discovered only<br>
much later through bug reports.<br>
<span class=""><br>
> - We do not have strict behavior compatibility<br>
> - We do not have dependency compatibility<br>
><br>
> Behavior and dependency compatibility are very closely related - if they<br>
> were covered by a versioning scheme, we could automatically answer the<br>
> question "is it safe to drop in version X to replace version Y?".<br>
><br>
<br>
</span>Yes.<br>
<span class=""><br>
> However, I do not think we should conflate these concerns with SemVer.<br>
<br>
</span>I could not agree more.<br>
<span class=""><br>
> Instead, two potential options would be:<br>
><br>
> 1) Continue to use SemVer, accept its limitations, be content with<br>
> reproducibility.<br>
<br>
</span>Or any other versioning scheme that people like. My current impression<br>
is that SemVer doesn't help much. I will keep using it, but it isn't<br>
any better than any other scheme that assigns keys to versions and<br>
enables to order them.<br>
<span class=""><br>
> 2) Create a separate versioning scheme that covers behavior and dependency<br>
> compatibility. Use it in tandem with SemVer.<br>
><br>
<br>
</span>You're absolutely right, but---phew---that's probably asking too much of<br>
people that are already unwilling to adopt to something as simple as<br>
SemVer.<br>
<br>
My current thinking is that we should require contributors to use a<br>
versioning scheme that can be sorted correctly by<br>
<br>
sort -V<br>
<br>
Anything else, i.e. compatibility guarantees, aren't possible to express<br>
with a simple number and require runtime testing (e.g. unit-tests<br>
promise this int an ideal world). We should therefore never drop any<br>
upgrade without significant attempt to test. We could assume that a<br>
maven build includes sufficient [unit-]testing to enable deployment if<br>
it succeeds (this is not true in reality but it is a meaningful<br>
contract). I.e. artifacts can be deployed if they were explicitly built<br>
against upgraded dependencies. In our heterogeneous environment,<br>
however, it is unrealistic to expect all contributors to adapt their<br>
code in time. Instead, we should try to build pom-fiji including all<br>
downstream modules *overriding* or *upgrading* their dependency versions<br>
to the highest possible. Do you have something like this already or do<br>
you have an idea how that could be done?<br>
<br>
Thanks for all the energy that you're putting into this!<br>
<br>
Cheers,<br>
Stephan<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
<br>
> If anyone can think of other examples of versioned guarantees that would be<br>
> useful to have, or counter-examples to any claims made here - please share!<br>
><br>
> Also, please let me know if any of this is confusing and/or additional<br>
> examples would be useful.<br>
><br>
> Thanks again for the continued discussion,<br>
> Mark<br>
><br>
> [1]<br>
> <a href="http://en.wikipedia.org/wiki/Application_programming_interface#API_in_object-oriented_languages" target="_blank">http://en.wikipedia.org/wiki/Application_programming_interface#API_in_object-oriented_languages</a><br>
> [2]<br>
> <a href="http://stackoverflow.com/questions/2954372/difference-between-spi-and-api" target="_blank">http://stackoverflow.com/questions/2954372/difference-between-spi-and-api</a><br>
<br>
</div></div></blockquote></div><br></div>