-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Underscore does not follow SemVer #1684
Comments
To quote jashkenas/backbone#2888 (comment):
The rest of the comment is worth a read too, even if you disagree. |
@akre54 I'm curious what your thoughts are on the fact that others projects like Lo-Dash (Underscore alternative) and ExosJS (Backbone alternative) can follow semver? Since those drop-in replacements can follow semver doesn't that kind of throw a wrench in the excuse pushed by Underscore/Backbone core? |
Couple things. Lo-Dash, for the most part, sticks to the cowpaths paved by Underscore, so it has the advantage of holding off until an Underscore release to push a version bump for feature parity. The differences from Underscore tend to be more in the enhancements category and less in significant breaking changes. Lo-Dash adds much more guard code for bc at the expense of code clutter while Underscore strives for terseness. It's easier to get away with a few lines of extra code when the library is larger to begin with (Lo-Dash clocks in at 8.7k lines vs 1.4k for Underscore.) There's also much more internal mucking that can be done in Lo-Dash since so much of the logic is internal. It's also written disproportionately by one contributor (you), whereas Underscore's changes tend to come from a much more diverse set of contributors, meaning new features can come at any time, and sometimes big feature changes and backward-incompatible changes come at inopportune moments to a release schedule. Anecdotally, I get the feeling Underscore also has the release-schedule disadvantage of being used in many more beginner projects than Lo-Dash (by its very nature, Lo-Dash tends to appeal to devs who need its power). A more advanced dev is going to be more comfortable dealing with the fallout from breaking changes, and may understand their reasoning a bit more. Lastly, as the co-author and lead contributor of Exoskeleton, I'll be the first to tell you we haven't been following semver either. We also have the advantages of Lo-Dash as described above. |
What does that have to do with Underscore's version strategy? Lo-Dash bumps versions following semver which is why it's at v2.x going on v3.x.
What does guard code or being terse have to do with version strategy?
Lo-Dash has inline docs, LOC isn't relevant to versioning.
Can't the same be said for Underscore?
That's why Underscore has maintainers to accept/reject or push off until a future release.
I disagree, Lo-Dash has thousands of dependents and all can't be experts with it.
Because Lo-Dash follows semver devs don't have to deal with fallout until they jump to a major version update. Unlike Underscore, Lo-Dash won't change from under their feet because they used a
Then you should remove that from its marketing. I don't think there's any reason why Underscore couldn't follow semver. |
If you want to be included in npm or bower, it's not up for debate. You must use semver. You're making an implicit promise to follow semver, and if you don't, that breaks people's code without warning, and that's frowned on by pretty much everybody. We're talking about a choice that breaks production code. It's not cool to play a sloppy game with other people's time and money. That means your version numbers get bigger faster. So what? It's a number. That's far better than breaking somebody's production shopping cart. |
+1 for semver |
Personally, I don't think it's "cool" to get personal in a bug report. Either it does or it doesn't follow semantic versioning. Here are the reasons--bang, bang, bang--why it would be an even better library if it did. Here are the reasons--bang, bang--why it's feasible for the maintainers to increment the version number in a manner congruent with semver. After that, it's up to the maintainers. If you disagree with their stance, there are alternative libraries to use.. You can fork the project (as others have done). You can write a blog post getting as personal as you please. But let's try to have civil disagreement. |
I don't understand @raganwald. Who's getting personal? I'm not attacking anybody. I'm pointing out that semver is part of the API contract you enter into when you publish a package to npm or bower. If you break that contract, you break other people's code. That's not cool. npm works really well because we all agree on a few rules that keep our modules working well with each other. If you break those rules, you break other modules that try to work with yours. You break production apps that rely on your code. The question is not "should we use semver?" The question is, "do we want to be good citizens in this ecosystem?" |
The key point is that on a project like Underscore, every change is breaking to someone. If we remove a null guard from For Underscore and Backbone, I don't think it's unreasonable to pin your dependencies. Following semver isn't a requirement to publish to a packager. |
You're jumping to an extreme to justify your position. The reality is it's a balance. There's popular API, edge cases, and documented behavior. It's very possible to go for a stretch of time w/o bumping a major version by simply fixing bugs and adding functionality. What it means is the maintainers have to think and plan. This means you may have to create a roadmap for features or changes that can't be tackled w/o breaking back-compat and that's fine. Underscore has bumped patch releases and introduced major breaking changes. This is something the maintainers can totally control.
There should be a message/warning in the documentation for sure. |
@akre54 Changing undocumented features or undocumented bugs may break code that relies on those, but users rely on undocumented features and bugs at their own peril. Ignoring semver puts every user of your API in peril. People fix bugs in large open source projects that follow semver all the time, but it's really rare to see large version numbers in the npm ecosystem. Why is that? Because all good APIs follow the open/closed principle (open for extension, closed for breaking changes) as closely as they reasonably can, so that users can keep pace with the API, and changes don't break existing code. |
To add to the anecdotes, my code has also been broken by Underscore bumps in the past. We've resorted to committing As for version numbers indicating progress, I don't care. Using version 2.1.3 or 143.3.2 makes no difference to me. Library progress and maturity are not measured in version numbers. I just don't want a phone call on Sunday afternoon because someone updated a dependency that relies on |
👍 Yep. @braddunbar makes a point I haven't got to yet -- ignoring semver makes your package a dangerous, virulent package, because that breaking change could be lingering anywhere. It's definitely an onerous requirement to force users to hunt down breaks in third party code that depends on your broken package. IMO, real library progress and maturity is measured in dependability, and semver goes a long way toward meeting that goal. |
Definitely. I'm happy to add one if that's what we decide. I'm not against a better release system (lord knows it's a pain to wait for months for your one little bugfix to get deployed), but I'm not sure "follow semver" is the one right answer. |
Right now, I don't think it matters if it's the one right answer. It is the community accepted answer. |
I don't think anybody said "follow semver" is the one right answer for a better release system. What we said is that it's the npm API contract, and that breaking that contract does damage. |
@jdalton and @dilvie How would you propose we handle releases? What about accepting features? "Use semver" doesn't really tell us anything. Should we push back features like I think semver just simply doesn't fully apply here. |
Shameless self-promotion: use next-update https://github.com/bahmutov/next-update to test first if the dependencies can be updated without breaking your project. I constantly found breaking changes in different modules despite changed |
Do you think this project is a snowflake? Lo-Dash is basically Underscore++, and following semver is no problem for @jdalton. Accepting new features: Does it break the existing API contract? Yes? - bump major version number. Accepting bug fixes / minor patches: Does it break existing API contract? Yes? - bump major version number. How you choose to schedule official releases is entirely up to you. Just make sure the versioning is semver compatible so you don't break other people's code. |
Agreed with @dilvie, for example 1.3.3...1.4.0 probably should of been a major bump as we dropped support for sparse arrays. Next version should be a major bump as we'll be adding a ton of new sugar via If the documentation of a function has to change its clearly a major change |
I got into a brief discussion about this at JSconf this year. I don't have the time to go into detail, here, but: stop conflating human-facing “versioning,” with computer-facing (or really, build-system-facing) “API compatibility.” just stop. Version: “This thing I like has new features, or something else I should be interested in when I have the time.” There's a new iPhone. There's a new OS X. There's a new Ember. There's a new Revised Report on the Algorithmic Language Scheme. API compatibility: “This thing was updated to fix <other person's> problem, and this may/will break the way exercises that thing.” The iPhone's power-plug was replaced. OS X deprecated resource-forks. Ember deprecated a style of action names. Scheme is now case-sensitive. The latter happens during, or alongside, the former; but the former is in no way necessarily reliant on, or even related to, the latter. They should be tracked, and (if we're really going to freaking specify a versioning system, jesus) specified, separately. (the concept of ‘semantic versioning’ popular in the J.S. community is particularly obtuse and terrible; but again, not something I want to go into in detail on somebody else's Issue comment-thread.) tl;dr: They aren't screwing up your ecosystem by choosing their own path. (Especially when that path is terribly flawed.) I wish more projects would. Go use something else, if you're that bent out of shape over it. |
@ELLIOTTCABLE - agreed about human facing vs computer facing ... As long as the human facing looks nothing like the computer facing so that conflating is less problematic. Maybe call the next human facing release something like "snowflake" instead of n.n.n Totally disagree with the last bit, though. When you pretend to follow an API contract and then break it, stuff breaks. It costs other people real time and real money. With a project as popular as underscore, there's potentially a lot of real damage done. |
Look back to the very first arguments in this thread. "Everything in Underscore is basically surface area", ergo, everything, documented and not, is part of its API contract. Any one change is a change for everyone. Lo-Dash, being "Underscore++" doesn't deal with nearly as many changes in features because it can follow safely behind Underscore in working out major features. Lo-Dash's improvements are mainly under the hood or in adding a few methods, not fundamentally rethinking its features. |
You can accept new API or even some enhancements to existing API. If you add new API or enhancements (that don't break compat) its a Minor version update.
I think
Sure it does. You're starting to creep into release cycle concerns, which is separate from semver, but I'll follow you there. |
@dilvie: going to stay out of the rest of the argument, but throwing this in: really, really like your suggestion of going with the ‘version name’ convention. (= For the human-facing part, I'm a big fan of
… couple that with a pretty name, to make it extra-clear that we're talking about “interestingness”-version, not API compatibility, and you've got a winning combo. +1 for Underscore 42: “Silly Sheltie.” (As for the build-system facing part, I've got some controversial views on automated, generative API-compatibility. Let's take this shit out of the hands of fallible maintainers, please, and attack it with static analysis or dynamic crawling.) |
What does that even mean? Lo-Dash deals with more changes and follows its own versioning separate from Underscore. Lo-Dash has changed so much it has had to offer an Underscore-compat build to continue its support of being a drop-in replacement. We have different features, methods, and different API compat concerns.
That's not the case either. Lo-Dash moves at a faster pace and runs up against back compat more frequently. This is why we're ~v2.x going on ~v3.x. Lo-Dash is Underscore-like. If Lo-Dash can follow semver so can Underscore. I've done it for ~2 years now. Your arguments simply fall flat in the face of reality. I've been down this road before so I can help y'all get there too. |
I'm curious how everyone thinks "breaking change" should be defined. Every new feature change to Underscore is a breaking change for somebody else. Let's take for example all the recent changes to Should we have bumped when we allowed the internal Changing I think we're overdue on a major version bump (a lot has happened in 219 commits). A 2.0 release and a solidification of our version policy would go a long way here. |
Not necessarily.
It's not a bug fix, it's an enhancement. Is it non-breaking?-- It's probably a safe change because it's unlikely the return value of
I'd say that falls under undocumented implementation details. At the time the change didn't allow anything new because Underscore still branched for native methods. This change falls under the larger group of changes in post 1.6.0 so can land in a 2.0.
It can be seen as a bug fix but it's definitely a breaking change. This is one of the things devs run into when they switch to Lo-Dash. Because of how Underscore used to be, using native when available, it would mask sparse array use and devs would only encounter the issue if they tested in older browsers. However with this change devs will be alerted to their sparse array use sooner, in modern browsers, so there's a chance their previously working code will hit a snag.
👍 |
Some of this requires some thought and judgment. It may be true that all changes break somebody's code, but if all participants agree to use the open/closed principle as a guide for what constitutes breaking, it makes everybody's life easier. So, adding any property or method to the API is generally not a breaking change (the API is open for extension, but closed to backwards incompatible changes). Changes to function signatures require more thought.
Was that a documented feature of the API that served some purpose? For example, some functions return undefined when the inputs passed in would not result in sensible output. That doesn't seem to be the case with Avoiding sparse arrays on the other hand has a larger potential to change return values that developers rely on, so clearly, that's a breaking change, and anybody who used sparse arrays cares. Sparse arrays may not survive ES6, but they're not dead yet. |
@akre54 At the very least following semver will help prevent major breaking changes from slipping into patch releases and encourage developers to think about the impact of their changes. That's a win for everyone. |
@jdalton, class act. :) |
It would be extremely useful if Underscore followed Semantic Versioning. It currently does not, as things like breaking
bindAll
and removingunzip
have occurred without major version bumps.This would allow library consumers to upgrade bugfixes and performance improvements and gain additional functions without fear of code breaking.
The text was updated successfully, but these errors were encountered: