It’s time for our annual Semantic Versioning argument/gripefest! This time it was kicked off by Jeremy Ashkenas’s post why he believes Semantic Versioning is wishful thinking. Olivier Lacan chipped in further thoughts on the importance of a changelog.
Yes, Semantic Versioning is wishful thinking. Change cannot be compressed into three version numbers to guarantee safe upgrades. Developers get things wrong and forget changes such that versioning often isn’t correct, even if they wanted to follow SemVer exactly1. I thought I would write down my own versioning policies as another example for people to consider.
It’s all about Change
If you aren’t keeping a well-curated project changelog, users will hate you. This is non-negotiable 2.
Any non-trivial change should have a note in the changelog explaining it. I mentally categorize these changes into three buckets:
- Major – API contracts change and user code will break! Major changes should planned out carefully and upgrade notes documented well3. I try to accumulate many breaking changes over the course of a year; major bumps must be a rare occurrence because they require active participation from your users. Make this as painless as possible or you quickly lose your user’s trust.
- Minor – cool new features are rolled out or existing features are refactored enough that code relying on implementation details could break. For instance, if I change how Sidekiq loads Rails code, I automatically consider that a minor bump because auto-loading and eager-loading is a hairy beast. Stuff probably won’t break but just in case…
- Patch – bug fixes, minor new APIs. Miscellaneous improvements, unlikely you’ll need to know about these changes but they are still documented.
My versioning policy encapsulates those buckets and the changes within a given release. Depending on your own bravery, you can lock to a precise version number or allow patch or minor upgrades. This versioning combined with a reliable, curated changelog allows the user to make their own decisions about upgrading versions and easily investigate any breakage or unexpected behavior after an upgrade.
- One example of my own versioning screw-up: Sidekiq 3.2.2 no longer worked on Ruby 1.9. Even though Ruby 1.9 hasn't been supported in Sidekiq 3 for months, several users were using it and complained. This change should have been rolled out as a 3.3.0 minor bump, not a patch release. ↩
- Here's Sidekiq's changelog. ↩
- Here's Sidekiq 3.0's Upgrade Notes. ↩