5 ms·
CoffeeScript doesn't follow "Semantic" versioning. Most projects that claim to follow "Semantic" versioning actually don't. Take, for example, the other news a
by jashkenas 12y ago
CoffeeScript doesn't follow "Semantic" versioning. Most projects that claim to follow "Semantic" versioning actually don't.
Take, for example, the other news at the top of the front page, Io.js 1.3.0 — a minor version bump that should include zero breaking changes to the public API.
And yet, 1.3.0 "broke" the way that urls are resolved with regards to trailing slashes: https://github.com/iojs/io.js/pull/278 https://github.com/iojs/io.js/pull/278
If you follow SemVer — and I don't think that Io.js should, or have to pretend to — this must be yanked, and re-released as Io.js 2.0.
Ironically, the behavior being complained about in this post relates to how CoffeeScript decides to name internal compiler variables. This is not something that has ever been part of the public API — and is something we can (and might) change at any point. We've changed it in the past.
Breaking changes in your API are a good thing — when the new way is better than the old. But this isn't one of them.
For more on SemVer, and why you should resist giving in to its fascist attempt at world version domination, see: https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e
I get that SemVer is an attempt to address dependency pain — but it's woefully inadequate, reductive and dangerous. We can do better.
- deleted 12y ago[deleted]
- kenperkins 12y agoI've felt for quite a while that we could have had a 4 octet semver that allows for a first octet romantic version while the others are proper semver. For example: io.js version 1.2.0.0 instead of 1.3.0. It would still be machine readable, but allows a human component (romantic version) to precede. Thoughts?
- dragonwriter 12y agoFirst, why? Semver is for humans -- it puts a defined meaning to version numbers so that humans can gain useful information from them (this also is useful for automation, because once there is a clear unambiguous meaning, workflows, automated or not, can use that meaning as input.) The "romantic" version is pure noise that adds no information, for humans or machines. Second, why octets specifically instead of numbers (or, more precisely, non-negative integers) more generally? Is there any value in restricting the range of components of a version number to 0-255?
- davidbanham 12y agoI think that is a wonderful idea. It could happily become a de-facto standard with people publishing a 4-octet version in READMEs and simply truncating it in the package.json.
- jashkenas 12y agoWhy, I'm so glad you asked. In short — true compatibility determined by the test suite, which tells you exactly how compatible two pieces of interdependent software are. We can automate this. In long: Compatibility between any two pieces of software — say an app, and its major dependency — is a rich, yet quantifiable thing. It consists of all of the functions you call (or the classes you use) in the dependency, and the way in which you use them. These uses should be covered by tests. If a library with a large surface area of 100 functions releases a new version ... and that version changes 1 of the lesser-used functions to have different behavior for an edge case, then by SemVer's fiat, it's a Breaking Change, and you bump the version number, and 99.89% of the library users that won't see any trouble in their application won't get the "free" upgrade. That's silly. In a sanely written library, general backwards-compatibility is always a priority, and it's entirely possible and likely that a well-written app will be able to upgrade without any problems through dozens of "breaking" major revisions. At that point, the "Semantic" version is just a false flag that would be better off ignored. That's silly. We have robust test suites that tell us exactly what goes wrong, and how, and where. We just need a tool that provisionally upgrades your dependencies (without regard to version) — runs your tests, and tells you what works, and what needs to be updated. If all is well, all is well. The tool can (safely! with assurances!) write the new version in your package.json (or what have you), and you can go merrily on your way. If a test fails, you update your code, or the tool can write into your package.json exactly the version ranges your current code is compatible with. Why would you ever let a third party — no matter how well intentioned — remotely break your app? Versions can go back to being for people, not for robots.
- jrochkind1 12y ago> and that version changes 1 of the lesser-used functions to have different behavior for an edge case, then by SemVer's fiat, it's a Breaking Change IF that function was part of the "public API". (AND the previous behavior was not a bug? You can fix bugs without major version bump in semver) This is the trickiest part of semver in actual practice, in my experience, having a clear definition and shared understanding between producers and consumers of what the 'public API' is. I agree tests is the operationalized way to know if 'something has changed in a backwards compat' way; I've considered somehow tagging certain tests as 'public api' and others as not (or vice versa, public api by default unless tagged private). And then perhaps there's a rule, you can not change any test marked public API unless it's going to be a major version bump (or unless the test itself was buggy I guess? there's always exceptions sadly). And incorporating this info into docs and/or CI somehow. And yeah, actually sticking to semver is not cost-free, for producers or consumers. Everything is a trade off.
- Touche 12y agoThe point of the article is that NPM uses semver. If you disagree with semver you should use a different package manager. > And yet, 1.3.0 "broke" the way that urls are resolved with regards to trailing slashes: https://github.com/iojs/io.js/pull/278 https://github.com/iojs/io.js/pull/278 Can you link to documentation of the old way? The way I understand it is that they fixed a bug. If they broke a documented API I would agree with you, should be a major version bump. Lastly there's a gigantic difference between breaking code because you made a mistake and breaking code because you don't give a shit and romanticize version numbers.
- untog 12y agoCan you link to documentation of the old way? The way I understand it is that they fixed a bug. If they broke a documented API I would agree with you, should be a major version bump. Ironically, this is exactly what has happened with CoffeeScript here - the blog post is conveniently light on details. 1.9.0 seems to have changed some internal variable naming, which no-one should be relying on.
- Touche 12y agoThere's no irony, io.js is trying to follow semver and is doing so correctly, Jeremy happened to follow it in this one case but will happily break people's app on any arbitrary release.
- untog 12y agoJust as long as we're not getting personal, hey? Jeremy did not break anyone's app. He has said, time and time again, that CoffeeScript is not released according to semver. If you choose to implement it without watching your version numbers your app breaking is your responsibility. I'm starting to understand why people are reluctant to open source their projects. Apparently it means you are tech support for absolutely everyone that uses it on their production systems.
- Touche 12y ago
- jeswin 12y agoI don't have a preference on semver. I don't think it completely solves versioning, or whether that can be solved. I just wanted to add a point on "dangerous". > (From your linked article) If an important security fix happens in a version that also contains a breaking change for your app — you still need to adjust your app to get the fix, right? Automatically upgrading to the latest minor revision is also a type of security risk. Take the example of the package manager npm, where most modules (via package.json) don't mention an exact dependency. They tend to allow minor version upgrades, via semver compatibility notation (https://docs.npmjs.com/misc/semver https://docs.npmjs.com/misc/semver). This is dangerous, since at any point, a module, sub-module (or sub-sub-module..) can release a malicious minor update which has full access to the user's data. An attacker breaking into a module author's computer simply has to release a minor version upgrade to infect dependency chains en masse. This even affects servers, since not everyone uses private npm. If the version number is pinned, you can avoid the risk. But then again, users don't get the security fixes you mention above.
- davidbanham 12y agoAnd now we get into a discussion about what constitutes public vs private API. I completely accept that the naked variable thing wasn't intended behaviour of Coffeescript. Nevertheless, it was a thing that worked and was widely enough used for it to be mentioned in the changelog. So, thanks for mentioning it the changelog! It's great that you're aware not only of how your code is intended to be used, but how it is being used in the wild. That's a really good thing and worthy of praise. The bit that annoyed me was that you knew this, but still chose not to bump the major. I read your stance on semver the last time we all did this collective dance. Most of it makes perfect sense. It is a valid argument, and I would be very happy for us, as a community, to work towards something better than semver. That has to happen in a holistic way, though. Our package manager uses semver. Publishing your package on that package manager is an implicit acceptance of that convention. The fact that someone can `npm install coffee-script` leads them to believe that it will at least attempt to follow the rules and conventions of that ecosystem. (Incidentally, I only found out about the recent underscore-semver-round-2 1.8.0 thing _after_ publishing this post. This isn't a guy trying to stir up larger drama. This is just a guy who had to spend his Friday evening fixing a preventable bug in production and it made him grumpy.)