Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This piece of advice hits me weird:

> For crates where you don’t need or want new features, bug fixes etc, you could consider pinning their versions.

It seems to me that you should _always_ pin your dependency versions. I'd go so far as to say that build tools shouldn't even have an option to automatically pull the latest - "version" should be a required field for all dependencies (and, ideally, that gets decorated with a hash after the first download).

Yes this means you might miss out on security fixes that you'd otherwise get automatically. But having the code that you run & ship change absent your intention just feels like a bizarre default approach.



The notion that one should always pin their dependency version falls apart when considering that package managers like cargo when considering libraries. Libraries hard pinning dependencies causes a world of trouble.

This is exactly why cargo uses a lock file that does pin your dependencies as described for binary crates, but does not use the same mechanism for libraries. https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-hav...


Wouldn't the library dependency hierarchy have been figured out during development in order to get it to a state that can compile? I'm assuming if you're pinning a dependency you already have something that compiles


Let's say crate B depends on crate A with a pinned dependency, and uses one of its types in a public interface.

Crate C depends on them both. It now can't bring in updates to A until B does, and when B updates that's a breaking change, so it better bump its major version.

Take a look at this trick, for example, for foundational crates updating their major version: https://github.com/dtolnay/semver-trick

Now imagine that being an issue every single patch update.


Yeah I see what you mean, it's not so much about the first time it's deployed but for future updates where you want to update one dependency but another one requires it to stay the way it is


Good point, diamond-pattern dependencies can get hellish. In the past, rather than deal with shadowing etc, I've resorted to choosing versions of my major dependencies that use the same version of their underlying dependency (for example, sync my GRPC lib with other HTTP client libs so they all use the same version of Netty - this is in the Java world).


Quite interesting. That doesn't seems like a complete falling apart but rather a (unintentional?) attempt of best of worlds since once set your dependencies on your binary, they will be pinned until you manually run a cargo update.

Granted that the supply chain attack defense would fall on the hands of the users of the library. Unless the library writer aggressively pins of dependencies on the Cargo.toml (not the default semver action), problematic, but at least Cargo allows multiple versions of dependencies on a program, on Python for instance this is much complicated scenario (but still the smallest of the dependencies problems there).


This behavior as very intentional, patterned after Bundler.


That guidance has changed and will hit stable for 1.74 (5 weeks).

For the new guidance: https://doc.rust-lang.org/nightly/cargo/faq.html#why-have-ca...

See also https://blog.rust-lang.org/2023/08/29/committing-lockfiles.h...


Both answers have major downsides.

If you pin your dependencies, when something you depend on fixes a security bug you don't get the fix unless you notice the new release and realize you need to apply it.

If you do not pin your dependencies, then your code will randomly break because you are depending on something that changed (Hyrums law). You push to CI and now you have build failures to fix unrelated to your change in the best case. In the worst case everything builds and you ship to customers who discover the issue (even if you have a great manual test plan that would have discovered it: if it is the last build before release you probably don't run the full plan)

I don't have a good answer here. I'm in the pin everything camp, and can report it is hard to notice all changes upstream. It was just a few years ago we finally threw away a computer with Windows XP with no service packs - it sat in a closet for years untouched just in case we had to rebuild some old software.


In cargo (Rust's primary build tool), there are two ways to pin dependencies:

- `Cargo.lock`: handled implicitly so long as you check it in which, as of rust 1.74 (next release), `cargo new` will scaffold all projects this way by default.

- `Cargo.toml`: requires using a `=` version requirement. We generally recommend against pinning this way; see https://doc.rust-lang.org/cargo/reference/specifying-depende...


> I'd go so far as to say that build tools shouldn't even have an option to automatically pull the latest - "version" should be a required field for all dependencies

When I'm developing, I frequently grab latest versions. Until i share, I want to keep up to date.


I'd argue that the right model is to consider what's been updated whenever you do a release. Likely not to the level of diffing source (which isn't realistic for most setups), but at least lets you see what's changing.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: