[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)