Avatar (Fabio Alessandro Locati|Fale)'s blog

On software versioning schema

July 31, 2024

Last month, the Ansible Forum had a discussion about potential changes that might be implemented in AWX. One aspect that immediately hit me was the decision to move from SemVer to CalVer. More specifically, what struck me was the focus on this change in the initial post and in the comments. Since it took me a while to formulate a whole reasoning behind my perspective, I created this blog post to explain my thought process better.

SemVer and CalVer

Firstly, let’s define the two systems:

SemVer

The SemVer system is very well documented, but it boils down to a simple concept: structure the release version following the schema MAJOR.MINOR.PATCH, where the three numbers are incremented based on what is the most significant change of a release:

These are general guidances on SemVer, but every project interprets it slightly differently. For instance, some projects only use two numbers, like MAJOR.PATCH, which intentionally ignores the difference between minor new functionality and API changes.

CalVer

Unlike SemVer, CalVer is less documented, but the general idea is to use the release date to calculate the release number. Some examples of commonly used formats are:

As you can notice, CalVer releases often use dots, but this only happens because many tools assume that a release number has numbers and dots, so they might fail if they don’t find any dots. However, from a CalVer standpoint, dots might be missed or replaced with any other character.

Tradeoffs

The big tradeoff between SemVer and CalVer is that SemVer release numbers can be very helpful if compared to a different version to guess the nature of changes that occurred in between, but it makes it hard to position those releases on a timeline. On the other hand, CalVer immediately suggests when a specific version was released, but it will require more effort to understand the differences between the two releases by simply looking at the release numbers.

An important behavior allowed by SemVer but not CalVer is maintaining multiple incompatible versions simultaneously. It is as simple as creating a new major (e.g., 2.0.0) and releasing both the old major and the new one by bumping minors and patch values as needed.

No matter which of the two systems you choose to implement, you should always provide a ChangeLog file with all your releases that will specify, for every release, the release version, the release date, and the changes from the previous release, preferably divided based on the impact to the user.

Convenience by project kind

Different reasons can drive the choice between SemVer and CalVer, but a common framework for deciding which to prefer is by assessing the kind of project analyzed.

Library

If the project is a library, this means that the users will be technical people and that (usually) they will care more about the upgrade paths than when the library was released.

Furthermore, when developing a library, it often makes sense to develop multiple major (i.e., non-compatible) versions simultaneously so that it is possible to support slow-moving users and make fast-moving users happy simultaneously.

For those reasons, using SemVer in libraries usually makes sense.

Desktop application

Desktop applications don’t usually need multiple major versions developed simultaneously, and the typical user cares more about having the latest version than the history of the releases. Due to those, SemVer could be a better fit. Usually, it makes sense to use a simplified flavor of SemVer, such as MAJOR.MINOR, since minor releases and patch releases will have no real difference for those users.

However, it is essential to notice that there are some applications where those assumptions do not apply. In those cases, the conclusions will also not apply.

Mobile application

Mobile applications tend to be automatically updated by the SmartPhone without the user’s awareness. For this reason, there is no real difference in value between SemVer and CalVer.

Webservice

Webservices (i.e., API) should either use deprecations to introduce non-backword-compatible changes or provide multiple versions simultaneously. If the latter method is used, the MAJOR version would be visible directly in the URL. In these cases, SemVer is often better since it can simplify the use from the webservice developer perspective, but it is often not even visible from the user standpoint.

Websites

Websites tend to use SemVer for similar reasons to those of Webservices.

Convenience by user

We have touched very lightly on this aspect so far, but in my opinion, it is the most important: the user relationship with the analyzed software.

Casual user

If the user is a casual user of the application, an easy-to-read version schema can help to quickly understand a lot of superficial information about the new release. Examples of this would be B2C applications or specific libraries that most users spend little time integrating into their projects.

Focused user

A Completely different situation is where the user spends most of their time managing the software itself. In this case, the user will (hopefully!) always read through all release notes and changes before applying the change, reducing the relevance of the small bit of information that can be carried in the release number.

In those cases, any system would work, and it becomes a matter of simple preference.

Machines

There are cases where the version number is parsed automatically by code, such as a dependency resolver that will parse the various releases of a library to decide which one to use. In this case, using SemVer will yield much better results than CalVer.

Conclusions

There are multiple well-known version schema, each with advantages and disadvantages. For this reason, in various situations, one schema can be better suited than alternative ones. For this reason, it is impossible to suggest to always use one method or the other, but I hope I’ve helped to better make the decision by showing some ways I think about the project.