Semantic Versioning
When new software comes out it has a version number like 8.2.0. If you’re confused about what that means you’re not alone. The software industry needed a standard way to describe software releases so we as consumers of the software could determine how big of a change it was and determine if we should upgrade. Semantic Versioning, or SemVer for short, creates that standard.
In this article, we’ll discuss how SemVer strings are composed, how you can read them to understand what’s changing quickly, what entries in our composer.json mean, and how you can create your own SemVer for published libraries (like composer libraries).
The Problem
One of the difficult challenges with software development is managing dependencies. It can be such a pain point we’ve even named it “dependency hell”. In the days before Composer, we didn’t know what version of different libraries might be installed on the server our software was being installed on. If we had multiple applications running on the same server we would run into conflicts all the time or we would develop our code using one version of a package only to have the server use a lower version without features we relied on. Thankfully Composer stepped in and create a solution to determine if a package would work with our software and localize it to just our application.
We always want to make sure we’re using the most up-to-date version of the libraries our application relies on. This makes sure we have the newest features and the latest patches for bugs. Composer uses SemVer to determine exactly what version of each package we can use without us manually having to figure it out.
Anatomy of a SemVer String
A SemVer release string is broken into three numbers working left to right:
- The major release
- The minor release
- The patch level
Major versions are defined as a version where the package has made API changes that are incompatible with the previous major versions. For example, the 8.0 release of PHP removed several functions that caused some applications to stop working and made the upgrade from 7.4 to 8.0 a little more difficult.
Minor versions are defined as versions where the libraries have had functionality added but in a backward-compatible manner. For example, the 8.1 release of PHP added enums. This was done in a way that still allowed software developed on the 8.0 release to run on the 8.1 runtime without a problem.
The patch-level releases are just that. These are versions of the software that fix a bug or a set of bugs but don’t make any core changes to the logic.
There can also be an additional label at the end of the SemVer version to indicate if it’s a pre-release or beta. In those cases, we would use RC or beta respectively. For example, the PHP core language goes through several beta and pre-release versions before it’s finally made into the final release. This is done so bugs can be ironed out. At the time of this writing, there is a PHP 8.2.0RC2 to indicate its release candidate 2 of the 8.2.0 version. When 8.2.0 is ready for widespread use the version will be changed to 8.2.0.
When we compare SemVer numbers it’s important to work our way left to right and treat each number as a number and not a string. For example version 0.3.10 is ordered before 0.10.3 because the major number is the same but minor 10 is greater than 3 and version 0.1.1 is ordered before 1.0.0 because 1 is greater than 0 in the major version and all others are unimportant.
Using SemVer String
Now there are two ways that we can use SemVer. As a consumer of the libraries that use it or as a maintainer of one of these libraries.
Composer
As PHP developers we use SemVer string mostly through Composer. Composer keeps a composer.json file that contains a listing of libraries we need and it uses SemVer to manage those dependencies for us.
If we look into a composer.json file for a Laravel project we’ll see lots of libraries listed. For example, we’ll see `”laravel/framework”: “^9.19”,`. The “^9.19” is telling Composer what versions it can safely use. The carat (^) at the start is will keep us “locked” into the 9 major release branches so we don’t accidentally upgrade to a new major release and break our application. We can also use the tilde (~) character to lock us into the current minor release.
Another option is the asterisk (“*”) character for any version. This is helpful for command line tools not tightly coupled to our software like PHP_CodeSniffer. PHP_CodeSniffer doesn’t directly interact with our code so upgrading between major versions should be simple.
We might also see ranges or >, <, or = signs. It’s not common but it’s possible.
If you take only one thing away from this video it should be this. We should all be using the caret inside of our composer.json. Then we must run `composer update` at least once a month to make sure we’re at the most current version of our libraries (with a degree of testing as well).
Now the amazing thing about Composer and all of the modern package managers is that it allows our dependencies to have dependencies which in turn might have more dependencies. It’s really dependencies all the way down. Each one uses SemVer but two libraries might support a different major version of the same library. Maybe both use the faker library but one only supports version 1 and the other supports versions 1 and 2. The composer will determine the best option for us.
Hopefully, it’s the newest version but we could be locked to a previous major release until all the libraries upgrade.
Library Maintainer
Now as a library maintainer here are your rules to live by.
- Breaking changes only in major versions
- New features in minor versions as long as they don’t break backward compatibility
- Bug fixes in patch releases
I like PHP’s approach where they deprecate the functionality in minor releases so they can remove it in major releases. Something for you to try as well.
Now if you accidentally release a backward incompatible change as a minor version it’s not the end of the world. Just fix the problem and release a new minor version that restores backward compatibility.
What You Need to Know
- Semantic Versioning is a method to label releases
- Broken down into major, minor, and patch
- Use the caret notation in your composer.json files and run update regularly
Leave a comment
Use the form below to leave a comment: