(If you have an hour to watch a video, Rich Hickey’s Spec-ulation talk is a must-watch for any software developer, and, basically, covers everything I’m about to say but better.)
Why Does Versioning Exist?
Versioning exists because, fundamentally, we want to make our software better over time. Nobody’s perfect, and sometimes bugs or regrettable API decisions make it out in a release, and we want to be able to fix those problems. But from the point of view of your library consumers, changes are bad. Changes represent risk and effort. So you, the library author, should endeavor to keep the API that you expose consistent.
The Golden Rule
Semver has a lot of rules, but the core is very simple:
- Versions take the format, MAJOR.MINOR.PATCH.
- PATCH versions are for bug fixes that do not change your public API.
- MINOR versions are for changes that add functionality, without otherwise changing your public API.
- MAJOR versions are for changes that change your public API.
Seems easy enough, but note that the above prohibits breaking changes on anything except major versions. But what is a breaking change really?
What Is a Breaking Change?
There are two major schools of thought here.
The first school is that a breaking change is any change that doesn’t alter the intended functioning of the library.
npm install --save and
yarn add both add dependencies using the
^x.y.zsyntax by default, which generally results in minor and patch versions being automatically upgraded. If libraries are constantly breaking on minor or patch releases, this quickly ends up being very unpleasant.
What to Do as a Library Author?
There’s no one solution to this problem, but here are some suggestions from me, a library maintainer and potentially your user.
1. Embrace More Major Versions
One of the reasons that people avoid major releases is that it seems to imply major revisions. But this may lead to minor releases with breaking changes, which, as we know, leads to madness. Instead, consider releasing major versions more frequently.
Lots of software groups release major versions routinely. What version is your browser at right now? Or, consider React 15 and 16 (leaving behind their up-to-0.14 beta period), which have been broadly non-breaking. This is the right way to do it.
Another way to look at major releases: If you want to overhaul your library’s public API, you may as well give it a different name, because it’s in effect a different library (as an example, remember Angular and Angular 2?). Don’t be Angular; use the Major version to advertise improvements to your API.
2. Add Instead of Changing
There are good reasons not to make a new major release for every bug fix, but luckily there are other ways not to break your library too.
Say you find a function that really isn’t working the way you intended. How do you resolve this oversight without creating a new major release? Simple! You add the intended functionality under a new name and do a minor release. Add a note in your docs to use the new function instead so that new users know about the change, and everyone is happy!
3. Use Suffix Versioning for Pre-Release Software
Do me a favor and skip the 0.y.z version. If you’re publishing “pre-release” versions of your software, and you expect it to break all the time, prefer “1.0.0-beta17” to “0.1.17,” for the sake of all of us who would rather not police our
^carats. Or, even better, call your package something like “mylibrary-beta” and then proceed with regular semver until it’s time to release a stable version!
I guess my point is, please start using semver properly and completely.
4. Be Strict About Your Own Dependencies
If you’re not writing stuff like
left-pad, your library probably has dependencies of its own. If those dependencies are using
Tips for Library Users
Unless this post has a lot more impact than I expect, chances are you’re still going to get burned by questionable version hygiene. Here are a few tips to help with that.
1.1.xsyntax in your
- Use yarn: Yarn will automatically lock down version numbers until you explicitly upgrade those dependencies, which should help you avoid issues until you explicitly upgrade.
Other advice is welcome in the comments if you have it!