Please see the disclaimer.

Assumed Audience: Hackers and anyone interested in Yzena’s software.

Epistemic Status: Confident because it’s my choice anyway.

Introduction

Yzena is my business. It’s a software business, obviously.

In July 2022, I wrote about how Yzena will version software.

I have made a few tweaks since then, so I am writing an update.

I do repeat information in this post so that it stands alone and remains a reference document for Yzena versioning.

Versioning Systems

Anyway, what versioning system should Yzena use?

SemVer (Semantic Versioning) is okay, but not great. It is standard, though.

But there are other ways.

EffVer

One is EffVer.

I like one thing about EffVer: it encourages updating the version number when the impact is bigger than intended.

But beyond that…it isn’t much. Judging “impact” is still a human process, and like everything human, it will always have problems.

I wish there was some way to alleviate this, and kudos to EffVer for trying, but I don’t think EffVer will work for Yzena.

CalVer

Another scheme CalVer (Calendar Versioning). 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 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 four components of the version. And one of them is eight characters!

😲

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 Component

Finally, the last component is the release date in year, month, day, with separating hyphens.

The hyphens are important; in the last version of Yzena’s version system, the release date was three components, and this is too much.

But separate the components with hyphens, and they become one component, even if it’s…special.

There is one further 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 Four?

So…what it sounds like is that there are really three components: edition, increment, and release date. Why do I still separate the edition with a period?

Well, I do it because Ubuntu does it, and personally, I think it looks better than a four- or six-digit number.

As for separating the release date with hyphens, 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 four 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 is an alias URL that only use the first three components. And maybe an alias tag.

So despite the long version scheme, I will ensure that your packaging works with just three components.

In fact, this is the real reason that the edition is two components!

So please put down your pitchforks!

Oh, and for users, I’ll do the same for links to things like documentation.

Interfaces

And there are still people screeching! Let’s see, who did I forget…

Ah! The SemVer and EffVer people! You want versions to be a contract, right?

I disagree.

Hey, what’s with the torches?! I’m not done yet!

You see, I have used SemVer for another project, but judging impact turned out to not matter.

Why? The project is two programs and a library. Everyone uses the programs, and no one uses the library.

I need SemVer for the library, but not the programs.

Eek…

There was one time I made a breaking change in the library and didn’t bump the major version. It was a calculated risk.

And you know what? It paid off.

Why? Because no one uses the library!

I wish I hadn’t used SemVer for that project; it has proven useless.

Put down the tar and feathers!

Because I understand that you want some contract, and I have one for you: I will version interfaces, not implementations.

My monorepo will have multiple versions. Each one will be tied to a specific API or module.

Multiple API versions will be supported for everything, and you will be able to select the API versions at build time.

In addition, any deprecated API that is removed will turn into a hard build error.

You can use this to upgrade your use of my code at your convenience with the guarantee that your code will only break if you act molasses and don’t get off your derrieres.

And also that it will break, loudly.

Oh, and I’ll update the edition whenever an interface is removed, so it will be obvious when work needs to be done. And I’ll carefully document the changes.

See, I’m not cruel!

Conclusion

So that’s the scheme, and that’s why. I hope it works for you all, whether users, packagers, or code archeologists.