
Chronologic Versioning: No more arbitrary version updates and regressions - pcr910303
https://chronver.org
======
smitty1e
Stylistic versioning was conquered years ago by TeX.

"The current version of TeX is 3.14159265; it was last updated on January 12,
2014. The design was frozen after version 3.0, and no new feature or
fundamental change will be added, so all newer versions will contain only bug
fixes. Even though Donald Knuth himself has suggested a few areas in which TeX
could have been improved, he indicated that he firmly believes that having an
unchanged system that will produce the same output now and in the future is
more important than introducing new features. For this reason, he has stated
that the "absolutely final change (to be made after my death)" will be to
change the version number to π, at which point all remaining bugs will become
features. Likewise, versions of Metafont after 2.0 asymptotically approach e
(currently at 2.7182818), and a similar change will be applied after Knuth's
death."

[https://en.m.wikipedia.org/wiki/TeX](https://en.m.wikipedia.org/wiki/TeX)

~~~
jacquesm
> he indicated that he firmly believes that having an unchanged system that
> will produce the same output now and in the future is more important than
> introducing new features

I sincerely wished that that was a more common sentiment. All this change for
nothing doesn't move the needle at all and irritates users the world over.

~~~
qwerty1234599
Oh really? You want an IE6 situation to happen for every software out there?

------
kstenerud
This will break when you need to support two tracks of your library. Also,
deprecation is not a breaking change; it is notification that a breaking
change is in the pipeline, but hasn't happened yet.

A better approach would be hybrid:

2.2020.01.01.3-bd

Where the first number is the release track, the next three are the date, the
last number is to handle multiple releases in a day, and the letters (always
in alphabetical order) are codes for:

b: this is a breaking change

d: there are deprecations in this release

I would also suggest a third letter code "z" to mark bad releases, where you
unintentionally broke things to the point that this release should not be used
(and for whatever reason cannot retract the release). So, to mark the above
release as bad, tag the exact same version a second time:

2.2020.01.01.3-z

Which means that 2.2020.01.01.3 is a bad release. It will show up after
2.2020.01.01.3-bd because it's later in the alphabet in the release list.
Anyone looking for the last release that matches whatever their criteria is
will now know to avoid that particular version.

Edit: Formalized here:
[https://github.com/kstenerud/hyver](https://github.com/kstenerud/hyver)

~~~
masklinn
Has the same fundamental problem as tfa: codes are not sticky / spanned so to
know what sort of changes you should expect between two versions you have to
look at every intermediate.

Meaning the tag is useless. If a release is “bad” you just yank it.

> it will show up as after 2.2020.1.1.3-bd

According to your scheme the last number is the release index in the day so
this is nonsense: either -z replaces -bd or it’s a later release which appears
before in the release list (assuming you have a descending alphanumeric sort).

You wouldn’t have _both_ 2.2020.1.1.3-bd and 2.2020.1.1.3-z because they’re
the same release with different crap tacked on.

~~~
kstenerud
> codes are not sticky / spanned so to know what sort of changes you should
> expect between two versions you have to look at every intermediate.

The only changes people usually care about are "will it break my software?"
and "Am I using deprecated calls?" Beyond that, there's no standardized way to
know what has changed between releases, and you'd have to look at every
release regardless. Of course we could always add another metadata letter "n"
to signify "new features". In fact, I'll add it...

> If a release is “bad” you just yank it.

And what if you can't yank it? That's what the "z" tag is for. If you can yank
it then by all means yank it.

~~~
naniwaduni
How are you going to relabel it when you can't yank it?

~~~
kstenerud
You don't. You create a second "marker" release whose only purpose is to
announce to the world that this release is bad.

Example:

Current release list:

    
    
        ...
        2.2019.12.18.1
        2.2019.12.19.1-n
        2.2019.12.19.2
        2.2020.01.01.3-bd
    

Bad release you can't yank: 2.2020.01.01.3-bd

Create a new marker release: 2.2020.01.01.3-z

New release list:

    
    
        ...
        2.2019.12.18.1
        2.2019.12.19.1-n
        2.2019.12.19.2
        2.2020.01.01.3-bd
        2.2020.01.01.3-z
    

Now everyone knows that 2.2020.01.01.3 is bad but couldn't be yanked.

------
moreira
For those trying to compare it to SemVer, ChronVer seems to have a different
target. It mentions web applications and systems that see releases (with
continuous delivery or not).

SemVer remains good for libraries, or anything where there's a clearly-defined
API for consumption, because it clearly establishes a set of rules for what to
expect. If you're using version 1.0.0 and upgrade to 1.10.30, with SemVer it
would remain perfectly compatible, and no change should be required on your
part (that's the ideal; of course developers are free to use whatever versions
they want and pretend it's valid SemVer).

For applications though, I agree that ChronVer seems far more useful, because
there's just no real "compatibility" contract with an application. After all,
macOS 2017.09.25 seems far more descriptive than "10.13", which means nothing
to anyone.

~~~
flukus
> For applications though, I agree that ChronVer seems far more useful,
> because there's just no real "compatibility" contract with an application.

It's unfortunately becoming less common but there is still a "compatability
contract" between developers and users. With 10.13 -> 10.14 upgrade I would
expect no major disruptions as a user, I would expect the UI to be nearly
identical and no features to be dropped. With a 10.13 -> 11.1 upgrade I would
expect "breaking" changes to my interactions and plan to install the update at
a convenient time to deal with this. For a 2017.05 -> 2019.08 upgrade I have
no indication of what to expect.

For something like continuously delivered web applications I don't think any
versioning scheme makes sense to user because they have zero control, it's
useless information.

~~~
magicalhippo
This is how we do it at work. Features and major changes go into trunk, which
gets released in the new versions. Bug fixes get released in earlier versions
and up.

We do major.minor version numbers, with even major versions being releases and
odd being development versions. We also have an user-selectable way to pick
version (major and minor) of our program at launch. So if we "dun goofed" in
one version, the user can always just relaunch the previous version which
worked.

Right before xmas I changed it so that if you didn't enter a first name, it
would skip the rest of the name and address fields. This went into a new major
version, so users were not that surprised to discover this rather big change
in UI flow.

However I had missed that in one special case, users were required to enter a
postal code. The user that reported this could then just launch the previous
major version until I got that issue sorted, getting bug fixes for other
issues in the meantime.

------
dathinab
Ok for user facing programs horrible for libraries as you can no longer tell
which versions have just internal bug fixes, which add additional interface in
a backwards compatible way and which are being changes.

Also this makes it impossible/stupidly hard to release security patches for a
older but stable version of a library when a new version with a largely
changed API is released (which might not yet be feature completely)

Sure there are some ecosystems what a lot of authors don't do semver right, or
where due to (mostly dynamic) aspects of the language this is harder then it
should be.

But why not: 1\. Require semver for a ecosystem/package manage which clear
rules as what constitutes as a breaking change 2\. Remove/ban packages which
don't keep with it (or at last put a warning up). Authors who don't like it
can still release a major version update Everytime.

Honestly if this schema would be used in a library ecosystem thinks would be
pretty fast become pretty bad with you having to pull in tens of versions of
the same fundamental dependency which might even all be compatible but you
can't tell automatically and have to check by hand which isn't something you
can afford time wise.

------
saxonww
Two big problems with this:

\- Does not support multiple release tracks. What if you have 'version 1' and
'version 2' with both receiving updates?

\- Cannot visually guarantee that any version is greater than, less than, or
equal to another. If you're using git, mercurial, or any other VCS with hash-
based commit IDs, how can a user tell which release for a particular day is
the latest?

This is probably fine for SaaS stuff where you only support one version at a
time and the version number is more important to you than your users.

~~~
kazinator
When version 1 receives an update, that's how we got version 2. The update to
version 2 is version 3.

I don't see what is here to misunderstand.

If someone wants to take just a subset of the changes between 2 and 3 (say
just one fix) and backport it over version 1, they are on their own.

That's a downstream problem that the project doesn't have to cater to in its
versioning scheme. The project issued a bugfix, and that bugfix was applied
when version 2 was superseded with 3; end of story.

~~~
rusticpenn
The problem with this is that it is not practical. One example I can think of
on the spot is an old tool written to support Windows 7, a bridge version
supporting win 7-10 and a new version supporting only 10. Most industries do
not move at the same pace (We have some projects that can only run on Windows
95). So some security updates to the bridge version adn the new version are
made simultaneosly and corresponding update to their version numbers.

Another example is python 2 and python 3, where python 2 was getting updates
form 5+ years after python 3 released.

~~~
kazinator
Python 2 and Python 3 are different languages that get installed side by side.

Two completely independently developed C compilers, or independent
implementations of Common Lisp are much more compatible with each other than
are Python 2 and Python 3.

They could as well have different names (think Perl vs. Rakudo).

Racket is more compatible with Scheme than Python 3 is with Python 2, yet has
a different name, for good reasons.

Both Python 2 and Python 3 could respectively use a simple versioning
numbering scheme. Python 3 version 1, version 2, version 3, ...

------
kazinator
Too complicated. Here is a better chronological versioning: 1, 2, 3, 4, ...

Given two versions j and k, those being integers if j > k, then j is
chronologically later than k.

That's what I use on the TXR project.

That being at version 230 means I made 230 releases since the project started
in 2009.

Since that number "means" something, it has semantics; therefore, it is not
only chronological but also semantic.

~~~
jacquesm
Totally agreed. This is seriously overthought. Users need to be able to tell
in an eyeblink what the order is without reference to some standards document.
Presumably everybody to whom it applies can count.

~~~
true_religion
For a web app under continuous release, I would suggest doing both.

230-12-01-2020 to mean the 230th release since the start of the project, made
on January 1st, 2020.

~~~
oneeyedpigeon
Why not 230-2020-12-01 to avoid the awkward 'US order or 'most-of-the-rest-of-
the-world order' issue?

Edit: the great irony is that your example included an error which I then
reproduced! Obviously, 1st jan is unambiguously:

230-2020-01-01

If you were representing 1st _dec_ , though, I’d suggest:

230-2020-12-01

~~~
true_religion
Actually I was trying to avoid the US date standard myself, then got confused
and wrote a date that follows no standard that I know of. My mistake entirely.

------
kamikaz1k
Seems to be solving the same problem as CalVer[1]?

I've used it in the past for Continuously Deployed web applications. The dates
make it easy to determine the age of the release, and it's easy to automate
away to a CI job[2].

[1] [https://calver.org/](https://calver.org/) [2]
[https://dephell.readthedocs.io/cmd-project-
bump.html](https://dephell.readthedocs.io/cmd-project-bump.html)

~~~
NetOpWibby
The author of CalVer emailed today, I had no idea their project (or mine) was
posted to HN! But yes, they are similar.

I'm biased but I like mine more (and have an npm module to increment
automatically).

------
amflare
Okay, but I _rarely_ need to know _when_ a version was released. I almost
_always_ need to know how a version relates to the version I'm currently
using. SemVer does this, and to an extent, "normal" non-SemVer also does this.
ChronVer is a textual representation of that green calendar on GitHub.

------
VLM
There's a RFC 1912 from 1996 explaining this versioning strategy which was
already in common use for DNS SOA record serial numbers.

[https://tools.ietf.org/html/rfc1912](https://tools.ietf.org/html/rfc1912)

I'm sure this strategy vastly predates 1996 in other computer applications.

Julian dates have a similar purpose, and have been used in the US Military
Logistics system for a very long time, but I can't figure out how far back.
Also some food products, beer especially, with "secret" expiration or
manufacture dates, according to civilians anyway, are often strangely
formatted Julian dates.

~~~
ctvo
Agreed it's not a new idea, but I'm not discounting adding a catchy name to it
and a well-made website with a clear specification. That will get people using
it in some open-source communities (Node / JavaScript specifically).

The problem with SemVer is that library owners are not strict with its
intended usage (backwards incompatible changes in patch!) or don't fully
understand it. Perhaps having a much more simple versioning strategy will help
in some use cases.

~~~
VLM
Sorry for the super late followup, but yeah my point was a pretty good selling
point might be its been an operationally useful, apparently optimized, and
successful solution for many decades in the fields of X, Y, and Z, and the
more examples of success, the better.

------
andrey_utkin
The Motivation is dependency hell, the Rationale says the version is easy to
understand at a glance. So, Rationale has missed the opportunity to explain
how this is a solution to the declared problem.

~~~
Izkata
Honestly, the intent there seems easy: it's hard to tell at a glance that
library A version 230 is compatible with library B version 1.2.4

However, if they both used date-based versioning, then the compatible versions
would in theory have the same-ish version of 2019.12.* when compatible with
each other.

For the same reasons as in tons of other comments, I also don't think this
theory would work out.

------
anonymfus
_> If backwards incompatible changes are introduced you MUST append a hyphen
and the reserved label "break". For instance: 2006.04.03.12 >
2006.04.03.12-break._

So with this system if you want to know whether two versions are compatible
you would need to check versions of all releases between them for not having
that label...

~~~
NetOpWibby
It's the best I could come up with when drafting this. What would you like to
see?

------
jl6
I just wish the idea of software being _finished_ came back into vogue.

------
neilobremski
I'll agree with the point that "version numbers are useless to the end user"
except when there's an incompatibility. To that end, I'd prefer release tracks
to be indicated in the TITLE and breaking (API) changes in the VERSION. Any
other number in the version is essentially irrelevant.

Then again perhaps in web apps there's something to be said for this when
breaking changes ARE the consistency. I have to say that working in back-end
technology, I don't really care whether something was built in 2010 or 2020 as
long as it's doing its job well.

Unfortunately, most back-end technology still communicates with web API's at
some point and then we're at the mercy of the service's "version".

~~~
NetOpWibby
Yeah that's a good point.

------
ipodopt
The idea rubs me the right way but why not 1, 2, 3...

I think a more modular versioning standard might be good as semantic
versioning can be very helpful in certain projects like libraries.

Like if your project has x abstract property then include x. and y for a x.y
versioning scheme.

~~~
slowmovintarget
To paraphrase Rich Hickey: "Just use a different name."

Compatibility of APIs is retained if you require less or provide more.
Breaking changes happen when you require more or provide less. Don't do it.
Add a new and different function that requires more or provides less. Keep the
old one. You now have a backward compatible interface.

------
velcrovan
Pollen has my favorite version numbering system, a blend of semantic and
chronologic:

> “Consistent with Racket’s version-numbering system, the first digit reflects
> major updates to Pollen that break backward compatibility. The second digit
> reflects feature updates that don’t affect existing features. > >
> “Inconsistent with this system, Pollen’s version also appends a build
> number, which is the age of the software in days and minutes.”

— [https://docs.racket-lang.org/pollen/version-
notes.html](https://docs.racket-lang.org/pollen/version-notes.html)

~~~
rodw
As far as I can tell I actually tend to use something like this also (semver
annotated with some form of timestamp, if only so I can tell at a glance how
old something is, but usually as two distinct fields), but even after looking
at the linked site I'm confused by what "the age of the software in days and
minutes" means exactly.

The current version is reported as 2.1.2329.415.

Does that mean this release (roughly v2.1.something) was
compiled/packaged/released 2329 days and 415 minutes after some arbitrary
project-start timestamp? That this was compiled/packaged/released 2329 days
and 415 minutes _ago_? Are those literally the "days" and "minutes" fields
they're talking about?

The former seems kinda crazy (as the version number would be mutable) but to
be honest that's how I'd naively interpret "the age of the software" \- I want
to know how long ago this build was created, not how long after the project
was first started.

If the version number is days-after-project start, why not just use the actual
date? What's the value of the arbitrary baseline?

(Actually, now that I think about it I guess the arbitrary baseline does have
an advantage if you are intentionally trying to obscure how old the build is
in calendar time. *.2329.415 provides an easily interpreted, monotonically
increasing identifier without making it obvious if this release happened
yesterday or 10 years ago. I.e., this solves the problem that products with
the year-of-release in their name have - surely people are eventually stop
buying FooBar2015, whether or not there's a real need for an update in the
past 5 years.)

------
slifin
Version number is too blunt an instrument

Ideally I want enough introspection in my tooling to automatically pick up
breaking changes by doing static analysis between versions and where breaking
changes are impossible to detect I want humans to tell me what the breaking
changes are in a structured way

I want my dependency manager to take me up to the next breakage free version
and to see what the breaking changes are if specified, maybe with programmatic
suggestions/fixes from the library maintainer

And perhaps hardest of all I want the culture of change to being hyper
allergic to breaking changes in the rich hickey sense

------
thrower123
I don't much care how you choose to number your versions, as long as you
publish release notes with it that say what has changed since the previous
version. If I have to start poking around in the commit history of your GitHub
project and trying to suss out how those commits correspond to published
releases, I start to get a little irate.

This is an enormous pain in the ass with .NET NuGet packages, I have found,
although I am sure it extends into other ecosystems as well.

------
tyleo
We used this version scheme at my last job. I have fond memories of it. It’s
easy to think in days/months/years. When a bug was found we could load old
versions to see when it first materialized. Because The date information was
contained in the version it was easy to remember what else was happening
around the same time and what could have caused it.

~~~
NetOpWibby
Yes, that's one of the reasons I created this. Well, bought a domain name and
made a webpage anyway, haha.

------
floatingatoll
There’s one or two Perl5 modules that are version yyyymmdd.nn that expect
you’ll only do less than 100 releases per day.

It turns out one of the more interesting problems with version numbers is
tools that assume that each number will fit within 2^8, or 2^16.

------
thrill
I like versioning things as YYYY.MMDD.HHmm

2020.0102.0345 if you stick to GMT.

------
NetOpWibby
I wasn't checking my analytics so I was quite surprised to see this here. I'm
almost a week late but I'll look at all the comments now.

------
cryptonector
A major version number is still needed. ChronVer seems fine as a replacement
for minor and micro versions (and rc and other designations).

------
rkagerer
Or just start at 1 and increment every build.

------
6510
I needed this one time when I had machine generated versions. I just append
.unixtime to the version.

------
jaxn
Tesla does something similar. They use year.week.patch.build (or something
like that).

------
jayd16
Changeset isn't enough. You need build number too or rebuilds will collide.

------
pisipisipisi
Calver?

------
LoSboccacc
begins having to have version to manage dependencies this does nothing to
solve dependency hell, to the point I question whether the author has a clear
understanding of the problem space

