Is this trick relevant outside of rust?
Usually this is great. You avoid dependency hell while only trading off some compiled binary size. Sometimes it fails when a package must have only one version, e.g. because you're passing around data types from that package to/from your dependencies which use the old version, but part of rust/cargo's trick is that types drawn from different versions of the same package are distinct types. So you get a compile-time type check error.
Solution: the widget package maintainer pushes out a final 1.x release which itself depends on widget=2, and is simply a shim that re-exports the API. This semver-violating trickery is basically a stealth upgrade that forces all upstream widget=1 pegged crates onto the new widget=2 release branch.
This trick is generic and relevant outside of rust, at least so far as other package managers user semver-aware dependency management.
Using the trick, the last v1 package is a facade that constructs the old interface using the new package. To provide equivalent functionality, you basically have to do the same thing.
But in the real world there are times when major versions are bumped without breaking changes. E.g. a bunch of crates maintained as part of a single project with a uniform versioning scheme.
A A
/ \ / \
Cv2 B into | B
\ \ \
Cv1 \ Cv1
\ /
Cv2
Suppose some exported symbol, X, didn't change from Cv1 to Cv2. In the former, A gets two copies of X depending on which path it took up the dependency tree. In the latter, there's only one copy since both paths terminate in the same place.In the case of Go I'm not sure if it's important that v1 specifically re-export the v2; I think it would work equally well either way. But it's at least very similar.
This has bitten me on the ass so many times. Exposing third party types means you have to upgrade the library simultaneously across the entire application, even if the language allows you to load different versions of the same library in different parts of the app. And if you’re trying to skirt Conway, having multiple teams sharing a single deployable, you’re gonna have a bad time. Because good luck getting all teams to agree to drop everything and upgrade next sprint.
I’d much rather my coworkers use libraries instead of NIH, but you have to be very careful how you use them. It gives me a little sympathy for microservices, but that’s often just swapping in a devil you don’t know.
You should never have multiple versions of the same code in objects that end up linked together, that's a recipe for ODR.
However, the Rust Arrow library bumps its major version every few months because it changes methods and auxiliary types, without changing the memory layout of arrays. But this means you can't have two dependencies (eg. an ORC parser and a CSV serializer) that depend on different versions of Arrow if you want to pass arrays from one dependency's functions to the other's.
And vendoring like you mention won't help, because the Rust compiler wouldn't recognize both vendored Arrow crates as compatible.
I don't use Rust or third-party build or packaging systems -- I usually recommend that people don't do so either, but I understand that cargo is part of the appeal of Rust.
I'd say just build whatever you need to do, this way you won't be limited by arbitrary restrictions others have decided.
And sure, I can soft-fork dependency B to add support for arrow 53, and dependency A to depend on my soft-fork of dependency B, but it quickly becomes messy. Especially when in parallel I send unrelated patches to A and/or B.
You onboard a version and make sure everything you need can build against it, patching software as needed.
(1) it has to be said I don't have much experience with mono-builds, but having brought together many services ( micro or not) from different teams and backgrounds, I wish for a little more coordination and governance.
this is why I'm not on team monorepo. Let other teams vendor their dependencies and upgrade on their own time. Just don't go trying to release N versions. Measure who is on an old version and work with them to update. But again, this slow team allows the other N-1 teams to adopt the new version and provide value to the org.
for those of you who are pro monorepo and have worked in one with dozens of teams in different orgs who have competing priorities and can't upgrade a dependency in lock-step, how have you solved this?
2. people are expected to fix the latest build whenever they have spare cycles. The incentive is that it is part of the pipeline for code reviews and can only be bypassed by the project owner. This means you'll need to support both stable and latest concurrently (bumping stable is also an option to simplify the requirement).
3. if you added conditional support for old stable/new latest and latest was eventually made stable, you can refactor that code.
Dependency versions matter when they are all part of the same program or library. Then you have the diamond dependency issue and related problems. However, none of this is related maintaining code in a monorepo. One program can be maintain in 10 different repos (impractical but possible) and still have the diamond dependency issue.
As I understand it:
- Anything which is breaking-changed in any way for 0.3.0 (e.g. in the article a type change from i32 to u32) is the exact same code in 0.2.1 as it was in 0.2.0.
- Anything which stays the same for 0.3.0 is re-exported in 0.2.1 (from 0.3.0). The code is replaced with a `pub use ...;`
- Anything which moves around in the submodule hierarchy (but is otherwise unchanged) in 0.3.0 is re-exported in 0.2.1, from where it used to be.
If crate Baz depends on something in Foo 0.2.x which changes in Foo 0.3.0, then when (if!) Baz updates to Foo 0.3.0 it will need to deal with that. But Baz can upgrade to Foo 0.2.1 without concern, and any types unchanged in Foo 0.3.0 will be interoperable.
https://news.ycombinator.com/item?id=24020254 (43 comments)
An idea isn't copyrightable work; only the text explaining it is. Please don't propagate the idea that ideas are copyrightable.
This is the same principle that means that mathematical equations or basic API usage examples are not and cannot be the subject of copyright.