JuliaLang / Juleps

Julia Enhancement Proposals
Other
67 stars 24 forks source link

Don't use semantic versioning for Pkg3 #33

Closed DataDaoDe closed 7 years ago

DataDaoDe commented 7 years ago

I know this sounds like heresy but please hear out my argument.

Semantic versioning basically just tells me whether my code will explode or not. For example a library I'm depending on changes from 1.0.3 to 1.0.4 I don't care my code will work. If it changes to 1.1.4 I don't care because my code will work. If it changes to 2.0.0 I care because my code will explode. This is literally all the information I get out of semantic versioning.

Now if pkg3 were to use a system like the following: <number>:<timestamp> for package versioning it would be much easier to implement and reason about than semantic versioning and it would give me, the end user, more information than semantic versioning.

Here's how this versioning system would work:

I create a package called foo with a version 1:1494423107554 where the number 14944... is just a timestamp. Now everytime I want to release a non-breaking change of my package I just update the timestamp, so for instance I change some internal crap and then I publish 1:1494423232649. Any consumer of my library now knows that they can use my library no problem, also its easy to always stay updated with the latest non-breaking change - you just pull the latest timestamp.

Finally, anytime I want to release a breaking change I just increment the initial number. For example, now I want to change some public api function so I do it and release a new version of my lib as 2:1494423377157.

This seems a lot simpler to me (especially from an implementation and usage perspective) and it also increases the amount of information conveyed to the end user (now every user knows when a package was published which is something I do not know when looking at a version like 1.0.3).

Lastly, in case anyone thinks it would be annoying to update the timestamp we all know that could be easily automated by a simple scripting command.

Thoughts?

ChrisRackauckas commented 7 years ago

This seems a lot simpler to me (especially from an implementation and usage perspective) and it also increases the amount of information conveyed to the end user (now every user knows when a package was published which is something I do not know when looking at a version like 1.0.3).

But that's already available on Github. I just think this is a convoluted solution to no problem, and goes in the opposite direction. You should care about patches and minor versions: they tell you information that you don't want to lump together. It's easier to know/remember what minor version you need than what timestamp you need.

oxinabox commented 7 years ago

SemVer is for humans. It is easily readable. I can readily tell the look at a short number like v12.9.2 and know that it is larger than v12.1.2.
I can not as easily look at v12:1494423107554 and know that it is larger than v12:1494323001221

Under SemVer 2 you are free to use ticks as part Build Metadata (not used for precedence (IIRC)) eg v12.0.0+1494323001221 or as prerelease info (used for precedence) v12.0.0-1494323001221. And only incrementing the major version number. That is fully legal semver

Though idk if METADATA moderators will be happy with allowing tagging release with prerelease tag info. Pkg2 certainly has the capacity to deal with things tagged this way as part of the require file.

SemVer (and similar concepts) is good.

DataDaoDe commented 7 years ago

@ChrisRackauckas

"you should care about patches and minor versions: they tell you information that you don't want to lump together."

You should but in practice no one does. Tell me the last time you as a user actually cared about the difference between a patch and minor version.

"It's easier to know/remember what minor version you need than what timestamp you need."

In practice you won't need to know the timestamp. You'll just need to know if you're using 1 or 2 or 3 or whatever b/c you can more or less sit on the latest timestamp. There might be some rare occasions where you need to a particular timestamp version. But I think it would be very rare. I'd say its happen to me maybe 5 times over the course of the last 5 years with a massive project. Otherwise I just care about v1 or v2 and the latest.

@oxinabox

"I can readily tell the look at a short number like v12.9.2 and know that it is larger than v12.1.2."

That's all I know and my point is I don't care. v12.9.2 is the same major as v12.1.2, thus I know there are no breaking changes so I just want the latest version. This is by far (maybe 95% of the time) the case.

"I can not as easily look at v12:1494423107554 and know that it is larger than v12:1494323001221"

In most (90%) cases you won't have to. Good editors, browsers, machine tools could easily parse this for you and render the actual dates. But the real point is I don't care which one is newer but in the case I do, this versioning scheme allows me to know the last time someone updated the package, with semver I have no idea just some vague notion that v1.0.1 occurred after v1.0.0.

"SemVer (and similar concepts) is good.*

SemVer conveys basically no information. From an information theoretical standpoint I could easily create a 4 computer bit (one hexadecimal digit) protocol that conveyed much more information (16 various states of affairs) than semver does. Semver uses 12 computer bits (ignoring the dots etc) to convey 2 states (it breaks my code, it doesn't break my code).

What you mean by similar concepts? Do you mean knowing whether a library I depend upon breaks my code or not? Yes I agree that is good.

ChrisRackauckas commented 7 years ago

You should but in practice no one does. Tell me the last time you as a user actually cared about the difference between a patch and minor version.

? People who build large libraries are using this daily!

I don't care about ForwardDiff's patches, but am looking for their minor version which adds in place derivative! which will be used in OrdinaryDiffEq.jl (minor version minimum requirement will be needed). Looking for SymEngine.jl's next minor (0.2.0) since that's when its libsymengine.dll updates, at which point ParameterizedFunctions.jl's change. Lots of minor version requirements are on libraries for these kinds of feature additions. That's what this is for.

When a user posts a bug report, I can also easily check this Pkg.status() and know what they should and should not have. That's major/minor is a huge indicator of feature support.

I agree that for small scripts which most users write, this isn't that important. But this difference between patches and minor/feature updates is very important for building and managing large modular package ecosystems.

MikeInnes commented 7 years ago

There are two separate issues here:

If both are true then it might make sense to use the timestamp as the minor version.

For the first point, it's common to pin a minor version to get patches but not new features. This hasn't really been used carefully in the Julia world; many packages just use 0.x.y which ends up equivalent. But it's more future proof; eventually, someone will want ultra-stability with only very small security patches, making semver more useful.

As to the timestamp... why? Why that specific piece of information and not others? I can't remember the last time I wanted to compare package release times, so it's weird to argue for utility of information and then propose that.

SemVer has the added benefit of being universally recognisable to users, regardless of whether it's a global optimum. I don't think this is something we want to innovate on, so this argument isn't worth having unless there are some much more compelling reasons.

DataDaoDe commented 7 years ago

@ChrisRackauckas ok so you say you care about differences between minor and patch.

you are "Looking for SymEngine.jl's next minor (0.2.0) since that's when its libsymengine.dll updates,"

This is a non-breaking change. You couldn't just get the latest release inside the major version when they update their package to 0.2.0? It sounds to me like thats exactly what you're doing you're just calling it the next minor release when really you just want the latest update inside the major version 0.

". Lots of minor version requirements are on libraries for these kinds of feature additions. That's what this is for."

This all falls away since in my version you can always pull from the latest timestamp and you know you can safely do this.

Right now we use semver to say oh I need feature X from v1.0.5 so the dependency must be at least v1.0.5. In my versioning scheme you just say I need v1 and you can always pull the latest and on the off chance you want to use some specific release you can optionally add the timestamp.

"When a user posts a bug report, I can also easily check this Pkg.status() and know what they should and should not have. That's major/minor is a huge indicator of feature support."

This is a valid point. To make this experience optimal you would need to sync your release with a git tag. Then its just copy/paste and checkout that tag.

ChrisRackauckas commented 7 years ago

To make this experience optimal you would need to sync your release with a git tag. Then its just copy/paste and checkout that tag.

All releases are Git tags.

This all falls away since in my version you can always pull from the latest timestamp and you know you can safely do this.

You can only depend on released versions, and hence Git tagged versions of repos.

In my versioning scheme you just say I need v1 and you can always pull the latest and on the off chance you want to use some specific release you can optionally add the timestamp.

No, you should say you need v1.0.5 if that's what you need. Not that there will be a new feature there: that's a patch and not a minor version, so that's a bad example. But sure, sometimes you'll need the patch. You should lower version require that. If someone else is upper version requiring <v1.0.5, the user should be notified that there's no way to make these packages work. Otherwise you're letting things silently fail.

This is a non-breaking change. You couldn't just get the latest release inside the major version when they update their package to 0.2.0?

Technically non-breaking. But patches can change behavior in subtle ways that aren't expected, that might break something even when the other library thought it's a non-breaking change.

DataDaoDe commented 7 years ago

@MikeInnes As to the timestamp... why? Why that specific piece of information and not others?

Because it makes implementing the whole thing a piece of cake. Its super simple comparisons at that point not the more complicated things you have to do when implementing a semver pkg manager. Also this is information that is easily automated by machines so you get it for free (I can easily have my tools automatically update the timestamp everytime I release a package).

" I don't think this is something we want to innovate on, so this argument isn't worth having unless there are some much more compelling reasons."

Okay I'm fine with that. Thanks for giving me feedback.

MikeInnes commented 7 years ago

It's not easier to implement than incrementing an integer, especially if you need extra tooling to make it readable.

DataDaoDe commented 7 years ago

I simply do not agree that (computationally) comparing a timestamp with another one is more difficult than comparing three integers all of which depend on various operators to give them their comparative meanings (i.e. ~ ^, etc ). I've written a semver parsing library so I should know.

Anyway if you get caught up on the whole timestamp thing you could just use a single number and have the same amount of information semver conveys.