4 ms·
Summary: The author argues that version bounds should be treated as a maximum rather than a minimum, like Go does. e.g., if the latest version of colors is 1.0
by howdydoo 5y ago
Summary:
The author argues that version bounds should be treated as a maximum rather than a minimum, like Go does. e.g., if the latest version of colors is 1.0.3, and you have dependencies that request 1.0.1 and 1.0.2, you would end up with 1.0.2. The end result being, the exact resolved version will have been tested with at least one of your dependencies.
I must admit I like the idea.
- shagie 5y agoThis in part has to do with how versions are specified and the standard way that this is done allows minor and point releases to be trusted. https://stackoverflow.com/a/22345808 https://stackoverflow.com/a/22345808 - and especially the comment. You will find a lot of `^1.2.3` in version specifications which means everything from `1.2.3` up to (but not including) `2.0.0` is allowed. Specifying `1.0.1 - 1.0.3` is allowed too and would meet the desired functionality - but that isn't the culture of JavaScript developers. The version range is allowed in other dependency management systems (e.g. Maven - https://www.mojohaus.org/versions-maven-plugin/examples/resolve-ranges.html https://www.mojohaus.org/versions-maven-plugin/examples/reso... ) but rarely do I see it used - most often its pinned to a specific known good version.
- howdydoo 5y agoLet's say you have two dependencies each requesting colors: colors@1.0.1-1.0.3 colors@1.0.1-1.0.4 With npm, you'll end up with 1.0.3 because it satisfies all constraints. OP wants to end up with 1.0.4 if at least one dependency tested with 1.0.4 (and reject 1.0.5). I don't know of a way to do this with npm today.
- gitgud 5y agoYou might like the [1] "overrides" field in npm v8.3 although I would recommend using it with caution, changing your dependencies dependencies has unknown consequences... even a patch release can break everything... [1] https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides https://docs.npmjs.com/cli/v8/configuring-npm/package-json#o...
- remram 5y agoYou are reading this wrong. The OP is suggesting that if you have two dependencies that are requesting: colors@^1.0.1 colors@^1.0.2 then npm should get you 1.0.2, instead of 1.0.4, because it's the "version as close as possible" to "the dependency version that the package was actually tested with". OP is not suggesting that npm should ignore dependency constraints, just that the version that is picked is the closest to the tested version (among those that satisfy the constraints). If you have a package that explicitly says it won't work with >1.0.3, installing 1.0.4 is silly.
- gknoy 5y ago> the standard way that this is done allows minor and point releases to be trusted. I feel like this event (and previous ones) has taught me that one should NOT trust patch and minor version upgrades to work. Obviously we want them to, but I distinctly recall having "minor" patches that broke existing behavior in the past, and has bitten my team on multiple projects over the last several years. Pinned versions are a giant pain, but having builds suddenly stop working seems worse, because you can't plan ahead for the time to upgrade.
- shagie 5y agoI've come to believe that pinned versions with an active dependency check is the way to go. A lot of the dependency checks/scans are build time rather than an "on going" approach. If nothing else, that is a step in the direction of reproducible builds which are also in the Good Thing category. This is likely going to be another maturing event for NPM and the community where they will need to decide how they want to move forward. The blind trust of a `^1.2.3` version specification is something that will likely be outgrown. I still believe that one of the biggest problems that JavaScript libraries face is the transitive dependency explosion combined with the "always update" build policies and that in turn makes makes the issue of a suddenly untrustworthy developer more likely and more problematic.
- Hizonner 5y agoExcept that a shit-ton of developers will code and test with one version of a dependency, and never, ever, ever update it. If the dependency has a catastrophic security hole, that security hole will be pretty much permanent. And what happens if project A pins projects B and C, which in turn pin DIFFERENT versions of project D? Is there any language or environment out there that can make that work?
- howdydoo 5y agoRead it again. Any one dependency, or the root project, has the power to pull in the latest version. One laggard dependency does not stop that. For your second question, yes, Rust handles that well. If you depend on ">=1.0" and ">=1.1", you end up with a single copy of 1.1. If you depend on "=1.0" and "=1.1", you end up with both copies of the library. Every crate uses the version it requested. You can argue whether that's good or bad, but at least it's principled. There's a lint if you dislike that behavior. https://rust-lang.github.io/rust-clippy/master/#multiple_crate_versions https://rust-lang.github.io/rust-clippy/master/#multiple_cra...
- Hizonner 5y agoOK, so suppose I depend on anarchy, which wants shades >=1.0.1, and chaos, which wants shades >=1.0.2. The author of shades releases 1.0.3 because of a bad security hole in all prior versions. My project will still get 1.0.2, so it will still have the security hole. For that matter, it may ALSO break because anarchy is broken by a change made between shades 1.0.1 and 1.0.2... which is why the maintainer of anarchy hasn't updated their dependency. On the whole, I think I'd prefer a solver that gave me 1.0.3 by default (but maybe would NOT give me 2.0.0 by default, depending on what the version numbers mean in this particular system). But the bottom line is that there is NO solver that can be SURE that what I eventually get will really work. That's an interesting fact about Rust, and I didn't know it. On the whole, it sounds like it at least needs some serious tooling so you can make sure you're not dragging in a bunch of old versions that both bloat your code and open you to abuse. Can I ask for a warning if I'm getting two different versions linked into the same binary? If something depends on "=1.0", and the maintainer issues 1.1 with a flag that says "I really, really don't think think you should be using 1.0 any more", will that throw an error? And what happens if both versions get pulled in, but the package in question uses an external data file whose format changed between 1.0 and 1.1? Edited to change "<=" to ">="...
- rwj 5y agoI agree that this approach is much better for stability. The trade off is that a lot of systems will end up missing their needed security updates. Very few people are consciously balancing their type I and type II errors when considering upgrade strategies.
- remram 5y agoThat means that if I depend on leftpad and leftpad depends on colors, and a new version of colors is released, the maintainer of leftpad has to be pestered about testing it with the new colors and doing a new release with absolutely no code change and only this (semver-compatible) dependency bump, otherwise no one using leftpad will be able to update their version of colors? And the security of this new scheme depends entirely on the leftpad developer correctly assessing the security of the third-party colors package, possibly much bigger than his own?
- Groxx 5y agoThe way Go's versioning works: no, the highest version wins, not the lowest. So anyone can force an upgrade by upgrading their minimum version. This includes your application's go.mod file, i.e. you can force updates of anything. Which has other problems too, particularly where semver is not followed strictly, since it fairly often means that using an update of X might force an incompatible update of Y that you now have to go and fix. Go modules have no way to specify upper bounds to prevent or warn about this.
- remram 5y agoI know, nothing does what OP recommends. And I'm with you that it's not a good idea at all.
- lmm 5y agoJust do it like Maven. You know why no-one talks much about dependency management on the JVM? Because everything works properly so it's all very boring.
- pjmlp 5y agoI love boring technology. :)