by Leon Rosenshein

Semantics

Debugging customer problems can be a challenge, especially over zoom or email where you can't see the exact input/output. To make it easier I have a set of questions I usually ask at the beginning. One of them is "What version are you running?" That's really important info since there can be many versions out in the field.

For the infra CLI it's pretty easy to get the version. Just run infra version and it will tell you. This is really important in *NIX based systems, because unlike Windows DLLs/executables, posix ELF files don't have a standard way to store/retrieve the version info of a file. Instead, for shared objects you use file name and a system of symlinks with prescribed names to manage version. Using that is a topic for another time.

The topic for today though is what to put in the version. The simplest is just a continuously incrementing number. Every time your build process produces a public version the version number gets incremented by one. This covers the most basic requirements of versioning. It ensures that all public versions can be uniquely identified and you can tell which of two versions is newer. That's a good start. But it leaves you with a problem. You can tell that one version is older than the other, but you can't tell how much older, and you don't know from the version number if it was yesterday to 10 years ago.

Another versioning scheme is to use the build date/time as the version. Something like YYYY.MM.DD.hh.mm.ss.<buildnumber>. Year/Month/Day/Hour/Minute/Second. That's almost certainly unique, but if you have a parallel build system that can start multiple builds at the same time then you can add the build number for disambiguation. It's important to use that order because that ensures that you can sort by version. The date scheme gives you the ordering of a simple number, and lets you know when the releases were done. That's a lot more helpful, and users really like it because it's obvious to them if something is old

As a developer though, that doesn't tell me something I really want to know. Should I expect that version to have what I'm looking for? And that's where semantic versions (SemVer) come into play. Semantic versions are of the form <major>.<minor>.<patch>. The theory is that all versions for a given <major> version are backward compatible, and increasing <minor> versions only add functionality, Removing functionality would be a breaking change and require a new major version. For a given <major>.<minor> everything is the same, and new versions fix emergent bugs/issues that are discovered after release. Pretty simple. SemVer trades the absolute time information for functionality/compatibility info. In my experience that's a trade worth making.

As with any system, you'll find that sometimes you need to extend it. You might have a on-off release, a shared fork, or simply need to test a version locally, but still be able to keep it distinct from all of your current and future released versions. A common way to do that is with an extension. That's where user name and date could be very helpful. Let's say I want to give you a test version I built based on the code in version `0.17.1`. In that case I might give it version `0.17.1-leonr-test_myfunc`. That way everyone who sees it would know the base version, who built it, and why.

And of course, you'll want this tied in to your version control system so that it's easy to get the code that went into a specified version and your build system, so you don't have to worry about getting it wrong.