A “Systems” Addendum To Semantic Versioning

tl;dr: When using semantic versioning, consider not only changes to the public API, but also changes to system requirements.


Semantic Versioning concentrates on the public API signature as the determiner of when to change version numbers. If the public API changes in a backwards-incompatible way, then you have bump the major version number. When I upgrade a dependency to a minor or patch version, I am hypothetically assured that the upgrade will be successfully completed, and that I will not have to change anything about my existing system or codebase.

However, I have come to think that while SemVer’s concentration on the public API is a necessary indicator of the upgradability without other changes, it is not a sufficient indicator. Here’s a real-world upgrade scenario:

  1. Package 1.0.0 is released, dependent on features available in Language 4.0.0.

  2. Package 1.1.0 is released, with a public API identical to 1.0.0, but is now dependent on new features available only in Language 4.1.0.

SemVer is honored here by both the Package and the Langauge. Neither has introduced backwards-incompatible public API changes: the Package API is unchanged, and the Language API adds new backwards-compatible features.

But now the Package internals depend on the new features of the Language. As such, it is not possible for the Package 1.0.0 consumers to upgrade to Package 1.1.0 without also upgrading to Language 4.1.0. If they try to upgrade, the system will break, even though SemVer indicates it should be safe to upgrade.

It looks like there is more to backwards compatibility than just the public API.

II.

Some will argue that when the package requirements are properly specified in a package manifest, the package manager prevent a break from occurring in the above scenario. The package manager, reading the manifest, will note that Language 4.1.0 is not installed, and refuse to upgrade Package from 1.0.0 to 1.1.0.

However, this is beside the point that I am trying to make. Yes, the package manager prevents breaking installations based on a manifest. But that prevention does not mean that the changes introduced in Package 1.1.0 are backwards-compatible with a system running 1.0.0. The 1.1.0 changes require a system modification because of a requirements incompatibility.

So it is true that the package manager provides a defense against breaks, but is also true that the version number of the package does not indicate there is a backwards incompatibility with the existing system. It is the indication of incompatibility (among other things) that makes SemVer valuable.

III.

I opine that requiring a change in the public environment into which a package is installed is just as major an incompatibility as introducing a breaking change to the public API of the package. To cover that case, I offer the following as a draft addendum to the SemVer spec:

  • If the package consumer has to change a publicly-available system resource to upgrade a package, then the package upgrade is not backwards-compatible with the existing system, and the package SHOULD receive a major version bump.

Using “SHOULD” makes this rule somewhat less strict than the MUST of a major version bump when changing the package API. It’s possible that Language 4.0.0 is no longer supported or installed on any of the target systems, in which case it might be reasonable that a Package minor version could require a change to the Language version. But you do need to have a good technical or practical reason (not a marketing reason 😉 to avoid the major version bump when changing the public system requirements for the package.

(You may also wish to review Romantic Versioning for an additional take on Semantic Versioning.)

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.
Share This!Share on Google+Share on FacebookTweet about this on TwitterShare on RedditShare on LinkedIn

8 thoughts on “A “Systems” Addendum To Semantic Versioning

  1. I think your complaint is somewhat over-stated, and thus your suggested modification is too strict. If one trusts the accurate Semantic Versioning of the dependence (in this case, Language 4.0.0 to 4.1.0), then requiring an upgrade to a compatible version of a dependency is not a breaking change, in that it can be safely applied automatically.

    Increases in dependence version should result in increases in the corresponding version component in the dependent package – requiring a newer bug-fix release would be acceptable in a bug-fix of the dependent, a newer minor version requirement would indicate a newer minor version, and a newer major version would increase that accordingly.

    • Hey Marco — the linked article states:

      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.

      I address that point in my post above: “So it is true that the package manager provides a defense against breaks, but is also true that the version number of the package does not indicate there is a backwards incompatibility with the existing system. It is the indication of incompatibility (among other things) that makes SemVer valuable.”

      You also say:

      If that wasn’t true, every dependency bump would lead to a cascade bump of all major versions in dependants.

      Maybe, but that’s also beside the point that I am trying to make.

  2. Given the way SemVer is currently written, I do think it’s perfectly valid to bump your dependency requirements (language or otherwise) without releasing a new major version.

    You’re absolutely right that SemVer doesn’t currently cover this type of BC break. So I guess the question comes down to whether it should, Ă  la your proposed addendum, or whether we should rely on package managers to manage dependency compatibility for us. I think the latter is perfectly fine.

    Don’t get me wrong, I’m not against bumping a major version to indicate other BC breaks (SemVer fully supports this) but it’s also not a requirement. It’s simply one option maintainers can use to help convey the BC break to their consumers.

  3. ” … But that prevention does not mean that the changes introduced in Package 1.0.0 are backwards-compatible with 1.1.0. …”

    Wouldnt that be `forward compatible`? 1.1.0 would be backwards compatible with 1.0.0; where 1.0.0 would (possibly) forward compat. w/ 1.1.0 ?

Leave a Reply

Your email address will not be published. Required fields are marked *