[HN Gopher] Build It Yourself
       ___________________________________________________________________
        
       Build It Yourself
        
       Author : todsacerdoti
       Score  : 228 points
       Date   : 2025-01-24 12:55 UTC (10 hours ago)
        
 (HTM) web link (lucumr.pocoo.org)
 (TXT) w3m dump (lucumr.pocoo.org)
        
       | abound wrote:
       | This was something that surprised me about the Rust ecosystem,
       | coming from Go. Even a mature Go project (e.g. some business'
       | production web backend) may only have 10-20 dependencies
       | _including_ the transitive ones.
       | 
       | As noted in this post, even a small Rust project will likely have
       | many more than that, and it's virtually guaranteed if you're
       | doing async stuff.
       | 
       | No idea how much of it is cultural versus based on the language
       | features, e.g. in Go interfaces are implicitly satisfied, no need
       | to import anything to say you implement it.
        
         | petecorreia wrote:
         | Go's vast standard library helps a lot with keeping dependency
         | numbers down
        
           | lionkor wrote:
           | Exactly this. You want logging in Rust? You will need _at
           | least_ `log` and another logger crate, for example
           | `env_logger`, maybe the `dotenvy` crate to read `.env` files
           | automatically, you already have 3 direct dependencies + all
           | the transitive ones.
           | 
           | In Go: https://pkg.go.dev/log
        
             | LinXitoW wrote:
             | The built-in "logging" in Go is barely more than a fancy
             | Println. For example, where are the levels, like DEBUG and
             | WARN?
        
         | Cyph0n wrote:
         | For Rust and Go in particular, the difference is in the
         | standard library. The Rust stdlib is (intentionally) small.
        
           | sesm wrote:
           | I would expect crates like `stdlib-terminal` and `stdlib-web-
           | api` in that case.
           | 
           | Honestly, something feels off with Rust trying to advertise
           | itself for embedded: no stdlib and encourage stack
           | allocation, but then married to Clang (which doesn't have a
           | good embedded target support) and have panic in the language.
           | 
           | Building a C++ replacement for a browser engine rewrite and
           | building a C replacement for embedded have different and
           | often conflicting design constraints. It seems like Rust is a
           | C++ replacement with extra unnecessary constraints of a C
           | replacement.
        
             | palata wrote:
             | I often wonder about this: obviously Rust is fashionable,
             | and many people push to use it everywhere. But in _a ton_
             | of situations, there are modern memory-safe languages (Go,
             | Swift, Kotlin, Scala, Java, ...) that are better suited.
             | 
             | To me Rust is good when you need the performance (e.g.
             | computer vision) and when you don't want a garbage
             | collector (e.g. embedded). So really, a replacement for
             | C/C++. Even though it takes time because C/C++ have a ton
             | of libraries that may not have been ported to Rust (yet).
             | 
             | Anyway, I guess my point is that Rust should focus on the
             | problem it solves. Sometimes I feel like people try to make
             | it sound like a competitor to those other memory-safe
             | languages and... even though I like Rust as a language,
             | it's much easier to write Go, Swift or Kotlin than Rust
             | (IMHO).
        
           | chris_overseas wrote:
           | Agreed, and the small stdlib is one of the main reasons for
           | this problem. I understand the reasoning why it's small, but
           | I wish more people would acknowledge the (IMHO at least)
           | rather large downside this brings, rather than just painting
           | it as a strictly positive thing. The pain of dealing with a
           | huge tree of dependencies, all of different qualities and
           | moving at different trajectories, is very real. I've spent a
           | large part of the last couple of days fighting exactly this
           | in a Rust codebase, which is hugely frustrating.
        
             | palata wrote:
             | What is the reason to keep it small? Genuinely interested,
             | I actually don't understand.
             | 
             | Embedded systems maybe?
        
               | 7bit wrote:
               | AFAIK: Rust compiles to machine code. Even if the stdlib
               | would be 600 mb, If you have 3 lines of Code your
               | programm would be microscopically small.
        
               | burntsushi wrote:
               | (I've been on libs-api, and libs before that, for 10
               | years now.)
               | 
               | API Stability. When the standard library APIs were
               | initially designed, "the Python standard library is where
               | packages go to die" was very much on our minds. We
               | specifically saw ourselves as enabled to have a small
               | standard library _because_ of tooling like Cargo.
               | 
               | There are no plans for Rust 2.0. So any change we merge
               | into std is, effectively, something we have to live with
               | for approximately forever. (With some pedantic exceptions
               | over edition boundaries that don't change my overall
               | point.)
               | 
               | Nuance is nearly dead on the Internet, but I'll say that
               | I think designing robust and lasting APIs is a lot harder
               | in Rust than it is in Go. Rust has a lot more
               | expressiveness (which I do not cite as an unmitigated
               | good), and the culture is more heavily focused on zero-
               | overhead abstractions (which I similarly do not cite as
               | an unmitigated good). That means the "right" API can be
               | very difficult to find without evolution via breaking
               | changes. But the standard library cannot, generally
               | speaking, make breaking changes. Crates can.
               | 
               | I would suggest not reading the OP as a black-and-white
               | position. But rather, a plea to change how we balance the
               | pros and cons of dependencies in the Rust ecosystem.
        
               | WhyNotHugo wrote:
               | I can understand not wanting to add SMTP or CGI to the
               | stdlib. But a lot of common POSIX functionality (which is
               | sometimes a single syscall away) is missing too.
        
               | burntsushi wrote:
               | A lot of common POSIX functionality is not missing
               | though. I was able to write ripgrep, for example, by
               | almost entirely sticking to the standard library. (I
               | think the only place I reach out to `libc` directly is to
               | get the hostname of the current system for rendering
               | hyperlinks in your terminal.)
               | 
               | We also came at the standard library with a cross
               | platform mentality that included non-POSIX platforms like
               | Windows. You want to be careful not to design APIs that
               | are too specific to POSIX. So it falls under the same
               | reasoning I explained above: everything that goes into
               | std is treated as if it will be there forever. So when we
               | add things to std, we absolutely consider whether the
               | risk of us getting the API wrong is outweighed by the
               | benefit of the API being in std in the first place. And
               | we absolutely factor "the ease of using crates via Cargo"
               | into this calculus.
        
               | WhyNotHugo wrote:
               | I peeked at the code for gethostname in ripgrep, and it's
               | nice and straightforward.
               | 
               | Much like op said here; we have a culture of "don't write
               | unsafe code under any circumstance", and we then pull in
               | a dependency tree for a single function that's relatively
               | safe to contain. It solves the problem quickly, but at a
               | higher price.
               | 
               | BTW, thanks for ripgrep. I don't actually use it, but
               | I've read through different portions of the code over
               | recent months and it's some very clean and easy to
               | understand code. Definitely a good influence.
        
               | ziml77 wrote:
               | I don't think you should treat unsafe code as that level
               | of toxic. It's necessary when interfacing with with
               | system APIs. The important part is that you try to have
               | safe wrappers around the unsafe calls and that you
               | document why the way you're using them is safe.
        
               | palata wrote:
               | I've been using ripgrep for years! Thanks a lot for that!
        
               | afiori wrote:
               | The three main reasons I see being given are:
               | 
               | - backward compatbility: a big std lib increases the risk
               | of incompatible changes and the cost of long term support
               | 
               | - pushing developers to be mindful of minimal systems: a
               | sort of unrelated example is how a lot of node library
               | use the 'fs' module just because it is there creating a
               | huge pain point for browser bundling. If the stdlib did
               | not have a fs module this would happen a lot less
               | 
               | - a desire to let the community work it out and decide
               | the best API/implementations before blessing a specific
               | library as Standard.
               | 
               | In my opinion a dynamic set of curated library with
               | significantly shorted backward compatibility guarantees
               | is the best of both worlds.
        
               | SkiFire13 wrote:
               | Other reasons also include:
               | 
               | - less burden on the stdlib maintainers (which are
               | already overworked!)
               | 
               | - faster iteration on those libraries, since you don't
               | need to wait a new release of the compiler to get updates
               | for those libraries (which would take at least 12-16
               | weeks depending on when the PR is merged)
        
               | michaelt wrote:
               | One risk with a bigger standard library is that you'll do
               | an imperfect job of it, then you'll be stuck maintaining
               | it forever for compatibility reasons.
               | 
               | For example, Java developers can choose to represent time
               | with Unix milliseconds, java.util.Date,
               | java.util.Calendar, Joda-Time or java.time.Instant
        
               | layer8 wrote:
               | It's really just Date and Instant. Joda-Time isn't part
               | of the standard library. And if you're listing Calendar,
               | you might as well also list ZonedDateTime,
               | OffsetDateTime, and LocalDateTime, not to mention stuff
               | like java.sql.Date.
               | 
               | In reality, there's just one old API and one new API,
               | similar to the old collection classes (HashTable, Vector,
               | etc.) and the newer JCF ones.
        
               | saghm wrote:
               | In addition to the points burntsushi gave in the sibling
               | comment, I'd also add that keeping the standard library
               | small and putting other well-scoped stuff like tegex,
               | rand, etc. in dependencies also can reduce the burden of
               | releases a lot. If some a bug gets found in a library
               | that's not std, a new release can get pushed out pretty
               | quickly. If a bug gets found in std, an entire new
               | toolchain version needs to be published. That's not to
               | say that this wouldn't be done for critical bugs, but
               | when Rust already has releases on a six-week cadence,
               | it's not crazy to try to reduce the need for additional
               | releases on top of that.
               | 
               | This probably isn't as important as the stability
               | concerns, but I think it still helps tilt the argument in
               | favor of a small std at least a little.
        
           | chikere232 wrote:
           | It might be a bad choice on rust's part.
           | 
           | IMO they should over time fold whatever ends up being the de-
           | facto choice for things into the standard library. Otherwise
           | this will forever be a barrier to entry, and a constant churn
           | as ever new fashionable libraries to do the same basic thing
           | pops up.
           | 
           | You don't need a dozen regex libraries, you just need one
           | that's stable, widely used and likely to remain so.
        
             | palata wrote:
             | Agreed.
             | 
             | > and a constant churn as ever new fashionable libraries
             | 
             | Isn't that the situation in Javascript? I don't work in
             | Javascript but to me it feels like people migrate to a new
             | cool framework every 2 months.
        
               | LamaOfRuin wrote:
               | Less so than it once was, but more so than other
               | languages/ecosystems.
               | 
               | To be fair though, I'd argue the environment Javascript
               | lives in _also_ changes faster than any other.
        
             | burntsushi wrote:
             | > You don't need a dozen regex libraries, you just need one
             | that's stable, widely used and likely to remain so.
             | 
             | That is the case today. Virtually everyone uses `regex`.
             | 
             | There are others, like `fancy-regex`. But those would still
             | exist even if `regex` was in std. But then actually it
             | would suck, because then `fancy-regex` can't share
             | dependencies with `regex`, which it does today. And because
             | of that, you get a much smoother migration experience where
             | you know that if your regexes are valid with `regex`,
             | they'll work the same way in `fancy-regex`.
             | 
             | A better example might be datetime handling, of which there
             | are now 3 general purpose libraries one can reasonably
             | choose. But it would have been an unmitigated disaster if
             | we (I am on libs-api) had just added the first datetime
             | library to std that arose in the ecosystem.
        
         | jitl wrote:
         | One big reason is because Go has a very nice complete standard
         | library, and Rust really does not.
         | 
         | Things you can find in go's built in to the language or in
         | standard libraries that need a dependency in Rust:
         | 
         | - green threads
         | 
         | - channels
         | 
         | - regular expressions
         | 
         | - http client
         | 
         | - http server
         | 
         | - time
         | 
         | - command line flags
         | 
         | - a logger
         | 
         | - read and write animated GIFs
         | 
         | I don't love the Go language, but it's the leader for tooling
         | and standard library, definitely the best I've used.
        
           | drrotmos wrote:
           | Which may or may not be fine in a Go binary that runs on a
           | modern desktop CPU, but what if your code is supposed to run
           | on say an ESP32-C3 with a whopping 160 MHz RISC-V core, 400
           | KB of RAM and maybe 2 MB of XIP flash storage?
           | 
           | You could of course argue that that's why no-std exists in
           | Rust, or that your compiler might optimize out the animated
           | GIF routines, but personally, I'd argue that in this context,
           | it is bloat, that - while it could occasionally be useful -
           | it could just as easily be a third party library.
        
             | jitl wrote:
             | It's the same as in C, Rust, or any other programming
             | language I've ever used. If you don't use a library, it
             | doesn't end up linked in your executable. Don't want to
             | animate GIFs on your microcontroller, then you don't write
             | `import "image/gif"` in your source file.
             | 
             | For a microcontroller sized runtime, there's
             | https://tinygo.org/
             | 
             | I think the lack of strong standard library actually leads
             | to more bloat in your program in the long run. Bloat is
             | needing to deal with an ecosystem that has 4 competing
             | packages for time, ending up with all 4 installed because
             | other libraries you need didn't agree, and then you need
             | ancillary compatibility packages for converting between the
             | different time packages.
        
               | IshKebab wrote:
               | > It's the same as in C, Rust, or any other programming
               | language I've ever used. If you don't use a library, it
               | doesn't end up linked in your executable.
               | 
               | I don't think that's true. If the standard library is
               | pre-compiled, and it doesn't use `-ffunction-sections`
               | etc. then I'm pretty sure you'll just get the whole
               | thing.
               | 
               | There is experimental support for building Rust's
               | standard library from source, but by default it is pre-
               | compiled.
        
               | XorNot wrote:
               | It's hardly the case that a good reason to not have a
               | more complete standard library on the basis of having to
               | do a tiny bit more work in a more special case to get
               | binary sizes down.
        
               | IshKebab wrote:
               | No I totally agree. IMO Rust should have a more complete
               | standard library.
        
             | chikere232 wrote:
             | Does anyone use the full standard library for embedded
             | targets? I've not seen it done in C, java has a special
             | embedded edition, python has micro-python, rust seems to
             | usually use no-std, but I might be wrong there.
             | 
             | It seems like a bad reason to constrain the regular
             | standard library
        
               | IshKebab wrote:
               | I have in the past, but most people don't.
               | 
               | E.g. for esp32 see https://docs.esp-
               | rs.org/book/overview/using-the-standard-lib...
        
           | 7bit wrote:
           | I hate that. I don't want dependencies for serialization or
           | logging. But you do and now you have to choose which of the
           | dozen logging crates you need.
           | 
           | As a beginner this is horrible, because everybody knows
           | serde, but I have to learn that serde is the defacto, and
           | that is not easy because when coming from other languages, it
           | sounds like the second best choice. And that is with most
           | rust crates.
        
             | burntsushi wrote:
             | This is why things like https://blessed.rs exist. Although
             | since they're unofficial, their discoverability is also
             | likely a problem.
        
       | Joker_vD wrote:
       | > it figures out your terminal dimensions. The underlying APIs it
       | uses have effectively been stable since the earliest days of
       | computing terminals--what, 50 years or so?
       | 
       | No, they haven't been stable, not really. The TIOCGWINSZ ioctl
       | has never been standardized to my knowledge, and it has many
       | different names on different Unixes and BSDs. The tcgetwinsize()
       | function only got in POSIX in 2024, and this whole thing has
       | really sad history, honestly [0], and that's before we even get
       | to the Windows side of things.
       | 
       | [0] https://news.ycombinator.com/item?id=42039401
        
         | the_mitsuhiko wrote:
         | It's not standardized but those calls do not change. The
         | windows calls in particular are guaranteed ABI stable since
         | they are compiled into a lot of binaries. There are definitely
         | issues with ioctl but the changes landing in terminal-size or
         | any of the dependencies that caused all these releases, are
         | entirely unrelated to ioctl/TIOCGWINSZ constants/winsize
         | struct. That code hasn't changed.
        
         | titzer wrote:
         | Terminals are a good example of something that seems really
         | simple but is a major PITA because of too many different
         | vendors in the early days, and no industry standard emerged.
         | What is the closest thing? VT100? VT102? I mostly write raw to
         | those, but stuff like terminal size and various other features
         | like raw (non-cooked) mode are crappy and require ioctl's and
         | such. Frankly, it sucks.
         | 
         | ...but the libraries suck even more! If you don't want to link
         | against ncurses then may God have mercy on your soul.
        
           | Joker_vD wrote:
           | Previous summer I've toyed with trying to write an "async
           | prompt" a-la Erlang's shell with output scrolling and line-
           | editing (see e.g. [0] for example of what I am talking
           | about), but it is so bloody difficult to do correctly,
           | especially when the input spans several lines _and_ there are
           | some full-width characters on the screen, that I 've
           | abandoned it.
           | 
           | [0] https://asciinema.org/a/s2vmkOfj6XtJkQDzeM6g2RbPZ
        
         | horsawlarway wrote:
         | This was vaguely my take away from the article: It's not that
         | his replacements are simpler because they're better or made by
         | him. They're simpler because they're only handling his use-
         | cases.
         | 
         | Sometimes - that's fine.
         | 
         | Sometimes - that's making his software worse for folks who have
         | different use-cases, or are running on systems he doesn't
         | understand or use himself.
         | 
         | The real value of a library, even with all those dependencies
         | (and to be clear, I disagree that 3 or 4 dependencies for a
         | library that runs across windows/linux is "all that many", esp
         | when his platform specific implementation still uses at least
         | 1), is that it turns out even relatively simple problems have a
         | _wealth_ of complexity to them. The person who 's job it is to
         | write that library is going to be more experienced in the
         | subject domain than you (at least in the good cases) and they
         | can deal with it. Most importantly - they can deal with your
         | unknown, unknowns. The places you don't even have the
         | experience to know you're missing information.
        
           | jvanderbot wrote:
           | 100%. If OP is willing to maintain a rust crate that takes in
           | no dependencies and can determine terminal size on any
           | platform I choose to build for, then I will gladly use your
           | crate.
           | 
           | OTOH, if minimizing dependencies is important for a very
           | specific project, then the extra work of implementing the
           | functionality falls on that project. It will be simpler
           | because it must only support one project. It may not receive
           | critical compatibility updates or security updates also.
           | 
           | It does not fall on the community to go and remove
           | dependencies from all their battle tested crates that are in
           | common use. I think anyone and everyone would choose a crate
           | with fewer over more dependencies. So, go make them?
        
             | the_mitsuhiko wrote:
             | > If OP is willing to maintain a rust crate that takes in
             | no dependencies and can determine terminal size on any
             | platform I choose to build for, then I will gladly use your
             | crate.
             | 
             | I already mentioned this on twitter but not a lot of people
             | work this way. I don't have to point you farther than my
             | sha1-smol crate. It was originally published under the sha1
             | name and was the one that the entire ecosystem used. As
             | rust-crypto became more popular there were demands that the
             | name was used for rust-crypto instead.
             | 
             | I have given up the name, moved the crate to sha1-smol. It
             | has decent downloads, but it only has 40 dependents vs.
             | >600 for sha1. Data would indicate that people don't really
             | care all that much about it.
             | 
             | (Or the sha1 crate is that much better than sha1-smol, but
             | I'm not sure if people actually end up noticing the minor
             | performance improvements in practice)
        
               | jvanderbot wrote:
               | Ha! Hi, I think we're having parallel conversations on
               | there as well. Well, good to make a second loop closure.
               | I won't copy my reply here.
        
               | liontwist wrote:
               | > but it only has 40 dependents
               | 
               | Isn't sha1 a several hundred line function? What's going
               | on?
        
               | the_mitsuhiko wrote:
               | In case I was unclear it has 0 dependencies, but 40
               | crates in the ecosystem depend on it.
        
               | liontwist wrote:
               | My mistake.
        
               | gpm wrote:
               | The rust-crypto sha1 crate has four direct dependencies
               | 
               | cfg-if - a tiny library making it easier to use different
               | implementations on different platforms. Maintained by the
               | official rust-lang libs team. Also used by the rust std
               | library. No recursive dependencies.
               | 
               | cpufeatures - a tiny library for detecting CPU features
               | maintained by the rust-crypto people, with a recursive
               | dependency only on libc (which is maintained by rust-lang
               | and used by the standard library).
               | 
               | digest - a library providing traits abstracting over
               | different hash functions, maintained by the rust-crypto-
               | people. In turn digest depends blockbuffer (some code to
               | minimize boundchecks) and cryptocommon (more traits for
               | abstracting), both maintained by the rust-crypto people.
               | Both in turn depend on
               | 
               | - typenum, a third party library for compile time math,
               | no dependencies.
               | 
               | - generic-array, a third library for fixed length arrays
               | with lengths computed by typenum, typenum is its only
               | dependency.
               | 
               | - version_check, a third party library for checking what
               | features the rustc being used supports (only block-buffer
               | depends on this one).
               | 
               | sha1-asm - A library with a faster assembly
               | implementation of sha1, maintained by the rust-crypto
               | people. Dependent only on cc (c compiler support),
               | maintained by rust-lang, used in building the rust
               | compiler. cc is itself in turn dependent only on
               | 
               | - shlex, a third party library for splitting things the
               | same way a shell does. So this tree ends in an actual
               | third party dependency, but one you're already indirectly
               | dependent on by simply using the rust compiler at all.
               | 
               | Oh, and in the next release
               | 
               | sha1-asm is being removed
               | 
               | The crypto common dependencies are being replaced with
               | hybrid-array, which is a replacement for generic-array
               | maintained by the rust-crypto people, and is only
               | dependent on typenum.
               | 
               | The version_check dependency is being dropped.
               | 
               | ---
               | 
               | So what's going on is
               | 
               | 1. This is a faster implementation of sha1, using all the
               | tricks to have different implementations on different
               | platforms. This resulted in 2 third party dependencies,
               | down to 1 in the next release.
               | 
               | 2. This is fitting into a trait ecosystem, and is using
               | tricks to abstract over them without degrading
               | performance. This resulted in 2 third party dependencies,
               | down to 1 in the next release.
               | 
               | 3. The count of non-third party dependencies is inflated
               | because rust-crypto has split up its code into multiple
               | crates, and the rust-lang team has split its code up into
               | multiple crates.
               | 
               | 4. It's not 40, it's 9.
               | 
               | Is it worth the extra code? I guess that depends on how
               | many times you are hashing things and how much you care
               | about the performance and environmental impact of extra
               | code. Or if you're doing something where you want to be
               | generic over hash functions.
        
               | Izkata wrote:
               | > 4. It's not 40, it's 9.
               | 
               | Just like a bunch of others, you understood their comment
               | backwards. Dependents, not dependencies. 40 other things
               | rely on it.
        
               | gpm wrote:
               | Uh, no, I understand the comment I was replying to
               | forwards.
               | 
               | I simply decided not to point out the source of their
               | misunderstanding since it had already been pointed out by
               | the time I replied, and this comment is already way too
               | long.
        
               | andyferris wrote:
               | Not trying to be perverse - but why does sha1-smol need
               | any dependencies, let alone 40? Isn't it a single public
               | pure function from a slice of bytes to a u128?
               | (Implemented with some temporary state and a handful of
               | private functions.)
               | 
               | (I am likely being completely naive, but I am well
               | satisfied by Julia's stdlib function for this, so
               | wondering what makes Rust different since I've been doing
               | more and more rust lately and am trying to understand
               | what the difference might be).
        
               | the_mitsuhiko wrote:
               | > Not trying to be perverse - but why does sha1-smol need
               | any dependencies, let alone 40?
               | 
               | It has zero dependencies, but only 40 crates on the eco
               | system depend on it. Compared to sha1 which has 10
               | dependencies, but > 660 crates depend on it.
        
               | WhyNotHugo wrote:
               | Do you still stand by your decision to give over the
               | `sha1` name?
        
               | the_mitsuhiko wrote:
               | I don't care that much about the name. It was already
               | clear that even ignoring the name, that the rust-crypto
               | ecosystem became the mainstream choice.
        
           | liontwist wrote:
           | > They're simpler because they're only handling his use-
           | cases.
           | 
           | This is a major part of the thesis of no dependencies.
           | General code is bad code. It's slow, branchy, complex, filled
           | with mutexes, nan checks, etc. Read "the old new thing", to
           | see the extreme
           | 
           | When you have a concrete goal you can apply assumptions that
           | simplify the problem space.
           | 
           | A good example of this was Casey's work on a fast terminal.
           | At first all the naysaying was "production terminals are
           | really hard because you have to handle fonts and
           | internationalization, accessibility, etc". Indeed those
           | problems suck, but he used a general windows API to render a
           | concrete representation of the char set on demand, and the
           | the rest was simple.
        
             | horsawlarway wrote:
             | > General code is bad code.
             | 
             | For whom?
             | 
             | I think most times, as a user of software, I almost always
             | prefer to have something that solves my problem, even if
             | it's got some rough edges or warts. That's what general
             | code is - stuff that solves a problem for lots of people.
             | 
             | Would I prefer a tool that solves exactly my problem in the
             | best way possible? Yeah, sure. Do I want to pay what that
             | costs in money, time or attention? Usually no. The general
             | purpose tool is plenty good enough to solve the problem now
             | and let me move on.
             | 
             | The value I get from solving the problem isn't really tied
             | to how optimally I solve the problem. If I can buy a single
             | hammer that drives all the nails I need today - that's a
             | _BETTER_ solution for me than spending 10 hours speccing
             | out the ideal hammer for each nail and each hand that might
             | hold it, much less paying for them all.
             | 
             | I'll have already finished if I just pick the general
             | purpose hammer, getting my job done and providing value.
             | 
             | ---
             | 
             | So to your terminal example - I think you're genuinely
             | arguing for more general code here.
             | 
             | There's performance in making a terminal run at 6k fps.
             | It's an art. It's clearly a skill and I can respect it.
             | Sounds like it's an edge case that dude wants, so I'm in
             | favor of trying to make the terminal faster (and more
             | general).
             | 
             | But... I also don't give a flying fuck for anything I do.
             | Printing 1gb of text to the terminal is useless to me from
             | a value perspective (it's nearly 1000 full length novels of
             | text, I can't read that much in a year if it was all I did,
             | so going from 5 minutes to 5 seconds is almost meaningless
             | to me).
             | 
             | The sum total of the value I see from that change is "maybe
             | once or twice a year when I cat a long file by mistake, I
             | don't have to hit ctrl-c".
             | 
             | I also genuinely fail to understand how this guy gets
             | meaningful value from printing 1gb of text to a terminal
             | that quickly either... even the fastest of speed readers
             | are still going to be SO MANY orders of magnitude slower to
             | process that, and anything else he might want to do with
             | that text is already plenty fast - copying it to a new
             | file? already fast. Searching it? fast. Deleting it? fast.
             | Editing it? fast.
             | 
             | So... I won't make any comment on why this case is slow or
             | the discussion around it (I haven't read it, it sounds like
             | it could be faster, and they made a lot of excuses not to
             | solve his specific edge case). All I'll say is your
             | argument sure sounds like adding an edge case that nearly
             | no one has, there-by making the terminal more general.
             | 
             | Any terminal I wrote for myself _sure_ as fuck wouldn 't be
             | as fast as that because I don't have the rendering
             | experience he has, and my use case doesn't need it at all.
        
               | liontwist wrote:
               | > For whom?
               | 
               | For users and programmers. Slower to use. Harder to read
               | and maintain. More code to do the same tasks.
               | 
               | > I almost always prefer to have something that solves my
               | problem
               | 
               | I didn't say anything about losing features. I don't read
               | Arabic. I'm glad the OS supports it. But it would be bad
               | if Arabic complexity had to leak into every line of code.
               | Limit the complexity scope. Casey's terminal supports
               | Arabic by following this principle.
               | 
               | > The value I get from solving the problem isn't really
               | tied to how optimally I solve the problem.
               | 
               | Yes it is. There are ok products and there are great
               | products.
               | 
               | > text still uses general solution
               | 
               | Operating systems have to solve general problems which is
               | why they are expensive and brittle. Every program is not
               | an operating system.
               | 
               | > There's performance in making a terminal run at 6k fps.
               | It's an art.
               | 
               | I think you are missing context about the issue that led
               | to this. And yes, as soon as there are no spinning wheels
               | while doing normal tasks, then we can stop complaining
               | about performance. But that's not the situation.
               | 
               | > and my use case doesn't need it at all.
               | 
               | Would the world be better or worse if your operating
               | system respected your time more?
        
         | mrweasel wrote:
         | In this case the terminal-size crate just calls Rustix
         | tcgetwinsize, which in turn just calls the libc tcgetwinsize.
         | So I suppose you could save yourself a whole bunch of
         | dependencies by just doing the same yourself. The only cost is
         | Windows support.
         | 
         | If this particular API has been stable, or at least reasonably
         | defined for 50 or 25 years is a detail, because the dependency
         | doesn't even pretend to deal with that and the function is
         | unlikely to change or be removed in the near future.
        
           | Joker_vD wrote:
           | > If this particular API has been stable
           | 
           | Well, it _hasn 't_. The tcgetwinsize() was proposed (under
           | this name) in 2017 and was standardized only in 2024. So it's
           | less than a 10 year old API, which is missing from lots of
           | libc implementations, see e.g. [0]. Before its appearance,
           | you had to mess with doing ioctl's and hoping your libc has
           | exposed the TIOCGWINSZ constant (which glibc by default
           | didn't).
           | 
           | [0] https://www.gnu.org/software/gnulib/manual/html_node/tcge
           | twi...
        
             | mrweasel wrote:
             | I had to check the Rustix implementation again, because
             | that would indicate that that terminal-size wouldn't work
             | on a number of operating systems. However Rustix also uses
             | TIOCGWINSZ in it's tcgetwinsize implementation.
        
       | cpursley wrote:
       | > It's 2025 and it's faster for me to have ChatGPT or Cursor whip
       | up a dependency free implementation of these common functions
       | 
       | I sort of stumbled upon this myself and am coming around to this
       | viewpoint. Especially after dependency hell of a big react app.
       | 
       | And there's also the saas/3rd party services dependencies to
       | consider. Many of them are common patterns and already solved
       | problems that LLMs can clone quickly.
        
         | macNchz wrote:
         | I've definitely become much more likely to start with small
         | internal utility functions implemented by AI before adding a
         | library than I would have been in the past--it's quite
         | effective for contained problems, I can have the AI write much
         | more complete/robust implementations than I would myself, and
         | if I do eventually decide to add a library I have a natural
         | encapsulation: I can change the implementation of my own
         | functions to use the library without necessarily having to
         | touch everywhere it's being used. Makes it easy to test a
         | couple of different libraries as well, when the time comes.
        
       | mberning wrote:
       | I agree. Here is a similar post from another amazing developer.
       | 
       | https://www.mikeperham.com/2016/02/09/kill-your-dependencies...
        
       | bluGill wrote:
       | Worse, sometimes the upstream is complex enough that you don't
       | want to do it yourself - then the upstream quits maintaining
       | their project. I have in my company some open source projects
       | that we still use that haven't been touched upstream since 2012,
       | but either there is no replacement or the replacement is so
       | different it isn't worth the effort to upgrade. Fortunately none
       | of these are projects where I worry about security issues, I'm
       | just annoyed by the lack of support, but if they faced the
       | network I'd be concerned (and we do have security people who
       | would force a change)
        
         | adrianN wrote:
         | Software that hasn't been touched in ten years and still does
         | the job is about as ideal as a dependency can be.
        
           | palata wrote:
           | I tend to agree, but it may have downsides to: it may do the
           | job _and_ have serious security issues. If you don 't know
           | what it does, no reason to know about the security issues.
        
           | qup wrote:
           | Maybe it's even actively maintained!
        
           | WhyNotHugo wrote:
           | In theory yes.
           | 
           | Although a ten year old dependency is written in Python, it's
           | likely not going to work any more due to changes in the build
           | system, stdlib, etc.
        
           | bluGill wrote:
           | But does it? If the software is a spell checker for a
           | language I don't know I will have no idea if it is any good.
        
             | adrianN wrote:
             | The same can be true for the dependency that releases
             | weekly updates.
        
               | bluGill wrote:
               | But the dependency will also get better of time. (One
               | hopes)
        
         | xnorswap wrote:
         | Or they bait-and-switch freedom.
         | 
         | So they start off with an open source Free solution, and then
         | later switch to a paid for model, and abandon the Free version.
         | This is particularly painful when it's a part of your system
         | that's key to security.
         | 
         | You're left between wondering if you should just pay the ransom
         | or switching to a different solution entirely, or gamble and
         | leaving it on an old unpatched version.
         | 
         | ( Looking at you, IdentityServer )
         | 
         | Either way you regret ever going with them.
        
           | rad_gruchalski wrote:
           | Or fork it and maintain yourself. Wanted to write it
           | yourself? Now the opportunity is there.
        
       | TZubiri wrote:
       | Yet another security issue that can be fixed by slapping a
       | nominal cost.
       | 
       | https://en.wikipedia.org/wiki/Sybil_attack#Economic_costs
       | 
       | It can also allow for maintainers of the RUSTSEC rating agency to
       | perform some kind of basic check to see if there's any abuse.
        
       | infocollector wrote:
       | I believe there's a balance to be struck between writing your own
       | code and relying on dependencies. If Armin (the author of this
       | post) is the one writing the code, I would highly recommend using
       | that dependency!
        
       | Voultapher wrote:
       | I sympathize with the author, it's a tricky balance to strike and
       | writing it yourself because how hard could it be can be a trap,
       | but at the same time babelian towers of abstractions can and
       | often do make for a great waste of mental resources.
       | 
       | One of the reasons I wrote https://crates.io/crates/self_cell/
       | was to avoid the dependency trees pulled in by proc macros like
       | ouroboros.
        
         | the_mitsuhiko wrote:
         | It is really hard! And thank you for self_cell. It's one of the
         | crates I'm happily pulling into projects because of having such
         | a great balance between size and utility and also making it a
         | goal to not have dependencies.
        
       | montroser wrote:
       | As the author says, it's a balance. There are many, many problems
       | we deal with that are relatively self-contained, whose solution
       | is going to be stable over long swaths of time. For those types,
       | I hereby grant everyone permission to craft/extract/copy the
       | smallest most straightforward implementation directly into your
       | codebase, and enjoy a life free of deprecation warnings and bogus
       | security alerts and endless dependency churn. If you want some
       | guidelines -- these sorts of cases should be at most one or two
       | hundred lines of code, be free of any dependencies, and have a
       | small api surface area.
        
       | nostradumbasp wrote:
       | Love the thesis statement. There is a lot of hidden cost in
       | allowing abstractions from other libraries to be exposed over
       | your own. I'm not here to say that should never be done but the
       | future costs really need to be balanced at the decision point.
       | 
       | If the encapsulating package churns over its design, or changes
       | it's goals it creates instability. Functionality is lost or
       | broken apart when previously it was previously the simplest form
       | of guarantee in software engineering in existence. It also deters
       | niche but expert owners who aren't career OSS contributors from
       | taking part in an ecosystem."I made a clean way to do X!" being
       | followed up by weeks of discussion, negotiation, politics so that
       | "X fits under Y because maybe people like Z" is inefficient and
       | wasteful of everyones time.
       | 
       | If there's one thing I've learned in my life it's that the
       | simplest things survive the longest. Miniliths, and monoliths
       | should be celebrated way more often. Rust isn't alone in this by
       | the way, I've seen this across languages. I've often seen OSS
       | communities, drive hard for atomistic size packages, and I often
       | wonder if it's mostly for flag planting and ownership transfer
       | purposes than it is to benefit the community that actually uses
       | these things.
        
       | hitchstory wrote:
       | The other extreme of this is:
       | 
       | * Bad abstractions which just stick around forever. There are
       | some examples of this in UNIX which would never be invented in
       | the way they are today but nonetheless aren't going anywhere
       | (e.g. signal handling). This isn't good.
       | 
       | * Invent all of your own wheels. This isn't good either.
       | 
       | There's a balance that needs to be struck between all of these 3
       | extremes.
        
         | chikere232 wrote:
         | I know it's just an example, but if you're on linux there's
         | signalfd() which makes signals into IO so you can handle it in
         | an epoll()-loop or whatever way you like doing IO
         | 
         | We can't remove the old way of course, as that would break
         | things, but that doesn't stop improvements
        
           | IshKebab wrote:
           | Sometimes removing the old way _is_ the improvement though.
           | E.g. adding an alternative to symlinks doesn 't help if
           | symlinks are still allowed.
        
       | bluedino wrote:
       | It's all about straddling the line of 'do you want to know how it
       | works', and 'do you want to get your task done'.
       | 
       | The second developer gets all the glory.
        
         | palata wrote:
         | a.k.a. quality vs productivity. And as you said, the second
         | gets all the glory.
        
           | chikere232 wrote:
           | Reinventing wheels does not always get you better wheels...
           | 
           | Often, with the type of developer who insists on reinventing
           | wheels because it's "easy", you get a pretty bad wheel, as
           | it's the first such wheel the developer has built and their
           | estimation of "easy" was built on a foundation of ignorance.
        
             | krapp wrote:
             | To be needlessly pedantic, reinventing wheels _never_ gets
             | you better wheels. The entire point of the idiom is that
             | the wheel is already a perfect machine and any effort made
             | trying to improve upon it is wasted. At best, you just
             | expend time and effort to get the wheel again.
             | 
             | Which is why it doesn't belong in software - there is no
             | software version of the wheel.
        
               | palata wrote:
               | Yeah. Many times in software, I feel like I'm told:
               | "Creating your own skateboard is reinventing the wheel,
               | you don't want to do that. Instead use this train because
               | it was written by Google and you won't do better".
               | 
               | Sure, but I need a skateboard, not a train.
        
       | palata wrote:
       | I like Rust-the-language, but I hate the Rust-dependencies
       | situation. Honestly I like C++ a lot better for that. People will
       | complain that "it's hard to add a dependency to a C++ project",
       | but I actually see it as a feature. It forces you to think about
       | whether or not it is worth it.
       | 
       | In C++, I control my dependencies. In Rust I get above 100 so
       | quickly I just give up. In terms of security, let's be honest: I
       | have no clue what I am shipping.
       | 
       | Also Rust does not have ABI compatibility and no culture of
       | shared libraries (I guess it wouldn't be practical anyway given
       | the number of libraries one needs). But that just destroys the OS
       | package distribution model: when I choose a Linux distribution, I
       | choose to trust those who build it. Say Canonical has a security
       | team that tries to minimize the security issues in the packages
       | that Ubuntu provides. Rust feels a lot more like Python in that
       | sense, where anyone could push anything to PyPi.
        
         | fxtentacle wrote:
         | How is Debian / Ubuntu secure?
         | 
         | It's signed by a maintainer. And maintainers are vetted. You
         | trust Debian/Ubuntu to only allow trustworthy people to sign
         | packages.
         | 
         | How are Docker / Python / Rust secure? I don't know any of the
         | people who created my docker images, PyPi packages, or Rust
         | crates.
         | 
         | Yes.
         | 
         | We're basically back to sending around EXE and DLL files in a
         | ZIP. It's just that now we call it a container and proudly
         | start it as root.
         | 
         | BTW, I agree with the author of the article: Sometimes you're
         | best off just merging dependency source code. It used to be
         | called "vendoring" and was a big thing in Rails / Ruby. The big
         | advantage is that you're not affected by future malicious
         | package takeovers. But you can still merge security patches
         | from upstream, if you choose to do that.
        
           | tonyhart7 wrote:
           | You use in house solution??? any of these guys that want
           | build something minimal dependency free is valid concern, I
           | agree with that
           | 
           | but but what if people just don't want that??? it given
           | people jobs and things to do (lol, this is serious)
           | 
           | also there are certain things better to use third party
           | library than develop in house like crypto
        
           | akerl_ wrote:
           | The vetting process for open source maintainers has very
           | little overlap with the vetting process for "is this person
           | trustworthy".
           | 
           | This is true for individual libraries and also for Linux
           | distros.
        
           | liontwist wrote:
           | > How is Debian / Ubuntu secure?
           | 
           | You're also forgetting process isolation and roles which
           | provide strong invariants to control what a given package can
           | do.
           | 
           | No such guarantees exist for code you load into your process.
        
           | woodruffw wrote:
           | I don't follow this reasoning: you might trust this
           | distribution packager to be honest, but this doesn't stop
           | them from honestly packaging malicious code. It's unlikely
           | that the typical distribution packager is reviewing more than
           | a minority of the code in the packages they're accepting,
           | _especially_ between updates.
           | 
           | There are significant advantages to the distribution model,
           | including exact provenance at the point of delivery. But I
           | think it's an error to treat it as uniquely trustworthy: it's
           | the same code either way.
        
             | WhyNotHugo wrote:
             | "Trust" as two meanings in English:
             | 
             | - You can trust someone as in "think they're honest and
             | won't betray me".
             | 
             | - You can trust someone as in "think they are competent and
             | won't screw-up".
             | 
             | In this case, we trust distributions packagers in both
             | ways. Not only do we trust that they are non-malicious, we
             | also trust that they won't clumsily package code without
             | even skimming through it.
        
               | woodruffw wrote:
               | The point was not about competency. I think typical
               | distribution packagers are very competent.
               | 
               | "They won't screw up" is the wrong way to look at
               | security: humans _always_ screw up. We 're essentially
               | fallible. We would all do well to remember that the xz
               | backdoor was _not_ caught by distribution code review: it
               | was caught due to a performance side effect that the next
               | adversary will be more careful to avoid.
               | 
               | Software stacks are getting bigger, largely due to
               | engineering pressures that are outside of the control of
               | distributions. It's a basic fact that that means work for
               | the same (or fewer) people, which in turn means less time
               | spent on more complicated packages. Under those
               | conditions, competency is not the deciding factor.
               | 
               | This is, separately, why having lots of little packages
               | _can_ be (but isn 't necessarily) a good thing: small
               | packages that decompose into well-understood units of
               | work can be reviewed more quickly and comprehensively,
               | and can be assigned capabilities that can be tracked and
               | audited with static analysis. You can't do that as easily
               | (or at all) when every package decides to hand-roll its
               | own subcomponents.
        
               | PaulDavisThe1st wrote:
               | > "They won't screw up" is the wrong way to look at
               | security: humans always screw up. We're essentially
               | fallible.
               | 
               | Sure. So pick a system that includes at least one extra
               | possible barrier to them screwing up than the system that
               | has none.
        
               | akerl_ wrote:
               | The average distro package maintainer is not reviewing
               | the underlying code changes in packages to determine if
               | they are malicious, nor is the average disto package
               | maintainer qualified to spot intentionally obfuscated
               | malicious code.
               | 
               | The the average distro package maintainers is "person who
               | cares that package repos stay up to date and is willing
               | to commit their time to that work"
        
               | rad_gruchalski wrote:
               | You are making a sweeping assumption that people who
               | create container images are incompetent.
        
             | palata wrote:
             | It's not only the packager. Some distros have an actual
             | security team. That does not mean they audit everything,
             | but it's vastly better than getting random code from PyPi.
        
               | rad_gruchalski wrote:
               | Some companies providing container images also have
               | security teams. Some companies providing pypi packages
               | also have security teams. Your point is?
        
           | KronisLV wrote:
           | > How are Docker / Python / Rust secure? I don't know any of
           | the people who created my docker images, PyPi packages, or
           | Rust crates.
           | 
           | I know who created the Docker images, because I'm the person
           | who built them!
           | 
           | A lot of the time you can build your images either from
           | scratch, or based on the official base images like Alpine or
           | Ubuntu/Debian or some of the RPM base images, not that much
           | different than downloading an ISO for a VM. With a base, you
           | can use apk/apt/dnf to get whatever packages you want if you
           | trust that more, just remember to clean up the package cache
           | so it's not persisted in the layers (arguably wastes space).
           | For most software, it actually isn't as difficult as it might
           | have initially seemed.
           | 
           | As an alternative, you can also look for vaguely trustworthy
           | parties that have a variety of prepackaged images available
           | and you can either borrow their Dockerfiles or just trust
           | their images, for example,
           | https://bitnami.com/stacks/containers and
           | https://hub.docker.com/u/bitnami
           | 
           | Most likely you have to have trust _somewhere_ in the mix,
           | for example, I 'm probably installing the Debian/Ubuntu
           | packaged JDK instead of compiling mine in most cases, just
           | because that's more convenient.
           | 
           | Also, rootless containers are pretty cool! People do like
           | Podman and other solutions a lot, you can even do some
           | remapping with Docker if there are issues with how the
           | containers expect to be run
           | https://docs.docker.com/engine/security/userns-remap/ or if
           | you have to use Docker and need something a bit more serious
           | you can try this
           | https://docs.docker.com/engine/security/rootless/
        
           | rad_gruchalski wrote:
           | > It's signed by a maintainer. And maintainers are vetted.
           | You trust Debian/Ubuntu to only allow trustworthy people to
           | sign packages.
           | 
           | > How are Docker / Python / Rust secure? I don't know any of
           | the people who created my docker images, PyPi packages, or
           | Rust crates.
           | 
           | Me neither. But the same goes for those from Debian/Ubuntu.
           | In fact, neither I know anyone who vets those who sign and
           | publish packages. What I know is that I can build my own
           | images from container files and then I'm back to installing
           | those apparently trusted packages from Debian/Ubuntu.
           | 
           | > We're basically back to sending around EXE and DLL files in
           | a ZIP. It's just that now we call it a container and proudly
           | start it as root.
           | 
           | I don't get your point. And what's an rpm or deb? You also
           | potentially run stuff as root... sudo apt install -y... post
           | install scripts...
        
         | jvanderbot wrote:
         | So, the feature of "Here's a set of easily pulled libraries" is
         | an anti-feature because it makes it easy to pull supporting
         | libraries? I suspect this is actually about developers and not
         | Rust or JS. Developers choose what dependencies to pull. If
         | nobody pulled a dependency it would wither and die. There are a
         | lot of dependencies for most libraries because most developers
         | prefer to use dependencies to build something.
         | 
         | But I digress. If we're talking build system, nobody is forcing
         | you to use Crates.io with cargo, they just make it easy to. You
         | can use path-based dependencies just like CMake/VCPkg,Conan, or
         | you can DIY the library.
         | 
         | Even with crates.io, nobody is forcing you to _not use version
         | pinning_ if you want to avoid churn, but they just make it easy
         | to get latest.
         | 
         | It's easy to build software on existing software in Rust. If
         | you don't like the existing software or the rate it changes
         | don't blame Cargo. Just do it the way you like it.
        
           | a-french-anon wrote:
           | > because it makes it easy to pull supporting libraries?
           | 
           | No, because it's used as an excuse for a lack of large(r)
           | standard library. It's the equivalent of "the bazaar/free
           | market will solve it!".
           | 
           | You basically end up with a R5RS level of fragmentation and
           | cruft _outside_ your pristine small language; something that
           | the Scheme community decided is not fun and prompted the idea
           | of R6RS /R7RS-large. Yeah, it's hard to make a _good_ , large
           | and useful stdlib, but punting it to the outside world isn't
           | a proper long-term solution either.
           | 
           | It's really a combination of factors.
        
             | materielle wrote:
             | Standard library omissions aren't there just because.
             | 
             | For almost any functionality missing in the standard
             | library, you could point to 2-3 popular crates that solve
             | the problem in mutually exclusive ways, for different use
             | cases.
             | 
             | Higher level languages like Go or Python can create "good
             | enough" standard libraries, that are correct for 99% of
             | users.
             | 
             | Rust is really no different than C or C++ in this regard.
             | Sure, C++ has a bigger standard library. But half of it is
             | "oh don't use that because it has foot guns for this use
             | case, everyone uses this other external library anyways".
             | 
             | The one big exception here is probably async. The language
             | needs a better way for library writers to code against a
             | generic runtime implementation without forcing a specific
             | runtime onto the consumer.
        
               | BoingBoomTschak wrote:
               | You're just elaborating on my use of the word "hard". Yes
               | it is, and C++ is a good example of what not to do. Also,
               | "good" is a spectrum, which means something a bit less
               | shiny but standard is worth existing.
               | 
               | What R7RS-large is doing by standardizing stuff that was
               | already discussed at length through SRFI seems like a
               | good way.
               | 
               | From an external PoV, Clojure seem to be doing okay too.
        
             | pie_flavor wrote:
             | And, what, because it's named `std` it'll be magically
             | better? Languages with giant stdlibs routinely have modules
             | rot away because code maintenance doesn't get any easier,
             | like Python. There are plenty of crates on crates.io made
             | by the Rust project developers, I trust the RustCrypto guys
             | pretty much the same amount, and merging the two teams
             | together wouldn't solve any problems.
        
           | WhyNotHugo wrote:
           | > If we're talking build system, nobody is forcing you to use
           | Crates.io with cargo, they just make it easy to.
           | 
           | Using cargo with distributed dependencies (e.g.: using git
           | repositories) has several missing features, like resolving
           | the latest semver-compatible version, etc. No only is it
           | _easier_ to use cargo with crates.io, it's harder to use with
           | anything else because of missing or incomplete features.
           | 
           | > You can use path-based dependencies just like
           | CMake/VCPkg,Conan, or you can DIY the library.
           | 
           | Have you tried to do this? Cargo is a "many things in one"
           | kind of tool, compiling a Rust library (e.g.: dependency)
           | without it is a pain. If cargo had instead been multiple
           | programs that each on one thing, it might be easier to opt
           | out of it for regular projects.
        
             | jvanderbot wrote:
             | Compared to ... cmake? vckpg? conan?
             | 
             | I have never had a good experience with those. However,
             | using
             | 
             | mydep.path = <path>
             | 
             | in cargo has never been an issue.
             | 
             | And I hate to say it, path-based deps are much easier in
             | C++ / C than other "make the build system do a coherent
             | checkout" options like those mentioned above. So we're at
             | worst parity for this use case, IMHO and subject to my own
             | subjectivity, of course
        
               | TeMPOraL wrote:
               | Speaking of Conan.
               | 
               | Something I don't see anyone talking about is, with such
               | systems you have not one but _at least two_ dependencies
               | to audit per any library you want to include. One is the
               | library itself, but the other one is _the recipe_ for the
               | package manager. At least with Conan, the recipes are
               | usually written by _third parties_ that are _not
               | affiliated with the dependency they 're packaging_. Now,
               | Conan recipes are usually full-blown Python scripts that
               | not only decide where to pull the target sources from
               | themselves, they also tend to ship _patches_ , which they
               | apply to the target source code before building. That is,
               | even if package source is specified directly and fixed on
               | specific release, you _still_ can 't assume you're
               | actually building the exact source of that release,
               | because the recipe itself modifies the code of the
               | release it pulled.
               | 
               | IMHO, trying to do OSS clearance on dependencies pulled
               | via Conan makes very little sense if you don't also treat
               | each Conan recipe as a separate library. But no one does.
        
           | johnnyjeans wrote:
           | yes a large component of it is about developers. if
           | developers were perfect beings, we wouldn't need rust in the
           | first place.
        
             | nindalf wrote:
             | Rust may not be what you want to write, but it's what you
             | want your coworkers to write.
        
         | a-french-anon wrote:
         | That's what I say when I converse about my colleagues: having a
         | package manager from the start that greatly lowers the friction
         | of adding or publishing yet another package deprives a
         | language's ecosystem from something very useful: a good measure
         | of natural selection.
         | 
         | Add to that a free-for-all/no curation repository situation
         | like pypi, npm or cargo together with a too small standard
         | library and prepare to suffer.
        
           | XorNot wrote:
           | I wonder how much of this is just the move away from shared
           | libraries.
           | 
           | In the .NET space nuget certainly makes it easy to add
           | dependencies, but dependencies do seem to be overall fewer
           | and the primary interesting difference I'd note is that a
           | dependency is in fact it's own DLL file - to the extent that
           | it's a feature that you can upgrade and replace them by
           | dropping in a new file or changing configuration.
           | 
           | It strikes me that we'd perhaps see far less churn like this
           | if more languages were back to having shared libraries and
           | ABI compatibility as a first class priority. Because then the
           | value of stable ABIs and more limited selections of upgrades
           | would be much higher.
        
             | a-french-anon wrote:
             | The quest for performance makes macros,
             | monomorphisation/specialization and LTO too attractive for
             | simple dynamic linking to remain the norm, unfortunately.
             | And in a way, I understand, a Stalin/MLton style whole-
             | program optimizing compiler certainly is worth it when you
             | have today's computing power.
        
         | oersted wrote:
         | This frankly sounds like a rationalization for an aesthetic
         | preference. It is undeniable that being able to easily build on
         | top of others' hard work is an enormous advantage in any
         | domain.
         | 
         | Duplicate work should only happen if you are confident that
         | your requirements are significantly different, and that you can
         | deliver an implementation as good as a team that has likely
         | focused on the problem for much longer and has acquired a lot
         | more know-how.
         | 
         | It is true that such an attitude might be justifiable for
         | certain security or performance critical applications, you
         | might need end-to-end control. But even in those cases, the
         | argument for trusting yourself by default over focused and
         | experienced library authors is dubious.
         | 
         | Either way, a good dependency manager opens the door for better
         | auditing, analysis and tagging of dependencies, so that such
         | critical requirements can be properly guaranteed, again
         | probably better than you can do yourself.
        
         | lolinder wrote:
         | There's a corollary here to "build it yourself", which is "vet
         | it yourself". Cargo, npm, and pip all default to a central
         | registry which you're encouraged to trust implicitly, but we've
         | seen time and time again that central registries do not
         | adequately protect against broken or malicious code that causes
         | major security flaws downstream. Each of these ecosystems
         | trains its developers to use hundreds of dependencies--far more
         | than they can personally vet--with the understanding that
         | _someone_ else must surely have done so, even though we 've
         | seen over and over again that the staff of these registries
         | can't actually keep up and that even long-running and popular
         | projects can suddenly become insecure.
         | 
         | I'd like to see an ecosystem develop that provides a small
         | amount of convenience on top of plain old vendoring. No central
         | repository to create a false sense of security. No overly
         | clever version resolution scheme to hide the consequences of
         | libraries depending on dozens of transitive dependencies. Just
         | a minimal version resolution algorithm and a decentralized
         | registry system--give each developer an index of their own
         | libraries which they maintain and make downstream developers
         | pick and choose which developers they actually trust.
         | 
         | Maybe a bit like Maven if Maven Central didn't exist?
        
         | Ygg2 wrote:
         | > In C++, I control my dependencies. In Rust I get above 100 so
         | quickly I just
         | 
         | Just don't add dependencies, it's that simple. If you have
         | enough time to control C++ dependencies, you can control them
         | in Rust as well.
        
           | lolinder wrote:
           | That's not an answer when the entire ecosystem is built
           | around the idea of adding lots of dependencies to do stuff. I
           | don't need no dependencies, I'd like to live in a world where
           | I can add two or three. But if the culture is so far gone
           | that those two or three transitively import 20 each, I don't
           | have that as an option--it's all or nothing.
        
             | Ygg2 wrote:
             | > That's not an answer when the entire ecosystem is built
             | around the idea of adding lots of dependencies to do stuff.
             | 
             | Again. Don't add dependencies. Just don't. Vendor it
             | yourself. Or write it yourself. Absolutely nothing is
             | forcing you to use the dependencies except your own desire
             | to save time.
             | 
             | Cargo is giving you the option to A) save your own time B)
             | minimize dependencies. You choose A) and blame Cargo.
        
               | palata wrote:
               | I don't think it's entirely fair. You're telling me
               | "don't use any dependency at all". Vendoring is not a
               | solution, because it does not remove the transitive
               | dependencies. So I have to essentially rewrite it myself.
               | 
               | I find many libraries in C++ that don't pull 20
               | dependencies. It's common for me to have a C++ project
               | that has ~6-8 dependencies. In Rust I have never seen
               | that. Either I have no dependency at all, or I have 100+.
               | 
               | I actually had this toy project that I wrote both in C++
               | and in Rust, for the learning experience. Both did
               | exactly the same thing, with a very similar design. In
               | C++ I had 8 dependencies. In Rust, 186. The thing is, 186
               | is enough for me to not even read all their names in the
               | lock file. As soon as 25 dependencies magically appear in
               | my lock file, I stop caring and start YOLOing it.
        
               | Ygg2 wrote:
               | > Vendoring is not a solution, because it does not remove
               | the transitive dependencies. So I have to essentially
               | rewrite it myself.
               | 
               | Vendoring means, you fork it, make any modification you
               | want, such as reducing the number of dependencies, but
               | keeping it up to date with upstream is on you.
               | 
               | Rewriting it for yourself is what happens in C++. C++
               | didn't get flatter by waving a magic wand, it just moved
               | the slider. It's just that code reuse is hard, so you
               | rewrite things that would be a shared dependency in Rust
               | into a header file and call it a day.
               | 
               | > I find many libraries in C++ that don't pull 20
               | dependencies.
               | 
               | I can find many libraries in Rust that don't pull 20
               | dependencies (mostly by searching crates written by
               | people like the_mitsuhiko). Some people care, but they
               | are a minority. If you truly care about this, like
               | the_mitsuhiko does, write it with no dependencies.
               | 
               | I, personally, try to minimize my dependencies, but there
               | is a reason why most people don't care - it has little to
               | no impact on them and saving time by NIH is better than
               | not learning from history and reinventing wheel only
               | square.
               | 
               | ---
               | 
               | Problem is: There are infinitely many of properties to
               | improve (number of dependencies, byte size, compile time,
               | run time, alignment, crates not made by X, time to
               | market, reproducibility, compliance with law XYZKM,
               | safety etc.) and not enough time or possibility space to
               | do them all.
        
               | lolinder wrote:
               | > Vendoring means, you fork it, make any modification you
               | want, such as reducing the number of dependencies, but
               | keeping it up to date with upstream is on you.
               | 
               | This is not what vendoring means, this is called forking.
               | Vendoring is just the copy+commit phase, not the
               | modification part.
        
               | palata wrote:
               | > you fork it, make any modification you want, such as
               | reducing the number of dependencies, but keeping it up to
               | date with upstream is on you.
               | 
               | Say a pretty complex library has 30 dependencies. I fork
               | it, I remove the dependencies, and now it doesn't build
               | anymore. What do I do?
               | 
               | I feel like you're saying "You should not write the small
               | feature you need yourself. Instead, you should heavily
               | modify a big dependency that contains the feature you
               | need, because that's certainly easier and better".
               | 
               | If the library did not rely on those 30 dependencies, it
               | would not depend on them, would it?
               | 
               | > If you truly care about this, like the_mitsuhiko does,
               | write it with no dependencies.
               | 
               | So you start by telling me that I should just remove the
               | dependencies from my dependencies, and then you tell me
               | that you don't do that and instead choose dependencies
               | that don't have many dependencies themselves? It feels
               | like we agree...
               | 
               | > not learning from history and reinventing wheel only
               | square
               | 
               | This is the thing: "I learned from history so I don't
               | reinvent the wheel" should not be treated like a
               | religious belief. It's probably not a good idea to write
               | your own kernel. But I often spend a day or two
               | implementing a feature that I would have gotten from a
               | dependency in 2h. And it's almost always worth it! And
               | sometimes I depend on libraries (e.g. I usually don't
               | rewrite an HTTP library).
        
               | Ygg2 wrote:
               | > So you start by telling me that I should just remove
               | the dependencies from my dependencies, and then you tell
               | me that you don't do that and instead choose dependencies
               | that don't have many dependencies themselves? It feels
               | like we agree...
               | 
               | There are two cases: 1. You have 100 dependencies. 2. You
               | just started writing your code.
               | 
               | If you are doing 1) then you have to vendor/fork till
               | it's acceptable.
               | 
               | If you are starting from 2) just don't add them.
               | 
               | > This is the thing: "I learned from history so I don't
               | reinvent the wheel" should not be treated like a
               | religious belief.
               | 
               | Nothing in programming should be treated as religious
               | belief. But duplicating code can be just as deadly as
               | dependencies glut, taken to it's logical extreme.
               | 
               | A golden middle approach is best, sadly no one can agree
               | on it.
        
         | SkiFire13 wrote:
         | > People will complain that "it's hard to add a dependency to a
         | C++ project"
         | 
         | The way I see it the issue is that it's hard to add a
         | dependency _in such a way that no people will have issues
         | building your project with it_. This is problematic because
         | even if you manage to make it work on your machine it may not
         | work on some potential user or contributor's.
         | 
         | > But that just destroys the OS package distribution model:
         | when I choose a Linux distribution, I choose to trust those who
         | build it.
         | 
         | Distros still build Rust packages from sources and vendor crate
         | dependencies in their repos. It's more painful because there
         | are usually more dependencies with more updates, but this has
         | nothing to do with shared libraries.
        
           | palata wrote:
           | > The way I see it the issue is that it's hard to add a
           | dependency _in such a way that no people will have issues
           | building your project with it_.
           | 
           | From my point of view, if it's done properly I can just
           | build/install the dependency and use pkgconfig. Whenever I
           | have a problem, it's because it was done wrong. Because many
           | (most?) developers can't be arsed to learn how to do it
           | properly; it's easier to just say that dependency management
           | in C++ _sucks_.
        
         | LinXitoW wrote:
         | I genuinely don't know what people with this opinion work on
         | that they can so easily choose to completely re-invent the
         | wheel in every project, just because they're afraid of
         | hypothetical dangers. Most of which are still present for
         | private re-implementations (like bugs).
         | 
         | I cannot think of a single project where NIH syndrome would've
         | been a net positive. Even dependencies that aren't "essential"
         | are super helpful in saving time.
         | 
         | When you recreate parts of an "optional" dependency for every
         | single project, how do you find the time to fix all the extra
         | bugs, the edge cases, the support for different versions of
         | lower level dependencies, of different platforms?
        
           | palata wrote:
           | > that they can so easily choose to completely re-invent the
           | wheel in every project
           | 
           | Nobody, and I mean 0, chooses to completely re-invent the
           | wheel in every project. I understand why you would find this
           | weird. I don't start every project with nand gates.
           | 
           | But the tendency is to use a library to check if a number is
           | even or odd. It is a gradient, and you have to choose what
           | you write and when you rely on a dependency. If you need to
           | parse an XML file, or run HTTP requests, most likely you
           | should find a library for it. But personally, if I can write
           | it in 1-2 days, I always do it instead of adding a
           | dependency. And I'm pretty sure it's worth it.
           | 
           | > how do you find the time to fix all the extra bugs, the
           | edge cases, the support for different versions of lower level
           | dependencies, of different platforms
           | 
           | If you take e.g. C++, maintaining your dependencies takes
           | time. If you support multiple platforms, probably you need to
           | (cross-)compile the dependencies. You should probably update
           | them too (or at least check for security vulnerabilities),
           | and updating dependencies brings its lot of issues (also in
           | Rust: most libraries are 0.x.x and can break the API whenever
           | they please).
           | 
           | Then, if you miss a feature in the library, you're pretty
           | much screwed: learning the codebase to contribute your
           | feature may be a lot of work, and it may not be merged. Same
           | for a bug (debugging a codebase that is not yours is harder).
           | If you end up forking the dependency and having to live with
           | a codebase you did not write, most likely it's better to
           | write it yourself.
           | 
           | The people advocating the "not re-inventing the wheel because
           | NIH is really bad" philosophy seem to assume that libraries
           | are always good. Now if you have a team of good developers,
           | it may well be that the code they write is better than the
           | average library out there. So if they write their features
           | themselves, you end up with less but better code to maintain,
           | and the people who understand that code work for you. Doesn't
           | that sound good?
        
           | caseyohara wrote:
           | > Even dependencies that aren't "essential" are super helpful
           | in saving time.
           | 
           | They might save time up front, but over the lifetime of a
           | long-lived project, my experience is dependencies end up
           | costing more time. Dependencies are a quintessential but
           | often overlooked form of tech debt.
           | 
           | If you only work on short-lived projects or build-it-and-
           | move-on type contract work where speed matters more than
           | quality, sure, go nuts with dependencies. But if you care
           | about the long term maintainability of a project, actively
           | reducing dependencies as close to zero as possible is one of
           | the best things you can do.
        
       | teddyh wrote:
       | " _When you're working on a really, really good team with great
       | programmers, everybody else's code, frankly, is bug-infested
       | garbage, and nobody else knows how to ship on time._ "
       | 
       | -- Joel Spolsky, _In Defense of Not-Invented-Here Syndrome_ :
       | <https://www.joelonsoftware.com/2001/10/14/in-defense-of-not-...>
        
       | jitl wrote:
       | At least in the JavaScript/NPM ecosystem, "if you want it done
       | right, you have to do it yourself".
       | 
       | Often the most popular package for X is actually low quality
       | and/or obviously incorrect, especially for small-to-medium
       | complexity topics. There may be better alternatives but they're
       | hard to find due to low usage numbers or poor SEO, so I usually
       | need to build stuff myself out of necessity.
       | 
       | For example, the most popular sql`...` tagged template literal
       | package available on NPM isn't type safe, doesn't understand
       | differences in SQL dialects, can't escape queries for debugging
       | or manual execution, doesn't have console.log formatter, lacks
       | utilities like .join or binding helpers, etc. it's an anemic
       | package yet everyone uses it. Maybe there are better ones that
       | are specific to a database like Postgres, but it's a simple
       | enough thing to build, plus if you build it yourself in the
       | monorepo it's super easy to improve things as they come up.
       | 
       | So, I stated with a little 300 line one for SQLite that's grown
       | over the years to have a nice Postgres dialect as well, an
       | ecosystem of helpers and lint rules, and it seems far ahead of
       | whatever in NPM.
       | 
       | Another area is ESlint rules. Often there's an open source rule
       | that does like 80% of the job, but the maintainers seem hostile
       | or dislike typescript or something. So much easier to copy the
       | rule into our repo and improve it there rather than trying to
       | contribute back. Or, it's the usual quality issue - original rule
       | is doing some crazy slow shit and it's much easier to write from
       | scratch a simpler more correct version.
        
       | palata wrote:
       | There was the "not-invented-here" syndrome, I think that Rust
       | (cargo), Python (pypi) and Javascript (npm) push to the other
       | extreme.
       | 
       | If you ship a library, you are responsible for its security. If
       | you dynamically link to a library you don't ship, then it's not
       | your problem anymore (someone else is shipping it). I think we
       | tend to forget that: shared libraries have advantages in terms of
       | security.
       | 
       | And whether you ship the dependency or not, you should be ready
       | to replace it or maintain it yourself. Too many projects depend
       | on a project they don't understand, and get screwed down the line
       | because it becomes unmaintained. Many times it's actually better
       | to write the code you need than to depend on a third-party you
       | don't understand.
        
         | swiftcoder wrote:
         | > If you ship a library, you are responsible for its security.
         | If you dynamically link to a library you don't ship, then it's
         | not your problem anymore
         | 
         | In what universe is that true? In this universe, you are now on
         | the hook for the security of _both_ libraries, and the extra
         | one you don 't actually have any influence over.
        
           | palata wrote:
           | Well to be fair, in practice in this universe, nobody gives a
           | damn about security. I meant it more in a normative way.
           | 
           | Nobody cares much about the security of their own code, and
           | even less for the security of their dependencies. At least if
           | you link dynamically, you give an opportunity to your
           | distribution to have someone care about it.
        
       | gwbas1c wrote:
       | > But when you end up using one function, but you compile
       | hundreds, some alarm bell should go off.
       | 
       | About a year ago I ran a project to update 3rd party
       | dependencies.
       | 
       | One of the dependencies was a rich math library, full of all
       | kinds of mathematical functions.
       | 
       | I did a little bit of digging, and we were only using one single
       | method, to find the median of a list.
       | 
       | I pointed the engineer to the Wikipedia page and told him to
       | eliminate the dependency and write a single method to perform the
       | mathematical operation.
       | 
       | ---
       | 
       | But, IMO, the real issue isn't using 3rd party dependencies: It's
       | that we need a concept of pulling in a narrow slice of a library.
       | If I just need a small part of a giant library, why do I have to
       | pull in the whole thing? I think I've heard someone propose
       | "microframeworks" as a way to do this.
        
         | ebiester wrote:
         | That's how we get things like leftpad in the JS ecosystem.
         | 
         | On one side, I think if we had a good system of trust, that's
         | not a problem.
         | 
         | And part of me likes the idea of something like Shadcn - you
         | like a component? Copy it into your library. However, if there
         | ends up being a vulnerability, you have no idea if you are
         | affected.
         | 
         | For some code, that's not a problem. For other code, we truly
         | depend on having as many eyes as possible on it.
        
         | cluckindan wrote:
         | Wow. For those who don't know, here's a pseudocode
         | implementation:                   Median(list) {           let
         | len = length(list)           if len % 2 == 0 {             let
         | x = floor(len/2)             return (list[x] + list[x+1]) / 2
         | }           return list[len/2]         }
         | 
         | Note: assumes the list is already sorted.
         | 
         | Managed to resist calling is_odd there!
        
           | gpm wrote:
           | In most cases I'd probably use nearly this. I note that it
           | contains a bug due to integer overflow if naively translated
           | to most languages.
           | 
           | But if I have a big enough list that I care about space usage
           | (I don't want to make a copy that I sort and then throw
           | away), or speed (I care about O(n) vs O(n log(n))) I'd be
           | looking for a library before implementing my own.
           | 
           | Here are the relevant algorithms if you really want to
           | implement your own fast median code though:
           | https://cs.stackexchange.com/questions/1914/find-median-
           | of-u...
        
             | cluckindan wrote:
             | I use that math textbook algorithm in production to produce
             | a median from a list which has a bounded size _and_ is
             | already sorted by the db, though that bound could
             | _technically_ grow to INT_MAX if someone managed to make
             | that many requests in five minutes. Not very likely. :-)
        
               | gpm wrote:
               | > and is already sorted by the db,
               | 
               | Right, if it's already sorted just taking the midpoint is
               | the obviously correct algorithm (and O(1) time/space).
               | It's only in the unsorted cases where with giant lists
               | you should start thinking about alternatives.
               | 
               | If I'm working with gigabytes of photon counts (each
               | element representing the number photons detected in a
               | time interval) I don't want to sort my gigabyte long list
               | before getting the median - sorting would destroy the
               | very important structure of the data so I'd just have to
               | throw away the copy afterwards. This is referencing some
               | code I worked on a long time ago. I'm not sure I had to
               | calculate a median specifically, but similar enough
               | statistics. It's a simple function, but not a one size
               | fits all algorithm.
        
         | saghm wrote:
         | In Rust, a library can define "features" that can be
         | conditionally enabled or disabled when depending on it, which
         | give a a built-in way to customize how much of the library is
         | actually included. Tokio is a great example of this; people
         | might be surprised to learn that the total number of direct
         | dependencies that are required by tokio is only two[1];
         | everything else is optional!
         | 
         | Unfortunately, it doesn't seem like people are super diligent
         | about looking into the default feature set that's used by their
         | dependencies and proactively trimming that down. It doesn't
         | help that the syntax for pulling in extra features is less
         | verbose than removing optional but default ones (which requires
         | both specifying "no-default-features" and then manually adding
         | every one of the default features that you do still want back
         | to the list of ones you pull in), and it _really_ doesn't help
         | that the only way for libraries to expose the ability to prune
         | unneeded features from their own dependencies to the users who
         | inherit them is by manually making their own feature that maps
         | to the features of every single one of their own dependencies.
         | For example, if you're writing a library with five
         | dependencies, and every one of them has one required dependency
         | and four optional ones, giving the users of your library full
         | control over what transitive features they pull in would mean
         | making 20 features in your own library mapping to each of those
         | transitive features, and that's not even counting the ones that
         | you'd want to make for your own code in order to be a good
         | citizen and not force downstream users to include all of your
         | own code.
         | 
         | More and more I'm coming to the opinion that the ergonomics
         | around features being so much worse for trying to cut down on
         | the bloat is actually the catalyst for a lot of the issues
         | around compile times in Rust. It doesn't seem to be super
         | widely discussed when things like this come up though, so maybe
         | it's time that I try to write a blog post or something with my
         | strong feelings on this so at least I'll have something to
         | point to assuming the status quo continues indefinitely.
         | 
         | [1]: https://github.com/tokio-
         | rs/tokio/blob/ee19b0ed7371b069112b9...
        
       | TZubiri wrote:
       | A metric that I would like to focus in is dependency depth. We
       | had this with the OSI model way back, but at this point it seems
       | that anything beyond layer 7 just gets bucketed into 8+.
       | 
       | We need to know if a dependency is level 1 or level 2 or level 3
       | or 45. And we need to know what the deepest dependency on our
       | project is. I might be naive, but I think we should strive to
       | reduce the depth of the dependency graph and maybe aim for like 4
       | or 5 layers deep for a web app, tops.
        
         | themk wrote:
         | I've often thought the same. I would love a depedency manager
         | that not only surfaced this information, but required you to
         | declare upfront what level your library is.
         | 
         | I think it would reign in the bloat.
        
       | jrmg wrote:
       | _Companies are more likely to reward engineers than scold them
       | for pulling in that new "shiny library" that solves the problem
       | they never actually had._
       | 
       | Perhaps I'm sheltered: is this really true in people's
       | experience?
        
         | swiftcoder wrote:
         | Depends on the company. Amazon had a pretty bad case of NIH,
         | Meta tended to embrace open-source (and as often as not,
         | transitioned to embrace-extend-extinguish if they liked it
         | enough)
        
       | baggy_trough wrote:
       | Functions that fit on a page should usually be published as
       | sample code rather than gems / crates / whatever.
        
       | dartos wrote:
       | The issue is, imo, rust is a big pain to write.
       | 
       | It's really nice when someone else has created all the
       | abstractions for you. It's fairly easy and fun to discover
       | features of crates thanks to the type system.
       | 
       | But to actually build out those low level abstractions yourself
       | is cumbersome and not very fun. It's easy to type system yourself
       | in a corner.
       | 
       | You even lose the whole big selling point of rust when you use
       | `unsafe`.
       | 
       | There was an article a while ago comparing zig and rust and it
       | had a good quote that went something like
       | 
       | "Rust is for programming in the large, and zig is for programming
       | in the small"
       | 
       | And I think what you're looking for is programming in the small.
       | 
       | Small, focused, programs with minimal dependencies.
        
         | palata wrote:
         | IMHO, Rust is a replacement for C/C++, which are not so easy to
         | write correctly.
         | 
         | Rust should not be a replacement for e.g. Go, Swift or Java,
         | which are a lot easier to write and have memory safety.
         | 
         | I wonder who actually needs Rust (as opposed to using e.g. Go)
         | and finds it a lot harder to write than C/C++?
        
           | dartos wrote:
           | I'd say rust is a replacement for C++.
           | 
           | Powerful, but complex, language features.
           | 
           | C is drop dead simple.
        
       | semanser wrote:
       | I'm actually working on a linter for dependencies that checks all
       | your dependencies on 15+ rules.
       | https://github.com/DepshubHQ/depshub
       | 
       | It's true that dependency-free software is very rare these days.
       | The most obvious reason is that people don't want to "reinvent
       | the wheel" when doing something. While this is a 100% valid
       | reason, sometimes people simply forget _what_ they are building
       | and for _whom_. Extensive usage of dependencies is just one of
       | the forms of overengineering. Some engineering teams even do
       | their planning and features because of the new shiny thing.
       | 
       | The problem of dependencies is massive these days, and most
       | companies are focusing on producing more and more code instead of
       | helping people manage what they already have.
        
       | ForHackernews wrote:
       | > But there is a simpler path. You write code yourself. Sure,
       | it's more work up front, but once it's written, it's done
       | 
       | Well, assuming you wrote it perfectly and didn't introduce any
       | security vulnerabilities... that you will never be alerted to,
       | because no one else is reviewing your code.
        
         | liontwist wrote:
         | This line of reasoning can't get you far. Where do dependencies
         | come from?
         | 
         | > security vulnerabilities
         | 
         | Does this code parse untrusted data? Does your process have
         | unlimited access to sensitive resources?
        
       | dazzawazza wrote:
       | It's important to remember that the most powerful form of code
       | reuse is copy and paste.
        
         | layer8 wrote:
         | Mutability for the win!
        
       | pbronez wrote:
       | > when you end up using one function, but you compile hundreds,
       | some alarm bell should go off.
       | 
       | That seems feasible to test automatically. Shouldn't an
       | intelligent compiler automatically trim these things out?
        
       | thrance wrote:
       | I used to think the same way seeing cargo pull so many LOCs, but
       | let's be real, I am not going to write my HTTP server by hand,
       | nor my postgresql driver. And those are the ones that pull a lot
       | of dependencies.
       | 
       | As for smaller QOL dependencies, I might as well use them
       | directly as I need them, instead of spending 3h building
       | something similar but half as good and robust, just to decrement
       | my dependencies counter by 1.
       | 
       | I've had very few issues with Rust where an old project can't be
       | built anymore because of rotting dependencies, when it happens
       | almost every time with JS or Python. This is my largest gripe
       | with dependencies.
       | 
       | I do still think Rust would have been better off with a larger
       | stdlib, but ultimately it's really not that big of a deal and
       | isn't worth it rewriting code for the sake of reducing a meter.
        
       | wiz21c wrote:
       | "You write code yourself."
       | 
       | I don't see myself writing wgpu or tokio. And wgpu is a hefty
       | price to pay in dependencies.
       | 
       | So yeah, dep's are a plague, but hey, we are writing super
       | complex stuff nowadays.
       | 
       | And I don't care if my project needs 464 (yeah, you read it well)
       | dependencies. I do my share by making sure I don't have 2
       | versions of the same lib and that's about it.
        
       | beej71 wrote:
       | Remember leftpad! :)
       | 
       | "Every dependency is an asset. Every dependency is a liability."
       | 
       | It's a balance.
        
       | jumpkick wrote:
       | I recently revived a web app I wrote in 2006, my first startup.
       | It was a social media site focused on media sharing. A pretty
       | simple LAMP stack for the time. PHP 5, MySQL 3.2, but it has all
       | of your typical (for the time) social media features. I revived
       | this app because I wanted some hands-on time with new CI/CD tech
       | that I don't get to use at my day job, so I'm working to
       | extremely over-engineer the app's deployment process as a
       | learning project. I could have used Wordpress or some other Hello
       | World app, but this is a lot more fun.
       | 
       | I had written nearly all of the PHP from scratch. I wrote
       | libraries for authentication/authorization, templating, form
       | processing etc. I used one PEAR library for sending email. The
       | frontend was vanilla HTML and there was barely any JavaScript to
       | speak of. We used Flash for media playback. In other words,
       | myself and my small team built nearly all of it ourselves. This
       | was just how you did most things in 2006.
       | 
       | It only took me about an hour to get the 19-year old app up and
       | running. I had to update the old PHP mysql drivers to mysqli, and
       | update the database schema and some queries to work in MySQL 8
       | (mostly wrapping now-reserved words with backticks and adjusting
       | column defaults which are now more strict). The only thing that
       | didn't work was the Flash.
       | 
       | An hour to revive an app from 2006. Contrast this with my day
       | job, wherein we run scores of Spring Boot apps written in Java 8
       | that have pages of vulnerabilities from tens of dozens of
       | dependencies, which are not easy to update because updating one
       | library necessitates updating many other libraries, and oh my
       | goodness, the transitive dependencies. It's a nightmare, and
       | because of this we only do the bare minimum of work to update the
       | most critical vulnerabilities. There's no real plan to update
       | everything because it's just too tall of an order.
       | 
       | And the funny thing is, if you compare what this PHP app from
       | 2006 did, which had truly, barely any dependencies, to what these
       | Spring Boot apps do, there is not a lot of difference. At the end
       | of the day, it's all CRUD, with a lot more enterprise dressing
       | and tooling around it.
        
         | skydhash wrote:
         | Go and the C linux world have sold me on the fat library
         | philosophy. You brought a library to solve a problem in a
         | domain, then add your specific bits. You don't go and bring a
         | dependency for each item in your check list. Yes there may be
         | duplicate effort, but the upgrade path is way easier.
        
         | ok123456 wrote:
         | Most of that new CI/CD tech is standard now precisely because
         | of all the complexity added by maintaining third-party
         | dependencies and constant changes in the runtime environment.
         | This isn't a problem for the most part for an old LAMP
         | application deployed by scp.
        
         | madduci wrote:
         | While I might agree with you on some points, I don't want to
         | spend time reinventing the wheel and introduce bugs into it.
         | 
         | Take for example standard communication message formats like
         | FHIR or HL7. You definitely don't want to implement the whole
         | definitions for the standard, which is already complicated.
         | 
         | Writing Cryptographic functions by yourself is also typically a
         | shot in your foot, has proved in all these years of found
         | critical security issues.
         | 
         | We live in a time where you want to actual solve a business
         | problem, by focusing on the problem and not on how the solution
         | is built properly. With the advent of AI this is even more
         | critical, since all the code feels like stitched together
         | blindly.
         | 
         | Spending time on developing all by yourself might give you a
         | good shot in the long run, but first you need to survive the
         | competition, who maybe has already caught the market, by using
         | fast and throw-away code at the beginning.
        
         | kgilpin wrote:
         | I'm curious if the OpenRewrite project has any value to you in
         | keeping your Java stuff up to date?
         | 
         | (I'm not affiliated with it; just curious about strategies for
         | upgrading and maintaining apps that use big frameworks.)
        
         | pie_flavor wrote:
         | An important point here is that the transitive dependency issue
         | completely does not exist in Rust. If you upgrade a crate to a
         | version which upgrades its _public_ dependency, i.e. it uses it
         | in its APIs and you need to interact with it to interact with
         | those APIs, then you obviously need to upgrade your copy of the
         | subdependency at the same time. But private transitive
         | dependencies are totally irrelevant unless they link to C
         | libraries. You can have as many semver-incompatible versions of
         | a crate in the same dependency tree as you want, and even
         | depend on multiple versions _directly_ if you need to. No Java-
         | style sweeping upgrades are ever needed, just upgrade the one
         | thing with the vulnerability. (I believe C# has the same
         | feature, though it 's a little more baroque about it.)
        
       | 999900000999 wrote:
       | I agree 100% .
       | 
       | Even though NodeJS is largely responsible for my career, NPM has
       | given me more trauma than my messed up childhood.
       | 
       | Imagine you're a new programmer, you're working on a brand new
       | app to show to all your friends. But you want to add a new
       | dependency, it doesn't like all the other dependencies, cool you
       | say I'll just update them. Next thing you know absolutely nothing
       | works, Babel is screaming at you.
       | 
       | No worries, you'll figure something out. Next thing you know
       | you're staring at open git issues where basic things literally
       | don't work. Expo for example has an open issue where a default
       | new react native project just won't build for Android .
       | 
       | It's like no one cares half the time, and in that case the
       | solution isn't even in the node ecosystem, it's somewhere in the
       | Android ecosystem. It's duct tape all the way down. But this can
       | also inspire confidence if a billion dollar project can ship non-
       | functional templates, then why do I have imposter syndrome when
       | my side projects don't work half the time!
        
         | strawhatguy wrote:
         | Certainly nodejs and npm getting out of hand was a wakeup call
         | for me, about 15 years ago.
         | 
         | I started to view it has a personal failure when I brought in
         | that first dependency, which meant needing all of the packaging
         | and organization just to use that first package.json, rather
         | than just having plain js loaded from a script tag.
        
           | 999900000999 wrote:
           | I have a side project right now where I tried my hardest to
           | use anything aside from NodeJS.
           | 
           | Even though it's just for my personal consumption, and I
           | doubt more than five or six people will ever see it, I ended
           | up having to use NodeJS and HTML because it's simply the best
           | solution.
           | 
           | Imagine an alternate timeline where Google decided to offer
           | other languages as first class citizens in the browser. Could
           | you imagine Golang or Dart. No compiling down to JS, just
           | running natively.
        
             | strawhatguy wrote:
             | Mozilla (Eich) wrote JS, and specifically Microsoft wrote
             | the XMLHttpRequest, which allowed Google to exist. And
             | supposedly WASM is to be that thing, so any language can
             | compile down to it. Hasn't totally worked out I guess. A
             | browser would have to take the leap to be WASM-only, and
             | compile even JS to it.
             | 
             | I'm doing backend work mostly right now. If I start some
             | other project, I'll probably try using htmx and tailwindcss
             | as my two js script tags, and the rest will be controlled
             | from the backend.
        
         | pie_flavor wrote:
         | This is a problem for Node, but it isn't a problem for Rust.
         | You don't need any dependencies to 'like' other dependencies.
         | You can have all the versions at the same time and nothing
         | breaks.
        
       | sz4kerto wrote:
       | I'll sound like a grumpy old man, but: that's one of the big
       | advantages of using Java. The ecosystem is _super stable_ if you
       | go with the usual stack (Spring Boot, etc.), you generally get
       | support for all the modern cloud stuff, and it breaks very
       | rarely.
        
       | medhir wrote:
       | Agreed with the sentiment of the author, but are teams really
       | arguing for pulling in dependencies in the name of security?
       | 
       | I've seen the exact opposite -- every dependency introduces a new
       | opportunity for vulnerabilities, and to be judicious in pulling
       | in new ones due to the potential security risk.
        
       | andrewaylett wrote:
       | I have a little JS library that has an analogue _within cargo_
       | which really helps with this:
       | https://www.npmjs.com/package/downgrade-build
       | 
       | It means I can keep my dependency spec broad, because I _actually
       | test_ my releases with minimum supported versions. Cargo has (or
       | maybe had -- I can 't find it any more) a similar feature built
       | in.
       | 
       | Renovate will even broaden (rather than replace) dependency
       | specifications, if asked, so if my package works with both the
       | old and the new version then I can make a patch release with the
       | wider dependency spec and not break anything.
       | 
       | (On which note: I can really highly recommend using Mend Renovate
       | to keep dependencies up to date: https://www.mend.io/renovate/ )
        
       | otoolep wrote:
       | Related, but not exactly the same:
       | https://blog.gopheracademy.com/advent-2014/case-against-3pl/
        
       | zelphirkalt wrote:
       | You need capable engineering for building it yourself. If you
       | only got engineers, who only ever reached for libraries, in
       | ecosystems like NPM or PyPI, you will find them hard-pressed to
       | develop solutions for many things themselves, especially so, if
       | they are supposed to be solutions, that stand the test of time,
       | and have the flexibility they need. It takes a lot of practice to
       | "avoid programming yourself into a corner".
       | 
       | Another thing I noticed is, that one can often easily do better
       | than existing libraries. In one project I implemented a parser
       | for a markdown variant, that has some metadata at the top of the
       | file. Of course I wrote a little grammar, not even a screen of
       | code, and just like that, I had a parser. But I did not expect
       | the badness of the frontend library parsing the same file. That
       | one broke, when you had hyphens in metadata identifiers. At first
       | I was confused, why it could not deal with that. Then it turned
       | out, that it directly used the metadata identifiers as object
       | member names ... Instead of using a simple JSON object, they had
       | knowingly or unknowingly chosen to artificially limit the choice
       | of names and to break things, when there are hyphens like in
       | "something-something". In the end my parser was abandoned, people
       | arguing, that they would have to "maintain" it. Well, it just
       | worked and could easily be adapted for grammar changes. There was
       | nothing difficult to understand about it either, if you had just
       | a little knowledge about parsers. Sounds incredible, but
       | apparently no one except me on the team had written a parser by
       | using a parser generator library before.
       | 
       | And like that, there are many other examples.
        
       | hyperpape wrote:
       | I'm so tired of rants like these. Both the pro and anti-
       | dependency versions. It's just impossible to express an opinion
       | on the issue without looking at specific applications.
       | 
       | What I want to see is someone actually break down a real
       | application and its dependencies and argue through what's
       | included and what's omitted.
       | 
       | At least there's one example. I just think it's wrong (and I'm
       | not the only
       | one...https://news.ycombinator.com/item?id=42813003). The
       | terminalsize crate has special behavior for illumos. The average
       | developer should never have to think about illumos.
       | 
       | (Note in case Bryan Cantrill walks by: no slight towards illumos
       | or you--you seem great, loved the Oracle rant. Illumos seems
       | cool. It's just that most developers should not think about it).
        
         | bcantrill wrote:
         | Ha ha -- just out here on my daily walk through HN and this
         | comment made my day...
        
       | bmn__ wrote:
       | 2025: Mitsuhiko discovers ::Tiny modules :)
       | https://metacpan.org/search?size=500&q=%3A%3ATiny
       | 
       | The article shows it's a cultural problem, not a technical. The
       | normal case should be that implementations come in all sizes of
       | complexity on the market, and the end user can choose freely; and
       | I consider this a healthy state of affairs. Rust and JS are a
       | monoculture that has fallen prey to some mind virus where only
       | big supply chain is valued, and so the market becomes distorted.
       | Tell me whether I'm wrong in my assessment.
        
       | melodyogonna wrote:
       | Working with Go moved my mindset from _use libraries for
       | everything_ I had with JS /TS to writing things myself helped by
       | stdlib
        
       | jacobjjacob wrote:
       | I think that although there are rational tradeoffs in bringing in
       | too many dependencies, a lot of these arguments are just
       | rationalizing a personal preference and a tendency of engineers
       | to want to build more and more.
       | 
       | Is managing your software supply chain more work than writing it
       | yourself? Probably not if there are thousands or millions of LOC
       | involved. But if you have infinite money, go ahead and build
       | everything from scratch..
        
         | forty wrote:
         | The issue is precisely that many people underestimate the cost
         | of pulling someone else's code as a dependency.
         | 
         | Pulling a dependency with 1M LoC is probably more costly than
         | writing 1000 LoC yourself.
        
       | jppope wrote:
       | I feel strongly about this but figured it would be a decent
       | exercise to challenge my assumptions? I've been doing this for a
       | while and with the exception of a limited number of high quality
       | packages I generally write a lot of my own utilities because in
       | my opinion "the juice isn't worth the squeeze" from a lot of open
       | source options. Obv The time trade off is different now that I
       | have decent experience and with the advent of ChatGPT
       | 
       | From what I can tell the research tends to agree with me:
       | -https://www.researchgate.net/publication/221555430_An_empirical_
       | study_of_build_maintenance_effort       -
       | https://arxiv.org/abs/1710.04936
       | 
       | It appears that there is a substantial overhead that comes with
       | `npm install`ing away your problems.
       | 
       | I would love to see other research if anyone has some... the
       | quick ~5 studies I checked didn't seem to answer the question
       | 100% but are good enough to confirm my thoughts.
        
       | ChrisMarshallNY wrote:
       | Speaking only for myself, I avoid [other people's] dependencies
       | like the plague.
       | 
       | But I use a lot of them; just ones that I wrote.
       | 
       | Almost all of my publicly-available work consists of Swift
       | modules (SPM), with very few stars or forks. Not very popular.
       | 
       | Which suits me just fine. I write for an audience of 1. I publish
       | my work, because I believe that this forces me to do a really
       | good job on it. I don't like to worry about my dependencies. If I
       | wrote them, and they follow my Quality bar, then they're fine.
       | 
       | I think, in all the work I do, I have maybe only two or three
       | dependencies, outside of ones that I wrote, or that are provided
       | by the development system (I write native, so there's no giant
       | ball of mud hybrid library).
       | 
       | It does limit the scope of what I can do, but not really that
       | much.
        
       ___________________________________________________________________
       (page generated 2025-01-24 23:01 UTC)