Assumed Audience: Hackers and anyone interested in Yzena’s software.
Epistemic Status: Confident because it’s my choice anyway.
This post has been superseded by this one.
Introduction
Yzena is my business. It’s a software business, obviously.
I have long wondered what versioning system I should use for that software.
SemVer (Semantic Versioning) is okay, but not great. It is standard, though.
But there are other ways.
There’s CalVer (Calendar Versioning), for example. This one is both new and familiar to me.
It’s new because I hadn’t heard of it until recently. It’s familiar because it’s what Ubuntu uses, and Ubuntu was my first Linux distro.
CalVer
Anyway, CalVer is interesting because it says nothing about how to version software except to include a date somewhere.
This gives me a lot of flexibility.
In addition, CalVer has two questions to ask:
- Does your project feature a large or constantly-changing scope?
- Is your project time-sensitive in any way? Do other external changes drive new project releases?
The answer to the first is yes since it’s a monorepo.
The answer to the second will be yes, even if it’s not obvious. One of the examples they gave is:
Business requirements, such as Ubuntu’s focus on support schedules.
Since this is for a software business, I sincerely hope that Yzena software has to care about support schedules.
So CalVer makes sense for Yzena software.
So I just need to choose a scheme and be done, right?
Not so fast.
Editions
One of the CalVer examples they gave was of Teradata. Teradata has an interesting scheme that I think the CalVer website describes well:
Teradata’s usage is notable not for the prominence of the technology or company, but because there have been multiple releases in 2016 which were versioned as 15.10. This may seem breaking at first, but the meaning and utility is clear.
The library maintainers have crafted a resourceful hybrid of semantic versioning and calendar versioning. The YY.MM part of the version are used as a combined SemVer major version. That is, for new releases, the API of the library remains the same as it did in October 2015. Dependent code written since then is safe to upgrade. We will see the year and month segments update next time there is a breaking API change.
I like this, for several reasons.
One, it’s kind of like Ubuntu’s version scheme, and since I care about support schedules, this seems nice to me.
Two, it’s also kind of like Rust’s edition scheme. I have a programming language myself, and Rust’s edition scheme seems to be the best for that.
Three, I can make the rest of the version anything I want.
But there is another thing I want from the version: knowing the date a version was released.
Why? Well, because it makes sense.
For example, SQLite, a project that I want to emulate, always adds the date of a version after the version. This is a good idea because the user can see how old the version is.
However, adding it in the documentation means that it is still not part of the version. If it’s part of the version, there’s no need to add it.
So I’d like to put the date of release in the version.
However, there is yet one more thing I want a version to have: a marker of how many versions there have been in an “edition.”
Scheme
So, without further ado, here is Yzena’s versioning scheme:
E0Y.E0M.0INC.0Y.0M.0D
where E0Y
is the zero-padded year for the edition, E0M
is the zero-padded
month for the edition, and 0INC
is the zero-padded, increment version number.
Yes, there are six, SIX, components of the version.
😲
Yeah, I know it’s a lot, but there’s a lot of information there.
So let’s go over it all.
Edition Components
First, there needs to be two parts for the edition because, unlike Rust, I want the month.
Why? To have finer granularity. And because I expect to release new editions more than once a year.
Version Increment Component
The third component is the number of releases in the edition, starting from 0.
This means it always increments or drops to 0. It has to change on every release.
It also tells the user something important: how many times has this edition had a release?
Yes, this is important. Say I release a 23.07
edition, and it is still the
active edition 10 years later. If the increment component is 01
, then people
might rightly question whether the project is alive, but if it is 57
, then
people will probably understand that the project is alive. And not only that
it’s alive, but that it’s stable.
That component is important because it will show how well-off the project is when combined with the edition.
Release Date Components
Finally, the last three components are the release date in year, month, day.
There is one tweak: the year will always be two digits, unlike the real 0Y
in
CalVer (which will go to three digits for years at or above 2100), because I
don’t expect an edition, much less an increment version, to last 100 years.
Why Six?
So…what it sounds like is that there are really three components: edition, increment, and release date. Why do I still separate the “subcomponents” with periods?
When it comes to the edition, I do it because Ubuntu does it, but I could be convinced to not do that.
As for the release date, well, an 8-digit number is just too much.
Small Version
At this point, there are people among my readers who are yelling at their screen. They are the people who package software, whether for a Linux distro or some other reason.
They are yelling at me because a lot of them work with software that works with version numbers, and their software probably has to make a few soft assumptions about what kind of versions exist. I’m pretty sure one of those assumptions is that there are not six components of a version number.
Because who in their right mind would have that many?!
Packagers, I hear you.
I know I already spent many words justifying the version increment, but the truth is that there was a second reason it always increments or resets: so that the first three components are sufficient to distinguish the version.
And I will go further: Even though the version control tag will have all components, I will make sure there are alias URL’s to all downloads that only use the first three components.
So despite the long version scheme, I will ensure that your packaging works with just three components.
So please put down your pitchforks!
Oh, and for users, I’ll do the same for URL’s to things like documentation.
Conclusion
So that’s the scheme, and that’s why. I hope it works for you all, whether users, packagers, or code archeologists.