4 ms·
In the "old" days ("old" being .. what, ten years ago?) packages were released as libraries, which bundled large amounts of functionality into a single atomic v
by jmillikin 4y ago
In the "old" days ("old" being .. what, ten years ago?) packages were released as libraries, which bundled large amounts of functionality into a single atomic version. You could depend on OpenSSL for all your crypto code, GLib for argument parsing or atomics or UUIDs, libiconv for character encoding. There was some expectation (usually met) that the developers of these libraries would have some sort of basic testing strategy, and that they would try to maintain API compatibility over long periods of time.
A large program might have less than a dozen external dependencies, and they released every couples months at most, so keeping up to date was easy. And most of the time you didn't even need to update unless someone discovered a security vulnerability, which was not that common despite all the libraries being written in C or C++.
The approach of NPM (etc) is fundamentally different in that it's considered normal for a project to have hundreds or thousands of dependencies. To manage the update cadence, the users of these package repositories try to invent new schemes for version numbers -- or write quirky gif-laden blog posts about how they burn the monthly budget of a small country on testing in CI.
But the core problem is that they've locked themselves into a stupid and unsustainable paradigm. You can't do the sort of software development that involves writing code if you've decided that your job is to haphazardly glue together other people's code, especially when your're willing to depend on packages written by anything and anyone.
--
I honestly think a lot of the problem of over-dependency comes from the new package managers that make it too easy to depend on stuff recursively. If NPM required you to type out `npm add-project-dependency left-pad/1.0.0 --checksum sha256:a1b2c3...` then that would have been a strong forcing function against a huge number of tiny packages, because at some point your fingers get tired.
For example, in my personal projects I use Bazel as a build system, which makes me a bit more aware of dependency hell because each dependency needs to be registered.
There are projects like QEMU that are straightforward to build in Bazel because their dependency tree is bounded, but some of the stuff coming out of JavaScript land is just unavailable to me because I don't have the patience to chase down hundreds of packages to run a "hello world".
I've found I avoid certain parts of the Rust ecosystem because they're JS-ish, but there's other parts that have a more C/C++-ish style and those packages work fine for me. Similarly for Python. Go has largely avoided the issue, though I don't have an intuition as to why (different culture?).
- juped 4y agoA problem with Rust is that the compilation unit is the crate, which pushes developers into splitting something that is one library into multiple crates to get incremental compilation, and it's hard for the user to tell the difference (you can synchronize their version numbers, sure, but the user has to put each crate into their list of dependencies individually).
- pferde 4y agoIt's not even in the "old" days, what you described is still the situation today, for C and C++ languages - as I'm sure you are aware. You have to know about all your dependencies, and curate them all manually. This despite all the misguided "package manager for C projects" attempts that pop up here on HN every now and then.
- BirAdam 4y agoWell, C was made with UNIX in mind. To that end, UNIX/Linux is both the package manager and dev environment for C. Further C package managers are just redundant.