CalVer: Calendar Versioning
calver.org
calver.org
Also, the "When to use" section is getting things quite wrong:
Does your project feature a large or constantly-changing scope?
Large systems and frameworks, like Ubuntu and Twisted.
Amorphous sets of utilities, like Boltons.
Wrong question - relevant is: "is your project the top end of the dependency chain?" Is your project time-sensitive in any way? Do other external changes drive new project releases?
Business requirements, such as Ubuntu's focus on support schedules.
Security updates, such as certifi's need to update certificates.
And both of these are actually made much harder by calendaric versioning. Administrators are already reluctant to update software for fear of breaking things. SemVer gives extremely useful information here to establish how "dangerous" and update might be. With date code versions, the admin is forced to dig through change logs, which costs time they probably don't have, so they'll just not update.Also, now you just have SemVer with really large version numbers.
Released 2020-04-05, updated 2020-10-15.
Version: 2004.201015
I'm not in love with that, but that's how I'd assume it'd work.
The whole point of CalVer as an alternative is that SemVer has sold folks a bill of goods with regard to software maintenance. Perpetuating the idea that people can blindly update will always create problems.
More discussion here: https://sedimental.org/designing_a_version.html
Why what? (I seriously don't understand what argument you're trying to make in your first paragraph.)
> [...] SemVer has sold folks a bill of goods with regard to software maintenance. Perpetuating the idea that people can blindly update will always create problems.
You're forgetting to ask the question whether this bill of goods is desirable. Considering the environment we have today (frequent security updates, huge dependency chains, interconnected systems), I'd say it's not just desirable but straight up necessary. People should be able to blindly update. They need to be able to, because users are not developers and updates need to be made as accessible as possible in order to propagate and proliferate as quickly as possible.
What we need is better testing and release engineering to get SemVer right, not defining the problem away by ditching a layer of usability.
As far as usability, time is a dimension no developer can escape. We develop software on a schedule and we deprecate it on a schedule. CalVer is tremendously semantic at that higher level. The semantics SemVer clings to suffer even under ecosystems which have mandated their use (go, node). The effect has been an over-granularization of APIs themselves.
I'm fine with agreeing to disagree for now. I'm also fine with the case that CalVer is not for everyone and everything. I'll leave it with this, a post seems to articulate a lot of your concerns: https://caremad.io/posts/2016/02/versioning-software/
It was written in 2016 by Donald Stufft, a maintainer of pip. Today, pip has been CalVer for a while and I'm not sure anyone has looked back. Try it sometime, and you might find the same. :)
Now you have a choice of either incrementing the date code liberally for small releases (e.g. Twisted), or keeping it sticky until you make a major change (e.g. Teradata.)
If you do the former, you're depriving the user (or chain-up developer) of information on how big a particular change was. It might be 20190322 to 20190411 but you merged a huge rewrite. Or it's 20180107 to 20190929 and it's just some fixes. You might as well give your releases alphabetically increasing codenames, same information content there.
On the other hand if you keep it sticky until you make a major change, you're back to making a call whether some change is "major" or not. You might as well use SemVer. If anything, a date code in front of the version number becomes misleading since if you reach a reasonably stable API it'll start getting weirdly old and confuse users.
I also find it funny (and somewhat disingenious) that you assume I never tried calendaric versioning. I use (or suggest) it whenever some project starts or otherwise (e.g. rewrite) goes through an instability period. This generally means version numbers like "0.20190811". When the instability period has passed, it moves to e.g. "1.0" and sticks with SemVer from there. If we start rewriting on top of 2.3, the version number might temporarily be e.g. "2.99.20200105". Exact numbers (and components/dot count) depends on the specific situation.
It's hopefully obvious that all of these versions are something I'd call "alpha" or "internal consumption". (Also means my brain has learned prejudice to distrust any version number with a date code.)
[Edited] P.S.: developers can't escape time, but code can. I recently dug up a project I last touched in 2007, and you know what? I don't even get compiler warnings. It just works. (It's obviously written in a language & ecosystem that affords this possibility — not all of them do.)
I'm doubtful about how useful the information SemVer gives really is. Someone can make massive changes to a package, rewrite half of it from scratch, add huge new features, completely redesign how parts of it are implemented, but if they don't making any breaking API changes the first version segment doesn't increment. On the other hand, someone removes some obscure feature which nobody ever used anyway, and that causes the first version segment to increment. The administrator should be much more worried about the first change than the second, but SemVer misleads them into being more worried about the second than the first.
The point of SemVer is to answer "if I trust the authors of this library to be as good or better than me at writing libraries, is it safe to upgrade?". The moment you don't trust the authors of the library to be as good or better than you it sorta breaks apart as a covenant, but it will still show the intent of the author.
So SemVer has problems, but CalVer just shows "I tagged a release at a date".
IMO badly practiced SemVer is better than perfect CalVer simply because I can open an issue of fix something that was broken because of SemVer, but with CalVer I need to live with any breakages regardless of if they were intentional or not.
Imagine researching some libraries and having to decide over which one to use, say LibA v2020.01.06 vs LibB 2019.12.31. These versions tell you nothing about the projects except their release dates.
On the other hand, semantic versioning (when not abused) – say LibA v3.0.1 vs LibB 1.0.0 – reveals something useful, such as, that LibA has undergone three major revisions, so perhaps it is much more mature than LibB.
Perhaps the calendar versioning works well with already mature and famous projects – e.g. Ubuntu 18.04, etc – but for smaller projects I don't think it's such a good idea.
Comment v1.0.4-20jan06
edit: I'm also a huge fan because unlike semver it can be easily generated in a CD pipeline.
- Number of commits.
- Number of open issues.
- Number of closed issues.
- How they respond to issues.
- Are the commit messages descriptive?
- Is the codebase a mess or does it look reasonable?
can't answer one and the other consistently.
it's great for compatibility level, and that's that.
- it is poorly maintained
- the authors are being lazy
- it's some kind of unofficial patch or build
- marketing has taken over
- nostalgia (for Windows 95?) or imitating turn of the century project marketing
I don't think there's a good reason to ever deviate from the simple [$MAJOR_CHANGES].[$NEW_FEATURES].[$PATCH]. I don't even think it needs to be formally specified (looking at you SemVer). Simple 3-tuple versioning is almost universally understood. Why fix what isn't broken?
It can also mean that LibA messed up their API design twice and had to break BC twice while LibB worked diligently to provide a design that nailed it at first try or spent years in 0.XX territory and only called it stable when they were certain it's stable.
I don't consider SemVer useful to compare the maturity of software components. It's not a statement about that. It's useful to get a grip on how hard it's likely to be to go from one version to the next one.
local date=$(git log -1 --format="%cd" --date=short | sed s/-//g)
local count=$(git rev-list --count HEAD)
local commit=$(git rev-parse --short HEAD)
echo "$date.${count}_$commit"
Example result: 20191121.68_84f90ff
It provides user about general information about when program was updated along with specific information for developer for bug reporting. Also, it allows intraday releases. printf "%s.%03d_%s\n" $date $count $commit main() {
local count=$(git rev-list --count HEAD)
echo $count
foo
}
foo() {
echo $count
}
main
prints:2282 2282
Anyways there are some more subtle caveats discussed in this blogpost I was trying to remember:
(This is for software that does not do updates to old releases. If you do updates to old releases, you need an additional version number component for that.)
Then I thought about how meeting requests are basically PRs. How how easy it could be to create shared calendars using submodules and such.
If I want to share a calendar with my spouse, do I need to get two subscriptions? No. You can just create a normal subscription for yourself, and an "Associate" subscription for your spouse. Then share the calendar with the second account, and that's it. However, Associate accounts can't create their own calendars. So in order to have a personal calendar (that you can't see), your spouse will have to get a normal subscription too.
For example, you might release a hotfix patch today that fixes a bug in all major versions of your software. Using calendar versioning as a patch number would give something like
- 3.4.20200106
- 2.1.20200106
- 1.5.20200106
making it very easy to tell whether a particular version includes todays fix or not.
During this episode Marco explains his decision to switch to YYYY.MINOR.MICRO scheme for Overcast, his podcast player.
> [...]
> Note that traditional, incremented version numbers are 0-based, whereas date segments are 1-based, and the short and zero-padded years are relative to the year 2000.
Y3K here we come!
There is software still running from over 50 years ago. I'd imagine new releases have come out. But, this may be a legit problem some day.
For things like Ubuntu yes, it makes sense because you wouldn't just run a command to upgrade your os.
However, your code you usually has a bunch of libraries that depends on. When I upgrade a library I don't care when the new version came out, all I care is that doesn't have breaking changes.
With semver I can get this information at a glance, calver on the other hand just says "newer version".
As others have mentioned, some combination of both approaches might give an extra data point for "freshness" especially if you're managing multiple versions, but even then what's wrong with just bumping the minor/patch?
It works well where you've got no commitment or requirement to release patches of old versions rather than roll forward. In my experience, that covers most internal software, where semver is overkill.
Every version potentially breaks backward compatibility, regardless of versioning standard (semver, calver, or anything else). It's the responsibility of the module consumer to have tests and ensure its own functioning.
I do find semantic versioning useful for public-facing modules/interfaces, to indicate (or infer from the consumer side) the intended compatibility. In practice, though, sometimes patch versions break things, or major version upgrades work fine without any changes. So the consumer still needs to be responsible for ensuring compatibility - not much different than calendar versioning.
https://tools.ietf.org/html/draft-ietf-tls-oldversions-depre...
Although I liked its original name (oldversions-die-die-die) obviously that's one of many things that couldn't survive in a publicly endorsed document.
But other than that, I think it is a good idea to try and lay out a common language for the cases described.
https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-...
I would rather the version numbers be used to inform users about the nature of the changes (patches, new features, backwards-incompatible interface changes) rather than simply when the change was published. I very rarely care about the publishing date.
I think it makes sense in a few cases:
* Umbrella-type projects, such as an Operating System, with Ubuntu being a great example.
* Time-dependent projects (where it's more about data), such as tzdata, certificates, tax rates, etc.
* Constantly-changing APIs
I disagree with some of the projects listed, such as Unity and boltons (more on that below).
----
I think the trick to this working well is that at least one of the following must be true:
* You never break backwards compatibility. For example: tzdata, certificates
* There has to be another way to check dependencies. For example: the individual package versions used within Ubuntu
* Release notes (and upgrade notes) need to be really good. For example: include an "upgrade guide" that explicitly calls out breaking changes and how to fix them; summarize the major changes over time; make sure they're digestible by someone who is updating from a few major versions from a couple years ago (without having to read through each incremental guide).
----
Unity is actually a good counter-example to CalVer as it doesn't follow any of these rules. A quick search comes up with breaking changes in at least 2019.2.5, 2019.1.0 and 2018.3.0 [1]. To make things worse, they release frequently -- if I'm updating from say, 2018.2.0, there have been 85 (!) releases since then. The release notes are very detailed and on individual pages so it would be a multi-hour effort to read through to even figure out how complex it'll be to upgrade. This is especially annoying if I'm updating in a hurry to get an important security fix. At least with SemVer I could focus on the major releases.
[1] https://unity3d.com/unity/whats-new/2019.2.5, https://unity3d.com/unity/whats-new/2019.1.0, https://unity3d.com/unity/whats-new/unity-2018.3.0
major.minor.YYYYMMDD
For an API it seems like a no-brainer to use semantic versioning, makes it easier to document feature deprecation, like supporting latest two major releases and so on.
SemVer puts the responsibility on the maintainer to assume how users are using the library.
I think by now we've learned that even though SemVer was a good idea, people are people and they are gonna eventually fail at setting the version correctly, making your assumptions broken
Semantic versioning lets the user decide.
Treating every patch release of Django like a major release would be a major waste of time compared to “assume Django maintainers have a good idea of how things are used, and rely on automated test suite”
That sounds either worse. Software releases should be immutable, so no changing existing versions.
And also, if X.Y is incompatible (because they screwed up the versioning, as in your example), X.Z should also be incompatible (according to semver), otherwise you break semver twice instead of just once...
> Treating every patch release of Django like a major release would be a major waste of time
Yeah, I guess computing time. If you manually testing each dependency update, your doing something wrong. This should be automated to such level as you feel comfortable stuff is working by just running the tests.
With SemVer the library maintainer tells you "here, let me help you". With CalVer the maintainer says "fuck that, I'm out". None changes your responsibility.
Or, as described in the project, calver might be good as a release date for a "umbrella projects" - like Ubuntu, or even Windows 10 builds.
Calver is used when you don't care about anything but the temporal difference between releases, and you can basically toss any expectation of compatibility between versions, other than something temporal ("this version is compatible with previous versions for up to one year"). That's why APIs use it.
Generally speaking, OSS uses Calver when the releaser doesn't need to care about the consumer, compatibility, etc. You'll find Linux system packages using Calver when someone basically cloned a random Git repo, made a one-off build, and decided "this will be a release" (you find this with firmware a lot), or as a way for 3rd parties to fork an official version with patches.
Random assortment of Ubuntu packages with a variant of Calver (sometimes along with Semver): libargon2, gyp, aspell, language-pack-en, libcrystalhd3, ntfs-3g, x11proto-* , python-cliapp, net-tools, rtmpdump, iputils-*, dh-python, amd64-microcode, lsb-release, libstring-escape-perl, wireless-regdb, ubuntu-keyring, tzdata, fonts-vlgothic, usb-modeswitch-data, publicsuffix, autotools-dev, geoip-database, ca-certificates, dns-root-data
As per our documentation (https://coreos.com/releases/): CoreOS Container Linux version numbers are determined by the number of days since the CoreOS epoch, July 1, 2013, at the time the release is built for the Alpha channel.
There were definitely challenges but it provided a rigorous method to ensure monotonically increasing values. It had a useful side effect of getting people out of the habit of "caring" about which version they were running and instead allowed us to focus on simply "being up to date."
Same issue that we have in Apple’s design department: change for the sake of change.
SemVer makes that situation worse, by requiring a bigger major release to break some part of the API. Other failure modes detailed here: https://sedimental.org/designing_a_version.html