I find the dependency creep for both rust and node unfortunate. Almost anything I add explodes the deps and makes me sweat for maintenance, vulnerabilities, etc. I also feel perpetually behind, which I think is basically frontend default mode. Go does the one thing I wish Rust had more of which is a pretty darn great standard library with total backwards compatibility promises. There are awkward things with Go, but man, not needing to feel paranoid and how much can be built with so little feels good. But I totally understand just getting crap done and taking off the tin foil. Depends on what you prioritize. Solo devs don't have the luxury.
slopinthebag|10 days ago
Go is a bit unique a it has a really substantial stdlib, so you eliminate some of the necessary deps, but it's also trivial to rely on established packages like Tokio etc, vendor them into your codebase, and not have to worry about it in the future.
ajross|10 days ago
The point is someone needs to curate those "deps". It's not about rolling your own, it's about pulling standard stuff from standard places where you have some hope that smart people have given thought to how to audit, test, package, integrate and maintain the "deps".
NPM and Cargo and PyPI all have this disease (to be fair NPM has it much worse) where it's expected that this is all just the job of some magical Original Author and it's not anyone's business to try to decide for middleware what they want to rely on. And that way lies surprising bugs, version hell, and eventually supply chain attacks.
The curation step is a critical piece of infrastructure: thing things like the Linux maintainer hierarchy, C++ Boost, Linux distro package systems, or in its original conception the Apache Foundation (though they've sort of lost the plot in recent years). You can pull from those sources, get lots of great software with attested (!) authorship, and be really quite certain (not 100%, but close) that something in the middle hasn't been sold to Chinese Intelligence.
But the Darwinian soup of Dueling Language Platforms all think they can short circuit that process (because they're in a mad evangelical rush to get more users) and still ship good stuff. They can't.
Mond_|10 days ago
Its STD exists because Go is a language built around a "good enough" philosophy, and it gets painful once you leave that path.
GuB-42|10 days ago
It is also common in languages without package managers to rely on the distro to provide the package, which adds a level of scrutiny.
kcexn|10 days ago
Mucking around with cmake adds enough friction that everyone can take a beat for thoughtful decision-making.
pjerem|10 days ago
It’s not that unique though. I can say that Python and hell, even PHP have pretty complete but also well documented stdlib.
Java is meh tier but C# is also pretty good in this aspect.
It’s totally a choice for Rust not to have a real stdlib and actually I feel like that would maybe make Rust maybe the best language overall.
bryanlarsen|10 days ago
In a decade or so Go the awkward things about Go will have multiplied significantly and it'll have many of the same problems Python currently has.
xnyan|10 days ago
Big caveat that this is just for me personally, but uv has fixed this for me personally. Game changing improvement for Python. Appropriately, uv is written in rust.
mixmastamyk|10 days ago
__mharrison__|10 days ago
SPBS|9 days ago
The stdlib packages are far better designed in Go than in Python. “The standard library is where packages go to die” is literally not a thing in Go, in fact quite the opposite.
tasn|10 days ago
Edit: changed "perfect" to "improve", as I meant "perfect" as "betterment" not in terms of absolute perfection.
aatd86|10 days ago
At least it is my experience building some systems.
Not sure it is always a good calculus to defer the hard thinking to later.
JetSetIlly|10 days ago
For stuff in the standard library proper, the versioning system is working well for it. For example, the json library is now at v2. Code relying on the original json API can still be compiled.
strawhatguy|10 days ago
I like go's library it's got pretty much everything needed out of the box for web server development. Backwards compatibility is important too.
incrudible|10 days ago
onyx228|10 days ago
I was thinking of this quote from the article:
> Take it or leave it, but the web is dynamic by nature. Most of the work is serializing and deserializing data between different systems, be it a database, Redis, external APIs, or template engines. Rust has one of the best (de)serialization libraries in my opinion: serde. And yet, due to the nature of safety in Rust, I’d find myself writing boilerplate code just to avoid calling .unwrap(). I’d get long chain calls of .ok_or followed by .map_err. I defined a dozen of custom error enums, some taking other enums, because you want to be able to handle errors properly, and your functions can’t just return any error.
I was thinking: This is so much easier in Haskell.
Rather than chains of `ok_or()` and `map_err()` you use the functor interface
Rust:
``` call_api("get_people").map_or("John Doe", |v| get_first_name(v)).map_or(0, |v| get_name_frequency(v)) ```
Haskell:
``` get_first_name . get_name_frequency <$> callApi "get_people" ```
It's just infinitely more readable and using the single `<$>` operator spares you an infinite number of `map_or` and `ok_or` and other error handling.
However, having experience in large commercial Haskell projects, I can tell you the web apps also suffer from the dreaded dependency explosion. I know of one person who got fired from a project due to no small fact that building the system he was presented with took > 24 hours when a full build was triggered, and this happened every week. He was on an older system, and the company failed to provide him with something newer, but ultimately it is a failing of the "everything and the kitchen sink" philosophy at play in dependency usage.
I don't have a good answer for this. I think aggressive dependency reduction and tracking transitive dependency lists is one step forward, but it's only a philosophy rather than a system.
Maybe the ridiculous answer is to go back to php.
zozbot234|10 days ago
instig007|9 days ago
Incremental Nix builds can take less than 1 munute to build everything, including the final deployable docker image with a single binary on very large Haskell codebases. That fact the the person was fired for everybody around him systematically failing to admit and resolve a missing piece of supportive infrastructure for the engineering effort of one person tells a lot about the overall level of competence in that team.
> but ultimately it is a failing of the "everything and the kitchen sink" philosophy at play in dependency usage.
Not really, as the kitchen sink only has to build once per its version change, for all future linkage with your software for the entire engineering team doing the builds in parallel.
slopinthebag|10 days ago
loglog|10 days ago
TheDong|10 days ago
When I update the rust compiler, I do so with very little fear. My code will still work. The rust stdlib backwards compatible story has been very solid.
Updating the Go compiler, I also get a new stdlib, and suddenly I get a bunch of TLS version deprecation, implicit http2 upgrades, and all sorts of new runtime errors which break my application (and always at runtime, not compiletime). Bundling a large standard library with the compiler means I can't just update the tls package or just update the image package, I have to take it or leave it with the whole thing. It's annoying.
They've decided the go1 promise means "your code will still compile, but it will silently behave differently, like suddenly 'time1 == time2' will return a different result, or 'http.Server' will use a different protocol", and that's somehow backwards compatible.
I also find the go stdlib to have so many warts now that it's just painful. Don't use "log", use "log/slog", except the rest of the stdlib that takes a logger uses "log.Logger" because it predates "slog", so you have to use it. Don't use the non-context methods (like 'NewRequest' is wrong, use 'NewRequestWithContext', don't use net.Dial, etc), except for all the places context couldn't be bolted on.
Don't use 'image/draw', use 'golang.org/x/image/draw' because they couldn't fix some part of it in a backwards compatible way, so you should use the 'x/' package. Same for syscall vs x/unix. But also, don't use 'golang.org/x/net/http2' because that was folded into 'net/http', so there's not even a general rule of "use the x package if it's there", it's actually "keep up with the status of all the x packages and sometimes use them instead of the stdlib, sometimes use the stdlib instead of them".
Go's stdlib is a way more confusing mess than rust. In rust, the ecosystem has settled on one logging library interface, not like 4 (log, slog, zap, logrus). In rust, updates to the stdlib are actually backwards compatible, not "oh, yeah, sha1 certs are rejected now if you update the compiler for better compile speeds, hope you read the release notes".
throwaway894345|10 days ago
> Don't use "log", use "log/slog", except the rest of the stdlib that takes a logger uses "log.Logger" because it predates "slog", so you have to use it.
What in the standard library takes a logger at all? I don't think I've ever passed a logger into the standard library.
> the ecosystem has settled on one logging library interface, not like 4 (log, slog, zap, logrus)
I've only seen slog since slog was added to the standard library. Pretty sure I've seen logrus or similar in the Kubernetes code, but that predated slog by a wide margin and anyway I don't recall seeing _any_ loggers in library code.
> In rust, the ecosystem has settled on one logging library interface
I mean, in Rust everyone has different advice on which crates to use for error handling and when to use each of them. You definitely don't have _more standards_ in the Rust ecosystem.
ceteia|10 days ago
This is not always true, as seen with rustc 1.80 and the time crate. While it only changed type inference, that still caused some projects like Nix a lot of trouble.
spartanatreyu|10 days ago
1. The web standard APIs themselves 2. It's own standard library inspired by Go's standard library (plus some niceties like TOML minus some things not wanted in a JS/TS standard library since they're already in the web standard APIs) 3. Node's standard library (AKA: built-in modules) to maintain backwards compatibility with node.
Bun has 1 and 3, and sort of has it's own version of 2 (haphazard, not inspired by go, and full of bun-isms which you may like but may not, but standard database drivers is nice).
rubyn00bie|10 days ago
ngrilly|10 days ago
Grimburger|10 days ago
I get that cross platform desktop app is a complicated beast but it gives off those creepy npm vibes.
pstuart|10 days ago
Ygg2|10 days ago