top | item 47078639

(no title)

robviren | 10 days 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.

discuss

order

slopinthebag|10 days ago

Those 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.

ajross|10 days ago

> Those deps have to come from somewhere, right? Unless you're actually rolling your own everything

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

The 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.

GuB-42|10 days ago

It is more of a cultural thing. Package managers encourage lots of dependencies while programmers using language with no package managers will often pride themselves in having as few dependencies as possible. when you consider the complete graph, it has an exponential effect.

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

Technically it's the same. But behaviorally it's not. When pulling in more dependencies is so easy, it's very hard to slow down and ask the question do we need all of this?

Mucking around with cmake adds enough friction that everyone can take a beat for thoughtful decision-making.

pjerem|10 days ago

> Go is a bit unique a it has a really substantial stdlib

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

Python 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.

xnyan|10 days ago

> the packaging story for Python is awful.

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

Lots of removals have already happened and uv took over packaging in Python-land.

__mharrison__|10 days ago

I just ported (this week) a 20-year-old Python app to uv/polars. (With AI it took two days). App is now 20x faster.

SPBS|9 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.

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

These 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.

aatd86|10 days ago

There 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|10 days ago

The 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|10 days ago

Iterating 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.

incrudible|10 days ago

The 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.

onyx228|10 days ago

The 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.

zozbot234|10 days ago

Rust 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.

instig007|9 days ago

> 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.

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

24 hours? is the haskel compiler written in javascript running in a python js-interpreter written in bash?

loglog|10 days ago

php is the only popular language that regularly removes insane legacy cruft (to be fair, they have more insane cruft than almost any other language to begin with).

TheDong|10 days ago

I'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|10 days ago

Man, 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.

ceteia|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.

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

FYI: 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).

rubyn00bie|10 days ago

Honestly 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.

ngrilly|10 days ago

Same. That’s why Go is such a great tool.

Grimburger|10 days ago

A 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.

pstuart|10 days ago

With Go it's good to keep in mind the Proverbs, which includes this gem:

  A little copying is better than a little dependency.

Ygg2|10 days ago

Good luck, if little copying is ICU based localization.