3 ms·
> The cause of the difficulty was the large number of crates using types from these libraries in their public API. This has bitten me on the ass so many times.
by hinkley 2y ago
> The cause of the difficulty was the large number of crates using types from these libraries in their public API.
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.
- sethammons 2y ago> 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. 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?
- frizlab 2y agoWouldn’t subtrees fix this instead of a mono-repo? Or even (gasp) submodules?
- dallasg3 2y agoI was looking into Paket for this on .NET. https://github.com/fsprojects/Paket https://github.com/fsprojects/Paket
- osigurdson 2y agoYou mentioned sub modules - you are now on call until someone else mentions them again.
- frizlab 2y agoI’m fine with that :)
- mgaunard 2y ago1. ensure you have continuous integration against both stable and latest versions of everything, with the stable set of all transitive dependencies defined on a per-project basis, and what gets used for releases. 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.
- osigurdson 2y agoDoes monorepo confer that all projects use the same dependencies? Binary dependencies seem orthogonal to how source code is managed.
- adastra22 2y agoUsually, yes. Monorepo means all dependencies are checked into the same repo. Even external dependencies (when source available) are checked in.
- osigurdson 2y agoUsually we are using package managers and just referencing packages. However, even in the hypothetical where I am downloading binaries and checking them in, I still don't see the relationship to the monorepo. I can have a monorepo with 100 folders representing 100 programs, each of these can have completely separate dependencies, languages, etc. 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.
- hinkley 2y agoI’ve done monorepo, separate compilation units before. It has its own set of issues but it cuts down on circular dependencies and makes more sense than having sixty repositories checked out. Those are hell.
- mgaunard 2y agoUsing third-party libraries is usually a bad idea, and must be done so very carefully. If you do, onboard it onto your own build system, and pin it to a version you're going to provide support for and ensure compatibility with. You should never have multiple versions of the same code in objects that end up linked together, that's a recipe for ODR.
- progval 2y agoConcrete example: the Apache Arrow format is designed to allow passing arrays across languages and libraries without conversion; so many public functions/methods (and FFIs) will have Arrow arrays in their signature. 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.
- mgaunard 2y agoUse a single version of the arrow library, and build everything against that one. I don't see where the problem is. 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.
- hinkley 2y agoSecurity patches say no, doesn’t work that way.
- progval 2y agoI can't always do that because dependency A depends dependency B that depends on arrow 52, and dependency C depends on arrow 53. 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.
- do_not_redeem 2y agoMicroservices only solve this because you have to serialize objects on the wire, no? You could accomplish the same within an app or lib by accepting a String and calling `serde_json::from_str` on it, avoiding the problems of microservices. Or more realistically, define your own struct and convert it to/from the dependency type at the interface boundary.
- hinkley 2y agoProcess boundaries tend to increase friction to exposing internal implementation details like this. They don’t fix the problem but they do discourage it.
- deleted 2y ago[deleted]
- alexchamberlain 2y agoIf you have a single deployable(1), I think you need to have a person/team responsible for the whole. They need to be trusted to work on any of the code to make the whole build, without overstepping into micromanaging the whole code base. It's a tough balance. (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.