I’ll admit it. Like almost everybody in the Node community, I’m in the habit of abusing npm’s save feature:
npm install --save lodash
The problem is, it uses a neat little caret `^` to indicate that your software should automatically use non-breaking changes.
But this could be dangerous. We all know that John-David Dalton is an unstoppable robot from the future. Check the selfie:
What? You didn’t know? His name is John. Coincidence? I think not.
What if he’s on a secret mission to stop Skynet by slipping a time bomb into all of our code? One of these days, he’ll make a breaking change to lodash, and the next time you `npm install`, BOOM!
Your code will break. Because he won’t increment the major version number… (sneaky robot).
Of course, if you really want to protect yourself, delete all the `^` symbols from `package.json` and add `save-exact=true` to your `~/.npmrc`. Then convince your entire team to do the same (paste this in Slack):
echo "save-exact=true" >> ~/.npmrc
But realistically, only 10 people are actually going to do it. The beautiful Skynet we’re all trying to build is doomed.
It’s Your Fault
Lodash is not the biggest threat to our future artificial humanity, though. You are. Every time you celebrate a new 1.0 launch or your amazing, totally overhauled 2.0, you’re adding to the problem.
But you’re hardly a lone super villain. Everywhere I look, there are projects tossing SemVer to the wind and thinking of major versions as marketing launches instead of what they really are: An indication for software that there is a breaking change coming down the pipe.
There is one tiny, minuscule chance that our future robot overlords will survive this impending disaster: We need to separate version names from version numbers and pay more than lip-service to SemVer.
Instead of Major.Minor.Patch, think Breaking.Feature.Fix.
FORGET the old. It never existed. There is only Breaking.Feature.Fix.
Start at 1.0.0
But if this is going to work, we need to start our modules at 1.0.0. Semver lets you start modules at 0.x.x, and break whenever you want without incrementing the major version number. That can be problematic though, because then you can’t easily tell whether or not a change breaks the existing API. Start at 1.0.0, and that problem goes away.
Version numbers are only there to communicate the nature of a change: Breaking.Feature.Fix.
To communicate, “Hey everybody, we have a new release! Here are the new features!” use release names instead of version numbers.
Releases and versions should be separate concepts because the need to communicate news of new releases and important updates (i.e. marketing), and the need to inform systems like npm about the nature of changes (breaking, new features, or fixes/security patches) are two separate concerns which advance on separate timetables.
The conflating of version numbers and public releases has led to a big problem in the software development community. Developers tend to break semantic version numbering, for example, resisting the need to advance the breaking (major) version number because they’re not yet ready to release their next major version to humans.
In other words, we need two separate ways of tracking changes:
- One for people & public announcements (names).
- One for software & resolving version conflict problems (numbers).
Release Names (AKA code names)
My major releases have code-names instead of version numbers. The current release is identified by the “latest” tag. The first version is always “mvp”. After that we pick a theme, and work through the alphabet from A to Z.
When talking about release versions, we don’t say “version Arty” we say “the newest version was released today, code named ‘Arty’”. After that, we just refer to it as “Arty” or “latest version”. More recognizable codename examples include “Windows Vista” or “OS X Yosemite”.
MVP stands for “Minimum Valuable Product” (a better version of the common “Minimum Viable Product”). The minimum number of features to make the product valuable to users.
Version numbers are essentially SemVer, except that I use semantic names, for the version roles, e.g. “Breaking.Feature.Fix” instead of “Major.Minor.Patch”.
We don’t decide what the version will be. The API changes decide. Version numbers are for computers, not people. Release names are for people.
Any breaking change, no matter how small increments the Breaking version number. Incrementing the Breaking version number has absolutely no relationship with issuing a release.
When any new feature is added. This could be as small as a new public property, or as large as a new module contract being exposed.
When a documented feature does not behave as documented (and little or no software relies on the broken behavior), or when a security issue is discovered and fixed without altering documented behavior.
If lots of software relies on broken documented behavior, it’s a breaking change. Increment Breaking accordingly.
If it’s time to write a blog post to inform the community about new features or important changes, find the version you want to publicize, tag it “latest”, and give it a human-readable name (e.g., “MVP”, “Aardvark”, etc…).
That human readable release name does not replace SemVer. “MVP” might correspond to v1.6.23 or v2.2.5 — the point is, the numbered version has nothing to do with the named release.
The numbered version is there so npm and developers can tell whether or not a new version is a breaking change, an added feature, or a bug / security fix.
Now start dreaming up cool codenames for your next public release.
- Online courses + regular webcasts
- Software testing
He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.