mirror of
https://github.com/semver/semver.git
synced 2026-03-22 14:10:15 -05:00
Problems with the Magic Zero #150
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @isaacs on GitHub (Sep 4, 2014).
The "anything may change at any time" nature of a leading zero major version is somewhat disruptive for authors who may feel intimidated at the perceived commitment involved in a
1.0.0release.We may all have see The Light, and realized that the number
1is in fact a perfectly fine place to start counting our releases, and casually increment the major version with every breaking change if that change provides some value. But many are timid, and talking them out of their timidity is very difficult.Yet, the language in section 4 makes it very difficult to rely on pre-1.0 code. I believe that this increases, rather than decreases, the trepidation at marking something 1.0. It would be better with a slight increase in commitment; a stepping stone from the wild world of
0.0.4up to the public scrutiny of1.2.3.This would also allow project authors to communicate non-breaking additive changes in the
0.x.yversion families. In practice, many seem to treat the transition from0.9.2to0.9.3as a non-breaking change, whereas they'd treat0.9.2to0.10.0as potentially introducing breaking changes. (Node, for example, operates this way, though that is a pretty egregious example of Sentimental Versioning.)In effect, the left-most non-zero version number is the "effective major version", and incrementing it indicates a breaking change. The next place is the "effective minor version", and the third is the "effective patch version". This allows authors to more gradually shift from "anything goes" to "grownup".
The
^operator in https://github.com/isaacs/node-semver used to operate this way, until some users requested that it instead follow the SemVer specification. However, shifting to^0.x.ymeaning "exactly equal to 0.x.y" has proven very problematic in practice.I haven't wordsmithed this very much, but this is a first-pass at some language we could use to express this. If others on this repo feel it's worthwhile, I'd be happy to send a proper pull request.
cc @Haacked @mojombo @othiym23 @domenic @ceejbot
@FichteFoll commented on GitHub (Sep 4, 2014):
You should consider that the FAQ suggest to use
0.1.0as first development release.(this was edited)
@haacked commented on GitHub (Sep 4, 2014):
It basically makes
0.1.0equivalent to1.0.0then, right? Will this cause people to then face0.1.*with trepidation and keep versions at0.0.*?I wonder if it would be better to say this is a recommendation for
0.*.*releases as a means of communicating intent, but be aware that as it's still pre-release software, the versioning scheme could be violated.By that I mean the change from
0.1.0to0.1.1is intended to be additive, but because of bugs in the pre-release code, there's still the risk of it being a breaking change.Of course the same is true with released software. The move from
1.0.0to1.1.0could inadvertently introduce a breaking change. The difference is that when you remove the pre-release label, you're communicating that you did some amount of due diligence testing. Whereas with0.*releases, you might not have done any testing to verify you're compliant with the versioning claims.@ceejbot commented on GitHub (Sep 4, 2014):
I love this suggestion very much. I think it accurately captures the distinction in my mind between
0.0.zand0.x.yversion patterns: alpha vs beta. It also describes the real-world behavior I've seen developers use when incrementing version numbers. The strictness increases, and the contract is fully in force once the major number is > 0.@othiym23 commented on GitHub (Sep 4, 2014):
I am also in favor of this change, for reasons specific to my understanding of conventional usage within the Node community (I have no numbers to back any of this up, hence the cagey phrasing). There are several large ecosystems (most notably grunt's) where versions are coupled between plugins and "master" packages (what are called
peerDependencieswithin Node), and the ecosystem as a whole is not yet at version 1.0.Developers within these communities are using the operators provided by
node-semver,~and^, to say "I want nonbreaking changes to the master module on which this module depends". With~this isn't a problem, as its intended interpretation is "reasonably close". With^, the intended interpretation is "compatible", and upon switching the meaning of^to be compliant with semver 2.0, we have suddenly rendered any plugins that are using specifiers like^0.4.2uninstallable – we have introduced a form of dependency hell where the plugin and the master module can no longer satisfy the version criteria for peer dependencies.The Node world is particularly rife with 0.x.y-versioned packages, and while the current text (and @Haacked's reasoning above) is a reasonable normative interpretation of semver, bringing the community's understanding into convergence with the standard is particularly difficult given the community's size and the inertia already accumulated by current conventional practice. I favor the approach suggested by @isaacs purely out of pragmatism – it matches what I see as the most common practice in the community I support.
@haacked commented on GitHub (Sep 4, 2014):
That's interesting and is in line with the philosophy of SemVer. Do you see this practiced in other communities as well?
I'd really like to hear from @mojombo on this as I know he's had strong feels. I still think making it a recommendation rather than a MUST might alleviate that. I'm not sure.
@isaacs commented on GitHub (Sep 5, 2014):
I think @othiym23 @ceejbot and I are all pretty full-time on Node and npm these days. Can't speak for other groups, but as npm becomes widely adopted for frontend stuff, we do see a lot of Java and Ruby folks picking it up.
Not quite.
1.0.0says "bugfixes that don't change the API increment the patch, and additive changes increment the minor, and breaking changes increment the major."0.1.0says "bugfixes and additive changes increment the patch, and breaking changes increment the minor (or major)."So, it is a smaller commitment, since additive changes can come along with bugfixes, without having to differentiate between them.
Not in my experience. It's an intermediate step that "feels" smaller.
@domenic commented on GitHub (Sep 5, 2014):
I am against this suggestion, because I think it stems simply from a poor quality of implementation issue in npm that has persisted until recently. That is, I think it does not reflect ipso facto author sentiment, but instead a post facto rationalization in favor of npm's formerly-broken implementation and the ecosystem that grew up around it.
In contrast, from talking to @wycats and his work on the greenfield Rust/Cargo ecosystem, the differentiation that pre-1.0.0 provides seems to have proven useful and to have been accepted in that ecosystem as a good dividing line between "very early development; dependencies should be pinned exactly" and "stable enough to start automatically getting features and bug fixes." Notably the latter category can benefit from deduping, whereas the former demands separate on-disk instances for each instance of a package in the abstract dependency tree. Dividing these clearly between pre-.1.0.0 and 1.0.0 onward is very helpful, and moving that line back to 0.1.0 does not seem like a good idea.
@rlidwka commented on GitHub (Sep 5, 2014):
The majority of npm users doesn't care about semver. So you suggest to fix this by changing semver to fit existing practices... I suppose next will be breaking post-1.x.x minors, because we have tons of those.
Please, just stop that already. Semver is great as it is. But it can't be used everywhere. It is meant for production-quality libraries with long iterations (like
requestfor example, orexpress- but there is a talk to change that). But most npm packages are the exact opposite of this.So, my suggestions are:
~. Let people override that if they know what they are doing.^).Let people use versioning system they want to use instead of trying to squeeze semver everywhere. You forcing people to use it, they fail to do so, and they blame the spec (1, 2, 3), while in reality it's npm at fault here.
cc: @jashkenas @balupton @jonathanong @mikesherov @dmethvin
@isaacs commented on GitHub (Sep 5, 2014):
To be completely honest, my first choice would be to drop the magic zero entirely.
SemVer should start at 0.0.0. The first breaking change should be 1.0.0. If the first "production ready" release is 10.22.0, then so what? Integers are cheap and plentiful.
A period of "anything goes" versioning encourages oversized modules and poorly thought-out designs that should usually be abandoned rather than refactored. It is exactly the reason why semver is a good idea in the first place.
I realize that this is a minority opinion. But that's why npm init starts at 1.0.0 by default now. 0.x versions are too hard to reason about, and encourage bad antisocial practices.
@isaacs commented on GitHub (Sep 5, 2014):
Also, we already have "anything goes" versions with prerelease tags, which are more orderly anyway.
The next version of node-semver will not let prereleases match on version ranges, so it's just as useful as 0.x is today.
@haacked commented on GitHub (Sep 5, 2014):
Not to diverge too much from the discussion, but I wanted to understand how NPM treats
0.*packages.For example, by default, NuGet only displays stable packages. The non-risk-adverse user can opt into pre-release packages by specifying the
-Preflag. NuGet only uses the presence of the pre-release label to indicate the software is pre-release. It treates0.*packages as if they were stable and includes them by default (rather than only including them when the-preflag is in use).I'd argue that this is a bug in NuGet.
I think it should treat
0.*packages as pre-release. Via the power of defaults, the fact that they're hidden by default would put pressure on authors to get to1.0.0and start following SemVer and not stay in0.*"anything goes" land forever.Does NPM work in this way? The reason I ask is another option that accomplishes much of what you propose is to allow but hide
0.*packages. This would compel package authors not to stay in0.*forever as there's a very good reason to get to1.0.0- broader distribution.@haacked commented on GitHub (Sep 5, 2014):
/cc @jeffhandley for that NuGet bug ^^^. 😄
@domenic commented on GitHub (Sep 5, 2014):
I really like the idea of hiding 0.* packages. I don't think it'll work well in the Node ecosystem though---some large-ish percentage of packages would disappear from the npm website.
@balupton commented on GitHub (Sep 5, 2014):
I don't really know why I was invited to comment on this. My personal experiences with things like this, is that the public opinion doesn't matter as it doesn't win against conventions, which is the entire point of conventions, which is why I dislike conventions.
I think that the way npm handles things currently is fine. I think complexity is evil.
Semver should be advisory, not enforced, for it cannot be enforced, without a never-ending spiral of complexity, such as this.
Yes. Npm has taken the stance, that npm is pro-semver, and you should follow it (not must follow it). However, changes like this, or the proposed changes in npm, make this silly, as it is we are pro-semver, except in the cases where we accept people don't follow it, so therefore we'll add an exception for that in the semver standard, so that hey, we can be pro-semver again while facing the reality that semver is an idealistic standard that can only be advised and not enforced like we want.
I'd like for a liberal and caring npm (remember when npm's tagline was "npm loves you"), recently this semver debacle is more like a totalitarian npm, where npm controls you.
As one who follows the current semver spec, I have published many modules where the initial or a subsequent 0.x.y version was fine and never needed to publish more.
Hiding the 0.x.y releases, means I gotta do unnecessary bumps for following the current semver spec. This also means current package consumers need to update their version ranges too.
Adding this change, also invalidates the integrity of those packages where the 0 versions where fine. For the few people who hadn't caught on to the semver standard yet.
If people want a playground for breaking things, use the git repo.
@rlidwka commented on GitHub (Sep 5, 2014):
Oh, sorry for spamming, I just mentioned people whose posts I was referring to earlier. I'll try to be quieter in the future. :)
@balupton commented on GitHub (Sep 5, 2014):
No worries at all, appreciate it even if it wasn't clear why I was invited. Having a question with the cc, or a why I was cc'd, would be useful just to reduce the confusion of such a notification. Hopefully I'm on the right track with my ramblings above.
@FichteFoll commented on GitHub (Sep 5, 2014):
@balupton
First, I really like the idea of hiding
0.*packages too. It gives the author a reason to finalize his product/package so that it can be consumed by the large public. Of course, this has to be treated differently by each package manager because they are all different in a way, but the general idea is good.Second, you're not doing "unnecessary bumps". If your software is working fine and people are using it in production or anything, you should consider switching to
1.0.0so that those who depend on it can trust on the conventions that a semantic version follows. By communicating that you're on a major >0 you tell developers that depend on your library that you do not intend to make large changes to the library/API in the same pace as you might have done <1. They can adjust their version range to~1(all versions with major 1) and be sure to receive non-breaking updates while this is not the case when <1. Semver is fine with that regard, it's just that people are too hesitant to do the 1.0.0 move and hiding 0.* packages helps with that decision.@rlidwka
Why would that be a problem with semver? Atom is already at
0.124.0and nobody considers it to be out of the initial development phase since they are changing their stuff rapidly (e.g. switching to React recently).1.0.0 should be used when you think you reached a point where the API (or something similar; that's a topic of a different issue) that you want to – or your clients want you to – continue supporting.
@balupton commented on GitHub (Sep 5, 2014):
That's a lot of notions all based on the premise that 0. means something different than 1+, which for a lot of people, it doesn't, nor does the current semver spec indicate this. This is a new convention that is being proposed here.
Exactly the required changes to a perfectly functioning 0 version that follows the current spec. Unnecessary as without changing the spec, none of the above would be needed.
@domenic commented on GitHub (Sep 5, 2014):
False. The current semver spec does indicate this, and it is not a new convention. semver.org:
@FichteFoll commented on GitHub (Sep 5, 2014):
My statements are solely based on the most recent spec of semver, 2.0.0, and maybe a bit of interpretation in case the initial wording is not 100% clear.
The core difference for clients depending on software 1.* and 0.* is that they can rely on 1.* versions to not break and thus specify a range selector. With 0.* versions this is not feasable because development between minor releases (which could potentially break and thus have to be checked manually for compatability) is too rapid and patch releases could (currently at least, according to the spec) contain breaking changes as well, so you can only select a specifc version as dependency instead of an entire version range.
Imo, the only thing that semver currently needs regarding versions prior 1.0.0 is a mention of
0.major.minorwhere patch and minor changes get to be grouped. In fact, you can always make a technically only patch update into a minor update because semver does not disallow it, but currently there is just a bit too much of confusion regarding pre-1 releases.@balupton commented on GitHub (Sep 5, 2014):
Wow my mistake. Sorry about that. Let me revaluate my position on this.
@othiym23 commented on GitHub (Sep 5, 2014):
I haven't had time to do an audit of the registry, but I'm guessing it would be a majority, and perhaps even a large majority.
@haacked commented on GitHub (Sep 5, 2014):
Something that just occurred to me. The problem isn't the "magic 0", but a problem of incentives. There are a group of folks who aren't ready to have their libraries subject to the constraints of SemVer and are skirting around it because it's less of a headache to do so. We have to make the benefits of SemVer outweigh that and provide incentives for embracing the constraints.
Consider this, the intent of
0.*is to indicate the software is pre-release in the same way that the pre-release label does. So if we started applying constraints on0.*, then folks who want the "anything goes" approach will simply add a pre-release label.0.0.1-betato circumvent it (unless we prevent that). Or they'll increment it to1.0.0-betaand never remove the label (Google! amirite?!). Why should the0.*packages have a different set of constraints than a labeled pre-release version?In order to change people's behavior in any given community, we need to give them an incentive to embrace the constraints. Hiding pre-release packages is one possible approach. Maybe that's too drastic for some communities. Other options might be to simply warn users when they install pre-release. Get them to tell the authors to supply a release version. Or show a message to package authors when the package has been pre-release too long asking for commitment (joke).
I think adding more rules increases the complexity without solving the root problem. Especially when there are easy ways to skirt around it.
@FichteFoll commented on GitHub (Sep 5, 2014):
👍
@othiym23 commented on GitHub (Sep 5, 2014):
@Haacked
I think part of the reason @isaacs opened this issue is that we at npm have maneuvered ourselves into a bit of a tricky position with respect to our community and its behavior. We introduced the
^operator tonode-semverat the beginning of the year as a more semver-compliant equivalent of the~operator. In particular,^1.2.3does include1.3.0, but~1.2.3does not. Since we made it the default about six months ago (which was probably not adequately evangelized to the Node community, which has led to a lot of additional support work), people have used it pretty widely, and have treated it more or less as equivalent to~, including for0.x.yversions.About a month and a half ago, we collectively noticed that the way
^worked was out of sync with semver 2.0, and so we decided to "fix" the operator to be more compliant with the standard. At the time, @timoxley suggested the introduction of a new operator with the fixed semantics (because the introduction and defaulting to using^as the prefix for saving semver ranges in npm manifests has caused significant support headaches), but my counterargument was that down that road lay an arbirtrarily long trail of semi-broken operators as we try to get this right. So we releasednode-semver@3with this change and also did the arduous work of bumping the major versions of all ofnode-semver's dependents used by npm.Unfortunately, our community has not really followed our lead (in part because it's very difficult to reach all of them in a consistent way, especially because we are not all of one mind, as this issue shows), and we are now at the point where, if we release npm 2.0.0 with this behavior, we are going to break several plugin-based ecosystems because of how a wide network of distributed developers have decided to implement versioning in their plugins. In particular, this will make it impossible for grunt, broccoli, and gulp users (who are not necessarily Node developers) to install certain sets of plugins that were compatible before, because some of those plugins are (peer-)dependent on
grunt@^0.4.2where others are dependent ongrunt@~0.4.3.The fundamental problem is that
^and~(or even getting the broader community to fully understand the difference between them – I didn't get it completely until I'd been working at npm for a while, and I had a strong motivation to understand this stuff)are all boil-the-ocean problems: they require extensive evangelization efforts, and presume that we even can reach (and convince) enough of our user community to make a significant impact.
As this thread has shown, there are a number of uncompromising, hard-line opinions within the Node community about the significance and proper interpretation of semver with respect to npm (I sort of blame @domenic for getting us in this mess in the first place). I see some value in normative behavior for 0.x.y versions, but I also see strong evidence that, in our community at least, it hasn't achieved a strong enough consensus to warrant how punitive this change is turning out to be. The least painful thing we could do prior to npm 2.0.0's release would be to revert this change to how
^operates and just accept that we lack the ability to unilaterally impose semver-conformant behavior on our community at a reasonable cost. @isaacs's proposal is an attempt to change semver to make this less of a deviation from the standard, but it's also a suggestion coming from a place of deep experience with a significant community./cc @rvagg, who has been known to have strong opinions about how npm deals with semver in the past
@mikesherov commented on GitHub (Sep 7, 2014):
My 2 (relatively unexperienced and naive) cents are this:
At this point, the
npmuse case extends beyond the node community, and even if it didn't, the node community has expanded wide enough that the only imposable behavior is behavior that has far and wide consensus.Those who remain
0.x.ydo so as a (possibly unintentional) protest to semver and the default behavior ofnpm install --save...While almost everyone can agree on "no breaking changes in patch releases", some folks operate on the assumption they can do minor breaking changes in minor versions. This is partially because the old default in npm was
~.On top of that, the semantics of semver are such that major breaking changes can not be distinguished from minor breaking changes at all. Some devs find this undesirable.
On top of that, some devs want their users intentionally (vs. automatically) upgrading when they release new features.
On top of that, some developers believe that requiring a major version bump on every breaking change reduces innovation because projects tend to "save up" their breaks and do them all at once, making the threat of 1.0.0 -> 2.0.0 artificially seem less panic inducing than a bump from 1.0.0 -> 10.0.0 would.
I share several (but not all) of the "problematic" beliefs above, but I'm personally willing to forgo them. However, I whole heartedly agree on the nature of these problems: boiling the ocean. For every me who's willing to bend, there are 10 who aren't.
Therefore, in light of this, it seems that the simplest change that could be made is to return the default behavior of
npm install --saveto~and have it behave the same for both0.x.yand1.x.y: latest patch version of this minor.That'll allow the grunt, gulp, and brocolli ecosystems to once again work, it'll allow authors the freedom they used to have to instrument what they consider major vs. minor, and it'll make devs consider the benefits of upgrading minor versions (which theoretically are only for new features, which perhaps devs shouldn't be blindly upgrading in the first place).
The downside of this approach seems to be more manual updating of libraries. But to prove that, we need hard numbers, not theory:
How often is a major release published compared to a minor compared to patch?
How often before the
^change?How often after?
@isaacs commented on GitHub (Sep 8, 2014):
npm will not be hiding 0.x versions. Interesting idea, but the costs dramatically outweigh any potential benefits.
There are at the current moment, 418,088 releases of 0.x versions, and only 64,536 releases of 1.x versions, 15069 at 2.x, and 5017 at 3.x. (It falls of dramatically from there.)
Most npm modules never are bumped up to 1.x. The reason is most often not a lack of support, but rather a lack of breaking changes. If a module is created, and given a 0.0.0 version, then each release that fixes a bug gets a 0.0.1, 0.0.2, etc., and each release that adds functionality gets 0.1.0, 0.2.0, etc.
Are all of those releases "unstable"? Not fit for public consumption? Let's look at the data.
The most downloaded module on npm is
mkdirp, which is version 0.5.0, and as stable and battle-tested as you could possibly want.async, second-most depended-upon module in npm, is version 0.9.0, heavily used everywhere, and only very rarely updated for the occasional bugfix. Grunt, the third-most-starred module in npm, and the fastest growing npm sub-community, used by people who only treat Node and npm as an implementation detail while building sites in Ruby and Java, is version 0.4.5, last updated 4 months ago. Extremely stable, and limited enough in its design to only very rarely require breaking changes.The spec says that 1.0 is the "first public release", but that's not actually how it people are using versions most often in JavaScript land.
x.y.z-alpha.1andx.y.z-beta.2and such are used for pre-releases.0.x.yversions are public releases. Tens of thousands of authors are releasing code to millions of users with 0.x versions. If the spec is intended to be descriptive here, it is incorrect; if the spec is intended to be prescriptive, then it is failing.npm already is defaulting to 1.0.0 as the first version number in
npm init. But that default will take a long time to catch on, if it ever does.We can either change the spec to reflect what people are doing, or we can change people to reflect what we think the spec ought to be. So, is SemVer a political manifesto, or a reflection of expected practices and reasonable expectations? Are we paving cowpaths or exercising eminent domain to build highways through existing cities?
As it stands, I have been coming to the conclusion that the
^operator was actually correct in node-semver 2.x. We should have just said that^is "what the spec should be" rather than "what the spec is".@boneskull commented on GitHub (Sep 8, 2014):
👍
@FichteFoll commented on GitHub (Sep 8, 2014):
Sounds similar to what I interpreted the situation as. The core problem in the npm situation is very likely:
and means that the core aspects of semver were not communicated well enough, especially considering that they use it the same way for 0.x.y versions.
So, I think the easiest band-aid fix is to make the
^operator behave like~when used with 0.x.y versions in npm's semver implementation.Regarding "1.0.0 as the first public release", I think this is wrong. I'm not sure whether this is actually in the spec, but if it is it should be removed. 1.0.0 is for when you reached a point where people depend on your library to "not break", and if they do that while you're still on 0.5.4 without breaking it regularly (~once a month) you should consider bumping to 1.0.0 for that reason. You don't even have to change anything in the code, a simple version bump would be perfectly fine here.
Which brings us to the other problem with people using semver: They don't want to reach the 1.0.0 threshold, but that has been talked about before alread. I think we should arrange an "international 1.0.0 day" where everyone gets to raise their projects' versions to 1.0.0 when he thinks he can. I recently did that, too.
@isaacs commented on GitHub (Sep 9, 2014):
It is. From http://semver.org
The update for npm is implemented and documented in node-semver v4, along with some saner handling of prerelease tags. If anyone here wants to weigh in on the issue, please be my guest: https://github.com/npm/node-semver/pull/99
@FichteFoll commented on GitHub (Sep 9, 2014):
@isaacs "Version 1.0.0 defines the public API" is not the same as "1.0.0 is the first public release". This is fine.
Well, it might still be poorly worded and allow misinterpretation, but it's not just a wrong statement.
@tomByrer commented on GitHub (Sep 19, 2014):
Ideally v1.0.0 should be the first release. Reality is the first 'release' is what ever winds up on GitHub or a blog post first. So what is more realistic compared to the time you have & human nature?
or
@rlidwka commented on GitHub (Sep 19, 2014):
Those people don't follow semver. Therefore, it's not applicable here.
@isaacs commented on GitHub (Sep 19, 2014):
@rlidwka
This is a needlessly pedantic point of view.
What is the purpose of the SemVer manifesto and specification, if not to document and specify the semantics that a version number can be reasonably expected to convey?
Not trying to get all "philosophy of language" here, but... yeah, actually, what the hell is the good of a liberal arts education if you never get to use it? Here we go. :)
Semantics are defined by the community of players of a language game. There may be multiple dialects, but trying to define a "correct" dialect is presumptuous, and declaring that any dialect is more "semantic" than another is completely ludicrous.
The SemVer specification is like a dictionary, in two major ways.
In the first way, it is originally intended as a document of the most common semantics implied by a given set of tokens. From that point of view, it is the duty of the maintainers of this specification to update it from time to time as token usage evolves.
Second, it is like a dictionary in that it is both properly and improperly used as a tool of social pressure to add friction to language evolution.
Wild dramatic shifts in a language tend to fragment communities, rendering them unable to communicate with one another. It is reasonable for a language community to use such a tool to police itself, and either expel or re-educate violators, so that communication can continue.
However, once such a shift has occurred, attempting to use the dictionary to argue for it to swing back is completely unreasonable (and in any event, it is unlikely to ever succeed).
Arguing over whether a dialect is "correct" is meaningless. A dictionary that ignores a predominant dialect is itself incorrect.
So, if we accept the above, there are two questions:
In terms of the relevance of a dialect of language game players, size matters.
There are just over 95,000 modules on npm today. Both in terms of absolute number of packages and in terms of relative month-over-month growth as a percentage of current size, the npm registry is the fastest growing package index on Earth. Packages are downloaded about 450MM times per month, to about 15MM unique IP addresses. There were 1.4MM unique users of the npmjs.org web site in the last 90 days. Our best estimate is that this community is about 2MM people, but of course the error bars are pretty big there. It's rare today to find a JavaScript dev who isn't familiar with npm, or a software application that doesn't involve JavaScript in some way.
How does that compare to Rubygems, NuGet, Rust, or other communities ostensibly using the SemVer language to communicate software changes?
I can totally accept the argument that the specification should not be dictated by npm's whims. But neither are "npm's whims" irrelevant! At the very least, the 0.x language should be revisited to acknowledge that such a dialect exists.
@isaacs commented on GitHub (Sep 19, 2014):
By the way, I'm not arguing that "number of packages" necessarily indicates "bigger". CPAN, for example, contains much more "human work hours", and probably many many more lines of code.
However, the number of packages is exactly the "number of versioned artifacts", and the number of SemVer-moderated interface boundaries is a geometric explosion of the number of versioned artifacts.
So, in terms of "how much SemVer-ing does this community do?" I don't think you can find anything anywhere near on the scale of npm. This is a huge chunk of the language game players that the SemVer dictionary ought to be tracking.
@rlidwka commented on GitHub (Sep 19, 2014):
This is a big overestimation based on the assumption that every npm package actually uses semver.
The issue is: not every npm user voluntarily chose to follow it.
If you talk about numbers here, npm has 95000 packages, but how many of them:
There are no such statistics, because npm refuses to add "versioning system" information to package metadata.
So I can't answer that. I know
requestdoes follow semver, I knowjquerydoesn't. We can't check all of them, but I'd bet the majority fits under last category. They follow default settings without even knowing what they are, and can routinely break stuff in minor releases. Call that "semver users" 'cause I don't.Are there people who chose to use semver, but has an issue with 0.x releases? Anyone?
@tomByrer commented on GitHub (Sep 19, 2014):
It is like specs that the W3C publishes:
@rlidwka commented on GitHub (Sep 19, 2014):
@tomByrer , W3C standards are about computer behavior. This spec is about human behavior, what people should or shouldn't do when they release stuff. It's more like code style really.
@tomByrer commented on GitHub (Sep 19, 2014):
@rlidwka I'm rather certain that isaacs's node-semver both tries to reflect this spec & is 'computer behavior'. & there are other SemVer programs out there.
Though yes, 0.0.0 vs 1.0.0 for a "first official release" is more about human perception vs spec rules ;)
@isaacs commented on GitHub (Sep 19, 2014):
Semantics come from humans. The spec ought to be first and foremost a description of what humans do.
Are you claiming that npm users literally have no shared understanding of what version numbers mean? That is an extreme claim, requiring compelling evidence.
A more modest claim would be that the humans using npm have some shared understanding of how to interpret version numbers, and that this meaning is affected more by the default behavior of npm than by any specification.
You say "follow semver" as if this specification is an immutable dogma that people are aware of. But it is not immutable, and dogmatism is misplaced. It is primarily an attempt to codify what people are already doing. If SemVer isn't documenting the common understanding of version numbers, then it has no value.
The people who are aware of it and read the spec are a rounding error compared with the number of people who don't read it, and assume that they know what it says.
A better question, and in fact the only question that maintainers of this spec should be concerned with, is "What are the semantics that a majority of X.Y.Z-style version users convey with their version numbers?"
So, here's the bottom line: npm is going to keep using
0.x.yas effectively0.MAJOR.MINOR. This behavior is too entrenched to reasonably alter at this point. In our attempt to change npm's behavior to align with the semver.org specification, and the resulting backlash and review of package data, we found that it has this meaning on our community. This is not a debate; it is a fact about the semantics of version numbers within the npm community at this time.In order to reduce confusion about this, we no longer say that the
^range operator is "based on the semver.org specification". Instead, we state exactly what it does, with examples and justification, and leave the spec out of it. It's clearer documentation anyway.We are adding the behavior that any
X.Y.Z-prereleaseversion will not match against version ranges unless the range explicitly includes a matchingX.Y.Ztuple with a prerelease version. This is all documented over at https://github.com/npm/node-semver. The pull req that introduced this change is https://github.com/npm/node-semver/pull/99. This is also already causing a bit of upset, but not nearly as dramatic. (There are packages that useX.Y.Z-A.B.Cstyle versions to indicate the version of a library they bind to. However, this means that every release is a "prerelease", so we're going to have to get them to change things. There are only a few of these, so it shouldn't be too terribly hard.)It is my contention that the spec should reflect the real semantics of version numbers. I don't think that's a controversial point. It's also my contention that the npm community's usage is a relevant portion of the semantics of version number usage.
If the spec maintainers disagree, then whatever. I'm getting repetitive, so I'll stop replying to this issue unless new questions are brought up. Thanks.
@isaacs commented on GitHub (Sep 19, 2014):
Specs are only about human behavior.
Software defines computer behavior. Humans write software. The spec assists humans in writing software that works with other software. It affects the human behavior of writing and modifying software.
@FichteFoll commented on GitHub (Sep 19, 2014):
I sure think that all MPEG specs are about human behavior.
@ronen commented on GitHub (Nov 25, 2014):
Joining this discussion late, and getting back to @isaacs's original post in this issue, I also believe that 0 should not have any special significance -- but not because of any "trepidation". Rather, for other reasons:
So IMHO if rules 4. and 5. of the spec were simply dropped, everything would work just as well, or even better.
@jwdonahue commented on GitHub (Dec 7, 2017):
IMO, 0.x.y or 0.0.y should both be banned from the SemVer spec in version 3.0.0. The -prerelease tag effectively has the same default semantics. Virtually all packaging schemes seem to cover the prerelease tag semantics quite well. Dropping the 0.x.y loop-hole would simplify the world and add the ability for developers to tell their customers, here's what I think is just a new non-breaking feature, but I know this technology is immature and we're still receiving surprising feed-back from our customers so I have this prerelease tag on it because I am uncertain that I won't break a significant number of my customers.
Forcing all prerelease versions to have a prerelease tag on them, frees up the entire SemVer triplet for the package producers to advertise their full intent while simultaneously tagging the release as risky. I see no problem with packaging tools refusing to handle this one feature of SemVer, provided they offer proper support for the prerelease tag and semantics.
EDIT: To clarify, 0.0.0-X.Y.Z and x.y.z-anytag would all be valid prerelease forms, but specifically, the leading 0.x.y (no prerelease tag) form would be banned. I think the original 0.x.y bootstrap form was conceived before the full semantics of how prerelease tags might be used was fully understood.
@jwdonahue commented on GitHub (Dec 7, 2017):
@isaacs, unless you intend to pursue this issue further, please close this issue at your earliest possible convenience.
@elypter commented on GitHub (Feb 7, 2018):
couldn't this all be solved if you add the exception that you can bump from 0.x.y to 1.0.0 without needing a breaking change? just allow people to bump when they feel the project is ready but the interface wont change anytime soon. if this is part of the standard then applications will simply ignore the pseudo major bump. the only downside is that you cannot do a major change while jumping to 1.0.0 but then you can still just do it right before.
@jwdonahue commented on GitHub (Feb 7, 2018):
The standard already specifies that 1.0.0 is the first stable version. Literally every change up to and including the 1.0.0 release is potentially, but not required to be, a breaking change. In other words, risk averse consumers wait for 1.0.0. From that point forward, you should not bump the major version unless you have actually introduced breaking changes.
@elypter commented on GitHub (Feb 8, 2018):
maybe make this more clear in the manifest so nobody gets the idea that you cannot just bump to 1.0.0 if you think the time is right.
@jwdonahue commented on GitHub (Feb 9, 2018):
@elypter,
People get all kinds of ideas in their heads. The spec can't possibly account for every irrational idea that might come into every developer's head. That said, I would personally prefer to see the 0.x.y release mode removed from the spec in vesion 3.x.x. The prerelease tag can be used effectively to cover all prerelease contingencies. The current spec essentially requires that all 0.x.y versions must be treated as prerelease anyway, so why have two forms? Well, it's probably historical, so it was captured in early versions of the spec, but we don't have to continue to perpetuate it.
Related: #287, #333, #238.
@grv87 commented on GitHub (Apr 29, 2018):
@jwdonahue, could you clarify your opinion? Does I make these right?
0.25.47, it becomes not complaint to the standard. I should release0.25.48-prereleaseinstead.1.0.0-prereleaseversion.If these are correct, then it looks OK for new libraries but not for existing. How, having
0.25.48-prerelease, I could make a release not making breaking changes?Or commit with incremented major version is considered as a breaking change itself?
@jwdonahue commented on GitHub (Apr 30, 2018):
@grv87 ,
The spec explicitly spells out what you must and should do as a publisher, when you make certain kinds of changes, depending on whether they break back-compat (major bump), add back-compat (minor bump) features or just publish changes with no new features (patch). It does not prohibit version changes in the absence of underlying product changes. In fact, the only way to recover from publishing errors is to remove the erroneously versioned package from public feeds and issue a new package with a correct version number based on the rules (ie, two packages in the world with identical content and two different version numbers is okay, but probably SHOULD be avoided).
The spec also implicitly defines expected risk levels to consumers of your published packages and therefore also guides their policy choices in automatically accepting updates. If you have been publishing a series of 0.y.z releases, your consumers are already treating them as though each release is very risky and also might be valuable to them. They are in a co-development phase with you and are eagerly awaiting completion of a relatively bug free and stable product. They may be taking every update from you, testing it and then deciding whether to publish their own bits that include your updates, or they may be stuck on a more-or-less useful version for their own purposes and waiting for you to complete the project before they devote much more effort into taking a new update. It's actually a continuum between those extremes for most of your consumers.
An arbitrary change on your part from 0.y.z to 1.y.z-prerelease might trigger some of your customers to take a closer look at your new release, and that will likely consume some of their resources. In the absence of guidance from you, they might assume that you are entering a more stable phase than in the past. Most of their tooling however, should distinguish both 0.25.48 and 1.0.0-tag as being of the prerelease risk class, but I don't know that there aren't some tools out there, that break the prerelease category down to higher and lower prerelease subcategories.
No-one has labeled my earlier suggestion as barking mad, yet, so I take that as a good sign, but you have to consider what you know about your customers and make the correct choices for you and them, to the best of your abilities. I can only make some general recommendations how you might convert to the prerelease tag form from the development form. First, taking your example above, your next release would be 0.26.0, whether or not you added new features or breaking changes, because you're about to make a big change in your versioning semantics. You include in the your release notes, a prominent notice of the intended change in versioning and the next package version number, which will be 1.0.0-a.dev (or whatever tag is appropriate for you) and except for a change in the release notes, that package contains the same bits as 0.26.0. Your customers can then fix any knock-on bugs in their own products caused by integrating 0.26.0, review and adjust their intake policies and then verify that the entire publish/consume chain of events works correctly, without having to worry about changes in your code.
Personally, I would only go to all that trouble, if I was going to produce new products. In that case, I wouldn't want to be supporting different workflows for different products. If I had been using the 0.y.z scheme on an earlier product line, I would convert. After working with semantic versioning for several years and having developed tooling around it, I see an advantage to the 1.0.0-X.Y.Z.Tag form of prerelease series, where the X.Y.Z are given full SemVer semantics and it is obvious to everyone that the target release is 1.0.0. It conveys a richer set of information to my consumers and it allows me to more easily support overlapping version 1 and version 2 projects (ie, development on N and maintenance on N-1). I tend to fix bugs first, then do features, so my typical version history might look something like:
1.0.0-0.1.0.dev // Made available to QA and very early adopters (VEA's).
1.0.0-1.0.0.dev // Just broke the world.
1.0.0-1.0.1.dev // Bug fixes.
1.0.0-1.1.0.dev // Making progress on the feature set.
1.0.0-1.1.1.dev // More bug fixes.
1.0.0-1.1.2.flight.0 // Dogfood release.
1.0.0-1.1.2.flight.1 // Wow, good at this, let some outside early adopters have a look.
1.0.0-1.1.3.flight.2 // Fixed bugs, widen audience.
...
1.0.0-Alpha.1 // Earliest generally available release.
1.0.0-1.1.4.dev // Bug fixes for QA and VEA's.
1.0.0-Beta.1 // Getting closer. This is 1.0.0-1.1.4.dev with a new label on it.
1.0.0-RC.1 // Locked down, only bug fixes from here on out.
2.0.0-0.1.0.dev // Moved resources to next generation.
1.0.0-1.1.4.dev // QA & VEA's
1.0.0-RC.2 // Decided to 1.0.0-1.1.4.dev is RC quality, publish it.
... A bunch of version 2 series releases ...
1.0.0 // New cars start showing up in the parking lot :)
2.0.0-1.0.0.dev // Lots of next gen work going on.
1.0.1-1.1.3.dev // Bug fixes in the works for v1.
etc...
The above version history is a plausible SemVer compliant sequence. Some CI tooling already supports it, some don't, in fact, some get in the way of implementing it like that. Obviously, not all of those versions are available to everyone.
Unfortunately, SemVer does not provide the means for defining the semantics for the prerelease tag identifiers (fields), beyond their sort order. Pure numeric prerelease identifiers sort lower than alpha-numeric identifiers. I have been working on and off, over the past few months, on a scheme to provide the means for developers to publish the full semantics of every field in their version scheme. A human and machine readable VersionSchema is required to bring more order to semantic versioning.
See https://VersionMeta.org/ and stay tuned.
@grv87 commented on GitHub (May 4, 2018):
IMO, @ronen suggestion to just drop rules 4 and 5 is simpler.
But I can't see any practical difference, turns out it's just personal preference to start major versions from 0 or from 1. When I use semantic release tool it starts versions from 1.0.0 anyway.
When we could expect semver 3.0.0 prerelease with changed magic zero rule?