Semantic Versioning when you change the required programming language version

The question

Here at White October, we maintain a number of Open Source projects.  We’ve recently been discussing changing the minimum PHP version supported by some of them.  The question naturally arose as to how we change the version number when we do that.

We follow Semantic Versioning, which says:

Given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.

On first look, it would seem that we should bump the major version when changing required PHP – the package used to work on e.g. PHP 5.6, now it doesn’t, so that’s a breaking API change, right?

The complication

However, it’s not quite that clear-cut when you remember that we declare the supported PHP versions in our composer.json file.  For example:

"require": {
    "php": ">=7.1.0",
    "symfony/framework-bundle": "~2.0|~3.0|^4.0",
    "symfony/templating": "^3.4|^4.0"
}

For this example, Composer would not consider this version of the package as a possible candidate if it’s being installed into an environment with a PHP version less than 7.1.  The point of semantic versioning is to know that an upgrade is compatible, and Composer already takes care of that here by not matching this version of the package, irrespective of what its release number is.

The process others follow

Thinking about Composer got us wondering whether we did need to change the major version number, so we took a look at what some other packages are doing and discovered a couple of discussions around Zend Framework and Doctrine.

Both of these bump the minor version number when changing PHP version support.  Here’s a good quote from Doctrine (linked above) as to why:

Why dropping PHP support in a minor version is not a BC break

One question we frequently hear is, “isn’t dropping support for a PHP version a BC break”? In a nutshell, no. A BC break happens when there is an incompatible change that your package manager can’t handle. For example, changing a method signature in a minor version is a no-go, since the composer version constraints mentioned above assume any minor upgrade can safely be used.

However, when we drop support for an older version of PHP, composer will not consider the new version if the PHP version requirement is no longer fulfilled. Thus, you won’t end up with a fatal error due to a wrong method signature, you just won’t get the new version.

The right number

Our investigations so far left us confident that we didn’t need to bump the major version number, but which version number should we change instead?  The minor version or the patch version?

Zend and Doctrine both change the minor version number.  E.g. they’d go from 1.2.3 to 1.3.0. We decided to do the same and came to realise that actually this is really important.

First off, it’s standards-compliant.  Semantic Versioning says:

[The minor version] MAY be incremented if substantial new functionality or improvements are introduced within the private code

Changing PHP seems like a substantial but private change (the API is the same).

Most importantly, however, consider what happens if you instead change the patch version, e.g. supporting PHP >= 5.6 in version 1.2.3 and PHP >= 7.1.0 in version 1.2.4.

The problem is that changing only the patch number means that you can never again release any changes to the version of your project which supports the old PHP versions!

To see why, ask yourself what you’d change the version number to if you wanted to release a security fix on your PHP >= 5.6 codestream in the example above.  That’s version 1.2.3, so you would go to 1.2.4, but that’s already in use for your PHP >= 7.1 codestream! Of course, you could then go ahead and change the minor versions of both, moving to 1.3.0 and 1.4.0, but that’s confusing and overly complicated.

Instead, you should just do it right in the first place and bump the minor version number for a PHP version change.  That way you can still add patch changes (like security fixes) to the old minor version by increasing its patch version.

Conclusion

When you change the version of PHP supported by a project using Semantic Versioning, increment your minor version number.

This allows people to use it without worrying about backwards-incompatible changes.  It also gives you the flexibility to add fixes to the version of your project which supports the older PHP versions, should you need to.

This principle will also apply to other languages, assuming that the dependency management system used offers a way to specify the required language version.

Post a Comment

Your email address is never published nor shared. Required fields are marked *

Ready to talk?

Whether you want to create a new digital product or make an existing one even better, we'd love to talk it through.

Get in touch