a BIT mighty

I like bits, bits are mighty. With bits you can do mighty things!

Hyrum's Law and Semantic Versioning

Published: December 09, 2024


Some time ago I had a classic nerd battle with a colleague of mine (hi Benji!) that lasted over the span of two emails, one comment in a merge request, hours of chats in the corridor and a fist fight in the parking lot. It was about versioning. Our opinions were completely cemented (complete nerds!!) and neither me or him budged a millimetre. My stance was very static; follow semantic versioning as it’s supposed to be done (!!) and everything will be fine while Benji’s stance was more nuanced and acceptance of chaos and claimed Hyrum’s law to be taken into account and just do a +1 on the versions.

Let’s begin with some background.

Semantic Versioning

If you don’t know the term you still know this strategy, at least on the surface. This is a wildly popular and potentially de-facto way of specifying versions. A version is split into a three part number that makes them look like this: 3.14.15. The gist is that the three numbers means different things.

Read more at semver.org

The selling point of semver is that it should be possible for a consumer of a software package to be mindful about when and how upgrades are supposed to happen and what to expect. If it’s a major version upgrade, you could expect something to break and you have to put more time into adopting your software for the new change, otherwise it should be fine.

Additionally, this makes it possible to do static analysis of the versions and automatically upgrade packages in a safe way.

Hyrum’s law

So what’s this other thing?

With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.

See hyrumslaw.com

So, what’s the contract? Well, the contract in semver is that we promise to upgrade the major version when we do a breaking change. But, what if we fix a bug? According to Hyrum’s law, given enough users that bug-fix is a breaking change. Someone relied on the behaviour of the bug and now have to do extra work to change the consuming software, even if the upgrade was supposed to be safe.

So where does that leave us?

Intention

If semver promises safe, automatic and statically analysable upgrades of software dependencies and Hyrum’s law claims that all change might be breaking, we’re in a bit of a contradiction. Well, almost.

What is left is intention. Given that there’s a spec (formal or informal) of the behaviour of the versioned software, fixing a bug is making the software follow the spec. Even if that turns out to be a breaking change for some users the bug was not intentional and the change that is done is intended to be safe if the software was used as it was supposed to be used.

There’s a lot of nuance there but the question comes down to if you think, in terms of promises, that this is enough.

Cultural laxity

I’m very fond of Emacs, for many reasons. One reason is that they “never” do breaking changes. Instead they make a new API call that is improved and marks the old one as deprecated in order to produce warnings for the user. But they never remove the old API call. Packages older than my grandma still works in Emacs, and that’s amazing! In the beginning of libc there were no versions, because there were no breaking changes. Things were added but kept to be backwards compatible.

This type of engineering seems to be almost lost.

Semver doesn’t necessarily encourage breaking changes, but since there’s a way to statically know when it happens they might be considered less harmfull. It gives package maintainers a get-out clause to be used when you don’t know, care about or can’t be bothered to design the software properly. Still, things happen and some APIs might have turned out bad. The key though is to not remove them when a new one comes around.

Conclusion

Versioning is hard. Software design is also hard. In general, I think we as a industry should put effort into making only additional changes and try our hardes to deliberately not break the old ways of doing things. It will probably make your software more complicated but I also think that your users will thank you. Stability is something that unfortunately is an exotic thing when it comes to software.

 

Move fast and break things Move slower so that you don’t break things

 

 

Update 2024-12-10

If you’d fancy a laugh, you can continue reading about binver.


Thanks for reading!

If you want to read more please visit the archive for more posts.