I think Go apps tend to have better dependency hygiene because the language has a better standard library, which results in better culture around dependencies.
I also think it’s frustrating that both cargo and npm totally ignore the decades of prior art from Linux distributions that have figured out good ways to improve dependency management. We’d be in better shape if there was a community curated subset of known-good dependencies that are release-managed together that the broader ecosystem could build on, sort of like Ubuntu having “main” and “universe”.
Rust meanwhile seems to be following some "no standard library" philosophy.
I feel like there's an opportunity out there to become like an amoeba: fund and build a third party Rust standard library, absorb absolutely everyone who is so grateful to have a library, and then get so big absorb Rust itself.
Certainly having a larger stdlib helps Go projects keep their deps down, but I don't think it's the real reason.
I disagree: having a big stdlib that encompasses a huge chunk of common functionality (logging, a plethora of network server/client protocols, etc) means that for basic needs, the question of 3rd party libs never arise, whereas for other language, the question is not if you need a dep, but which one. Making gorilla easier to find won't undo the cultural reluctance of adding a 3rd party dep when using the (very pragmatic, IMO) stdlib server is adequate to the task.
One of the core tenets of early Go was the maxim "a little copying is better than a little dependency".
Probably because of this stance, they didn't even HAVE a dependency-management solution for years
I strongly agree the fewer dependencies the better, on average.
Personally I came from a C background so I tended to use deps more sparingly.
In the end it's a bit of a balancing act—lots of dependencies is a larger opportunity for these kind of supply chain attacks to affect you. Copying stuff into your repo protects you from that, but it also makes it way more likely that you'll miss security fixes, unless you're actively looking for them. Re-implementing what you need is also viable but it slows down the dev process.
Culture has a lot to do with it.
There’s no poking, unless you are into that sort of thing
The big reason is money & time. Maybe less so today if you are happy with an AI generated stdlib, but I don't think it's fair to compare Rust (built by Mozilla, who's primary product is an open source web browser) to Swift/AppKit (built by Apple, 4.6T marketcap at the time of writing).
When Go was released it had an amazing stdlib, but that was because Google was funding it.
Swift was intended from the start to not only replace Objective-C and all of its use cases, but also take on new use cases and bring a number of features from other languages that were newer and had different dominant paradigms.
Certainly having a juggernaut like Apple behind it has been instrumental in its success in achieving those goals. That said, a community-lead project with similar aims could probably achieve those aims as well, given enough time.
I think it's just rare for enthusiast-led projects to set out to do such things. My theory on why things tend to go that way is that the types of people to start programming language projects tend to heavily lean nuts-and-bolts and theory with a purist/idealist sort of mentality that's more concerned ideological purity than practical usability.
So to sum this all up, a community-run practical, multi-purpose, batteries-included language likely needs to at least partially designed and helmed by product engineer types so it doesn't end up anemic and stuck in an ideological rut.
Look at C++'s long in the tooth STL.
You don't want to marry a language to fast aging libraries you have to support for eternity. Better libraries always naturally emerge.
Rust's decision here is fine.
The only thing I'd like to see is the ability to programmatically limit transitive dependency count or depth in Cargo. I'd also like crates to specify whether they limit their own deps and whether they have panick-y behavior or not.
One can very simply....make breaking changes. Yes it will require some work to update but that's already the case when you upgrade library versions.
The dependency hell doesn't help anyone here, the downside is much worse - lots of bloat, overgeneric libraries and awful supplychain security.
> There’s no reason why this can’t be replicated elsewhere. The key is to make the programming language reasonably robust with at least 80% of common non-UI dev needs built in and put the remaining 20% and UI bits into a small family of well-supported, community-embraced, preferably first party libraries.
I wholeheartedly agree. Most standard libraries out there (when I say most I easily mean of 99% languages that I know) have pitifully tiny implementations. They at most provide for string parsing, io, a bare networking layer (that's at best a wrapper around the POSIX syscalls), threading and that's it. If you want to do anything more complex, you either have to roll it yourself or use an assortment of the "blessed libs" for any given language, that may or may not work properly, and may or may not even work well with each other. I got pissed off by this at some point so I decided to go ahead and roll my own standard lib that would actually have everything I need to.. actually develop apps. Now I know most people probably aren't going to be using it (mainly because its functional API isn't what most C++ devs want) but for me it's actually been brilliant.
Huge standard libraries make sense for Java, Go, Apple platform etc. because they are developed by giant enterprises that can manage the overhead. Thinner modular systems are a more natural fit for open source development.
While overhead is a real concern, I think it’s often blown out of proportion. Once a language achieves a certain baseline of stability and isn’t in constant flux and the standard library matures, changes become infrequent and maintenance load is low. The work is heavily front-loaded.
They do not want a big stdlib. The downsides are real (the stdlib cannot make breaking changes), and there are no upsides (except, maybe, for faster compilation, since std comes precompiled).
They want more official crates (e.g. `regex` and `libc` are official crates, maintained by the Rust project). And the Rust project does not oppose to that, it just doesn't have the funding.
There are upsides, your program is smaller, better security because a random kid can't pwn your deps, quality and interoperability. What's not to love?
The std making a breaking change is the language making a breaking change. Most mainstream languages guarantee stability, certainly Rust.
> your program is smaller
How so? It doesn't matter if the code is in std or a crate.
> better security because a random kid can't pwn your deps, quality and interoperability
That's exactly what I said: you don't need bigger std, you just need more official crates.
That's their mistake, right there... When you're upgrading software, you presumably want a better version. You can't have something better without changing it. It's a logical contradiction.
>It doesn't matter if the code is in std or a crate. It very much does because you don't need 95% of the random stuff in the crates. Even for something like rand, you need an xorshift and that's roughly it. 25 lines of code, sorted. You can even write it as a copypaste "dependency" without much fuss in practically any language. That, versus importing a whole rand library with lots of different algorithms, deps on crypto, tests, OS random-based seeding, customisability, etc.
>you just need more official crates
I guess that's one solution but it would probably just be a better idea to split std in two SLAs, one is guaranteed for core stuff i.e. the status quo, one is YMMV.
I can use most of the clunky Python, Java, .NET and if it must be, Go, standard libraries, than hunting down for dependencies with platform tier support and such.
We also have the classic example of PHP with numerous not safe stdlib ways to use mysql.
To me the answer is still to vendor your dependencies and don't be on the bleeding edge of updates unless you're willing to invest the time into validating them.
I think it goes without saying that emulating PHP is rarely a good decision.
What is your critique of their approach? Is it not the case that `go get` is the only one which doesn't even provide a way for the person downloading to run the downloaded code until it is actually executed by the consuming codebase? That seems pretty sound by comparison.
I guess you're saying, "they had to" meaning they should've seen the need and provided it? I'll say this to that (imagined) take; plenty of useful software was made without it, and they got the job done when they knew the absolute most about what a good solution would need. I totally understand being annoyed at the fact that this is the story of every evolution in Go, but I genuinely think they're picking good implementations when they decide on them.
It’s half arsed, brittle and far from user friendly.
> Is it not the case that `go get` is the only one which doesn't even provide a way for the person downloading to run the downloaded code until it is actually executed by the consuming codebase?
If you’ve added the package to your imported then odds are your next step is going to build it. Thus negating any benefit.
I think the real issue is malicious packages entering package ecosystems. Whether your package manage executes on downloads or not is moot because you’ve still got untrusted code sat in your project imports, just waiting to be accidentally executed.
> I guess you're saying, "they had to" meaning they should've seen the need and provided it? I'll say this to that (imagined) take; plenty of useful software was made without it, and they got the job done when they knew the absolute most about what a good solution would need. I totally understand being annoyed at the fact that this is the story of every evolution in Go.
I think you’re being too charitable here. I think Russ Cox just didn’t want a package manager because C doesn’t have one. But ended up relenting after everyone nagged the Go team for years afterwards.
And really what they built was the bare minimum to manage package version pinning and updates. But it has none of the visibility that central package repositories have. So how do you know if a Go package has been compromised when the only source of truth is the compromised origin?
I don't think automatic updating is a good idea at all. It's just the honor-system, and trust is a security flaw.
> If you’ve added the package to your imported then odds are your next step is going to build it. Thus negating any benefit.
I actually think this is the benefit! I don't need to go to a website to see what changed, I can just have a look at the code. The best dependencies have a changelog. Ideally I can look at a diff.
> I think you’re being too charitable here. I think Russ Cox just didn’t want a package manager because C doesn’t have one. But ended up relenting after everyone nagged the Go team for years afterwards.
That's entirely possible.
> So how do you know if a Go package has been compromised when the only source of truth is the compromised origin?
Fair point, and probably worse in this future we're in now that NIST is drowning in CVEs and has turned away from some share of them.
If Odin gets moderately successful someone will probably reinvent it.
It was only when people wanted a common approach to shipping both in browser and "native" that this glitch happened. I believe a standard library and "batteries" would have abated it entirely or resulted in a slightly less-bad situation. I do think Cargo is a slightly less-bad situation in many ways, and that it can be done better.
Batteries also don't help if dependencies don't replace them. Arrayref functionality has been part of Rust std lib for a while now.
https://www.youtube.com/watch?v=GZOuz-SG7-g
Funny how you skipped "I should build my own batteries" and when straight to "increasing and centralizing the duties of your main gratis 'vendor'".
I'm happy to contribute to a larger effort but anything I can build on my own is going to be a thin, flimsy happy meal toy compared to something with the backing of a company or well organized FOSS project.
Also the challenge of building a generic module is much larger than building your own. A generic module needs to have flexibility for many different options and integrations, when you build your own you build just what you need and tightly integrate it with the product
True but I believe overestimated. Usually rather than building what's needed, what gets built is what is thought to be needed (often a substantially smaller subset), and then over time you end up building a markedly poor version of a generic module.