5 ms·
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
by robviren 8mo ago
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.
- ngrilly 8mo agoSame. That’s why Go is such a great tool.
- tasn 8mo agoThese are two sides of the same coin. Go has its quirks because they put things in the standard library so they can't iterate (in breaking manners), while Rust can iterate and improve ideas much faster as it's driven by the ecosystem. Edit: changed "perfect" to "improve", as I meant "perfect" as "betterment" not in terms of absolute perfection.
- incrudible 8mo agoThe cost of "perfecting" an idea here is ruining the broader ecosystem. It is much much better for an API to be kinda crappy (but stable) for historical reasons than dealing with the constant churn and fragmentation caused by, for example, the fifth revision of that URL routing library that everyone uses because everyone uses it. It only gets worse by the orthogonal but comorbid attitude of radically minimizing the scope of dependencies.
- dwattttt 8mo ago> It is much much better for an API to be kinda crappy (but stable) for historical reasons But this does more than just add a maintenance burden. If the API can't be removed, architectural constraints it imposes also can't be removed. e.g. A hypothetical API that guarantees a callback during a specific phase of an operation means that you couldn't change to a new or better algorithm that doesn't have that phase.
- TheDong 8mo agoYes you can, and Go has done exactly that. Realize the "log" api is bad? Make "log/slog". Realize the "rand" api is bad? Make "rand/v2". Realize the "image/draw" api is bad? Make "golang.org/x/image/draw". Realize the "ioutil" package is bad? Move all the functions into "io". Te stdlib already has at least 3 different patterns for duplicating API functionality with minor backwards-incompatible changes, and you can just do that and mark the old things as deprecated, but support it forever. Easy enough.
- dwattttt 8mo ago> mark the old things as deprecated, but support it forever Is that 'supported'? A library that uses a callback that exists in 'log' but not in 'slog'; it'll compile forever, but it'll never work. 'Compiles but doesn't work' does not count as stable in my book. It's honestly worse than removing the API: both break, but one of them is noticed when the break happens.
- TheDong 8mo agoWhich has been working great for go, right. They shipped "log" and "flag" stdlib packages, so everyone uses... well, not those. I think "logrus" and "zap" are probably the most popular, but there's a ton of fragmentation in Go because of the crappy log package, including Go itself now shipping two logging packages in the stdlib ('log/slog'). Rust on the other hand has "log" as a clear winner, and significantly less overall fragmentation there.
- Ferret7446 8mo agoI think you underestimate how many programs use log and flag, if you just focus on the few (bloated) popular projects.
- bobbylarrybobby 8mo agoI think “the fifth revision of that URL routing library that everyone uses” is a much less common case than “crate tried to explore a problem space, five years later a new crate thinks it can improve upon the solution”, which is what Rust’s conservatism really helps prevent. When you bake a particular crate into std, competitor crates now have a lot of inertia to overcome; when they're all third-party, the decision is not “add a crate?” but “replace a crate?” which is more palatable. Letting an API evolve in a third-party crate also provides more accurate data on its utility; you get a lot of eyes on the problem space and can try different (potentially breaking) solutions before landing on consensus. Feedback during a Rust RFC is solicited from a much smaller group of people with less real-world usage.
- skydhash 8mo agoIs there that much to explore in a given problem space. I believe a lot of people will take the good enough, but stable API over the unstable one that is striving for an unknown state of perfection. The customer of a library are programmers, they can patch over stuff for their own use case. A v2 can be released once enough pain points have been identified, but there should be a commitment to support v1 for a while.
- aatd86 8mo agoThere is a moral hazard here. By accepting that APIs are forever, you tend to be more cautious and move toward getting it right the first time. Slower is better... And also faster in the long run, as things compose. Personally, I do believe that there is one best way to do things quite often, but time constraints make people settle. 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 8mo agoThe golang.org/x/ namespace is the other half of the standard library in all but name. That gets iterated often. 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 8mo agoIterating often is not helpful for stable systems over time. 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.
- bryanlarsen 8mo agoPython used to have a great standard library, too. But now it's stuck with a bunch of obsolete packages and the packaging story for Python is awful. 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.
- mixmastamyk 8mo agoLots of removals have already happened and uv took over packaging in Python-land.
- __mharrison__ 8mo agoI just ported (this week) a 20-year-old Python app to uv/polars. (With AI it took two days). App is now 20x faster.
- minimaxir 8mo agoBoth uv and polars are technically Rust, too.
- itishappy 8mo agothat's polars for ya uv should not impact runtime performance at all
- __mharrison__ 8mo agouv just happens to make installation trivial. 20 year old app much less so.
- TheDong 8mo agoI've found Go's standard library to be really unfortunate compared to rust. 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 8mo agoMan, I've been using Go as my daily driver since 2012 and I think I can count the number of breaking changes I've run into on one finger, and that was a critical security vulnerability. I have no doubt there have been others, but I've not had the misfortune of running into them. > 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.
- slopinthebag 8mo agoThose deps have to come from somewhere, right? Unless you're actually rolling your own everything, and with languages that don't have package managers what you end up doing is just adding submodules of various libraries and running their cmake configs, which is at least as insecure as NPM or Crates.io. 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.
- Mond_ 8mo agoThe tradeoff Go made is that certain code just cannot be written in it. Its STD exists because Go is a language built around a "good enough" philosophy, and it gets painful once you leave that path.
- deleted 8mo ago[deleted]
- deleted 8mo ago[deleted]
- ajross 8mo ago> The tradeoff Go made is that certain code just cannot be written in it. Uh... yeah? That's true of basically all platforms, and anyone who says otherwise is selling something. > it gets painful once you leave that path Still less painful than being zero-day'd by a supply chain attack.
- jjav 8mo ago> > The tradeoff Go made is that certain code just cannot be written in it. > Uh... yeah? That's true of basically all platforms, and anyone who says otherwise is selling something. What code can you not write in C? Might be painful for some(many) cases, but there is nothing you can't write in C.
- 8mo ago
- onyx228 8mo agoThe dependency creep keeps on happening in web frameworks where ever you look. 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.
- slopinthebag 8mo ago24 hours? is the haskel compiler written in javascript running in a python js-interpreter written in bash?
- zozbot234 8mo agoRust has trouble supporting higher-kinded types like Functor (even though an equivalent feature is available, namely Generic Associated Types) due to the distinctions it makes between owned and referenced data that have no equivalent in Haskell. Whether these higher abstractions can still be used elegantly despite that complexity is something that should be explored via research, this whole area is not ready for feature development.
- rubyn00bie 8mo agoHonestly this is one of the biggest reasons I stick with Elixir. Between Elixir’s standard library, the BEAM/OTP, and Phoenix (with Ecto)—- I honestly have very few dependencies for web projects. I rarely, at this point, find the need to add anything to new projects except for maybe Mox (mocking library) and Faker (for generating bits of test data). And now that the Jason (JSON) library has been more or less integrated into OTP I don’t even have to pull it in. Elixir dev experience is truly unmatched (IMHO) these days.
- pstuart 8mo agoWith Go it's good to keep in mind the Proverbs, which includes this gem: A little copying is better than a little dependency.
- spartanatreyu 8mo agoFYI: Deno includes: 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).
- Grimburger 8mo agoA Tauri hello world app has about 500(?) deps out of the box, always makes me laugh. I get that cross platform desktop app is a complicated beast but it gives off those creepy npm vibes.