10 ms·
Build It Yourself
- dazzawazza 2y agoIt's important to remember that the most powerful form of code reuse is copy and paste.
- layer8 2y agoMutability for the win!
- abound 2y agoThis 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 2y agoGo's vast standard library helps a lot with keeping dependency numbers down
- lionkor 2y agoExactly 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 https://pkg.go.dev/log
- LinXitoW 2y agoThe built-in "logging" in Go is barely more than a fancy Println. For example, where are the levels, like DEBUG and WARN?
- Cyph0n 2y agoFor Rust and Go in particular, the difference is in the standard library. The Rust stdlib is (intentionally) small.
- sesm 2y agoI 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 2y agoI 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).
- jcgrillo 2y ago> it's much easier to write Go, Swift or Kotlin than Rust (IMHO). While I respect your opinion, I must say I find it much more difficult to get work done in golang than rust. Mainly due to stringly typed errors and nonexistent documentation culture. Trying to figure out what error states my program might get itself into is essentially a futile exercise in golang whereas in rust it's generally annotated right there in the source code by lsp.
- jitl 2y agoOne 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 2y agoWhich 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 2y agoIt’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/ 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 2y ago> 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.
- Joker_vD 2y ago> 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 https://news.ycombinator.com/item?id=42039401
- the_mitsuhiko 2y agoIt'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 2y agoTerminals 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 2y agoPrevious 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 https://asciinema.org/a/s2vmkOfj6XtJkQDzeM6g2RbPZ
- cpursley 2y ago> 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 2y agoI’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 2y agoI agree. Here is a similar post from another amazing developer. https://www.mikeperham.com/2016/02/09/kill-your-dependencies/ https://www.mikeperham.com/2016/02/09/kill-your-dependencies...
- pdimitar 2y agoThe sentiment is good but our OP here is not making their argument well (and is incorrect about terminal development btw). Mike Perham also talks about a dynamic language in an ecosystem that was just as obsessed with left-pad-like lunacies like the Node.JS ecosystem still is. The sentiment is not wrong but doesn't apply to Rust. Be honest: would you roll your own HTTP and WebSockets server from scratch? Also how likely do you think it is that a business will allow you this huge downtime during which no moneymaking activities will be performed?
- bluGill 2y agoWorse, 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 2y agoSoftware that hasn’t been touched in ten years and still does the job is about as ideal as a dependency can be.
- palata 2y agoI 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 2y agoMaybe it's even actively maintained!
- WhyNotHugo 2y agoIn 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 2y agoBut 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 2y agoThe same can be true for the dependency that releases weekly updates.
- TZubiri 2y agoYet another security issue that can be fixed by slapping a nominal cost. https://en.wikipedia.org/wiki/Sybil_attack#Economic_costs 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 2y agoI 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 2y agoI 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/ https://crates.io/crates/self_cell/ was to avoid the dependency trees pulled in by proc macros like ouroboros.
- the_mitsuhiko 2y agoIt 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 2y agoAs 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 2y agoLove 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.
- deleted 2y ago[deleted]
- hitchstory 2y agoThe 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 2y agoI 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 2y agoSometimes removing the old way is the improvement though. E.g. adding an alternative to symlinks doesn't help if symlinks are still allowed.
- chikere232 2y agoWhy? That way you break a lot of things.
- pdimitar 2y agoYou have to start somewhere. Strongly specialized programs that f.ex. never access disk and only access network are a good candidate to be tested in either restricted containers or brand new OS-es that carry legacy baggage. It's doable, but nobody wants to put in the money, time and energy into pioneering it.
- bluedino 2y agoIt'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 2y agoa.k.a. quality vs productivity. And as you said, the second gets all the glory.
- chikere232 2y agoReinventing 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 2y agoTo 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 2y agoYeah. 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 2y agoI 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 2y agoHow 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 2y agoYou 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_ 2y agoThe 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.
- teddyh 2y ago“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-invented-here-syndrome/ https://www.joelonsoftware.com/2001/10/14/in-defense-of-not-...>
- jitl 2y agoAt 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 2y agoThere 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 2y ago> 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 2y agoWell 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.
- pdimitar 2y agoRust is not taking this into the extreme at all. You're taking a ranty ill-informed article way too seriously. Maybe it confirms your bias?
- palata 2y agoI'm sharing my opinion on a related thread. Sure, I agree with the article. What makes you say that I am ill-informed, except that you disagree with me? Is it a rule that anyone disagreing with you is ill-informed?
- gwbas1c 2y ago> 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 2y agoThat'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 2y agoWow. 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 2y agoIn 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-unsorted-array-in-on-time https://cs.stackexchange.com/questions/1914/find-median-of-u...
- TZubiri 2y agoA 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 2y agoI'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 2y agoCompanies 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 2y agoDepends 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)
- pdimitar 2y agoYes, it's extremely common, think at least 95% of the time. Time to delivery is the main metric for almost any company that ships software.
- baggy_trough 2y agoFunctions that fit on a page should usually be published as sample code rather than gems / crates / whatever.
- dartos 2y agoThe 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 2y agoIMHO, 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++?
- semanser 2y agoI'm actually working on a linter for dependencies that checks all your dependencies on 15+ rules. https://github.com/DepshubHQ/depshub 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.
- pdimitar 2y agoYour thing looks promising. Do you plan to introduce GitHub releases? I would subscribe to those and read the CHANGELOG.
- semanser 2y agoI do use GitHub releases already https://github.com/DepsHubHQ/depshub/releases https://github.com/DepsHubHQ/depshub/releases You can subscribe by clicking on Watch -> Custom -> Releases.
- ForHackernews 2y ago> 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 2y agoThis 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?
- ForHackernews 2y ago> Does this code parse untrusted data? I don't understand the question. Yes, I trust the global community of software developers to write a parsing library with sanitization more than I trust myself + my one or two work colleagues.
- pbronez 2y ago> 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 2y agoI 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 2y ago"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 2y agoRemember leftpad! :) "Every dependency is an asset. Every dependency is a liability." It's a balance.
- pdimitar 2y agoRust is nowhere near the craziness of left-pad and it saddens me to see how many "I agree" comments I've read in this thread with zero accounting for nuance.
- jumpkick 2y agoI 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 2y agoGo 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.
- 2y ago
- deleted 2y ago[deleted]
- 999900000999 2y agoI 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 2y agoCertainly 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 2y agoI 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 2y agoMozilla (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.
- sz4kerto 2y agoI'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.
- pdimitar 2y agoGood news for you: Rust is already quite mature and is mostly the same as Java in this regard. OP is exaggerating, if not misinforming.
- medhir 2y agoAgreed 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 2y agoI have a little JS library that has an analogue within cargo which really helps with this: https://www.npmjs.com/package/downgrade-build 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/ https://www.mend.io/renovate/ )
- deleted 2y ago[deleted]
- otoolep 2y agoRelated, but not exactly the same: https://blog.gopheracademy.com/advent-2014/case-against-3pl/ https://blog.gopheracademy.com/advent-2014/case-against-3pl/
- zelphirkalt 2y agoYou 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 2y agoI'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 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 2y agoHa ha -- just out here on my daily walk through HN and this comment made my day...
- bmn__ 2y ago2025: Mitsuhiko discovers ::Tiny modules :) https://metacpan.org/search?size=500&q=%3A%3ATiny 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 2y agoWorking with Go moved my mindset from use libraries for everything I had with JS/TS to writing things myself helped by stdlib
- jacobjjacob 2y agoI 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 2y agoThe 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 2y agoI 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 2y agoSpeaking 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.
- dhagrow 2y agoThis is deliciously ironic for me. For those who aren't aware, Armin is the original author of Flask, the Python web framework. Around the same time, there was a very similar library called Bottle. They were almkst identical in functionality, but while Flask became very popular, I always preferred to stick with Bottle because it was a single file with no dependencies, which meant it was very easy to just copy into your project. It also made it very easy to hack around with, and I got to the point where I understood the entire thing. I did couple it with Gevent for the server and websockets, but I was able to put together some heavy-lifting projects that way. I still feel a strong impulse to use it for small web projects. Sadly, it didn't keep up with a lot of the more modern practices that Python has introduced over the years, so it does feel a bit dated now.
- Onavo 2y agoRather rich of OP (he's the author of flask and the rye package manager). Rust adopted the NPM style dependency resolution because it scales. The traditional Python school of dependency resolution doesn't scale. Sure you get a nice clean transitive graph, but you will also spend many hours wrangling upstream diamond dependency conflicts.
- funcDropShadow 2y agoMy observation with the Scala and Haskell ecosystems has been very similar. One primary source of churn is changing interfaces. And very advanced static type systems offer a large design space how to model interfaces. Which leads to lots of incremental improvements. But lots of interface changes together with deep dependency trees lead to exponential explosion of changes. Rich Hickey has been discussing this very early, but almost nobody got it when he said it, myself included. Striving for obviously simple interfaces, that avoid nominal static types like the plague, is the way to avoid this often pointless waves of changes through language ecosystem, just because someone designed a better option monad or whatever.
- Havoc 2y ago> Sure, it's more work up front, but once it's written, it's done. I don’t think that’s entirely true. Unless you’re a star programmer you’ll find bugs and edge cases in your own code. So I end up updating it a lot. Not a dependency but also not write once
- Sloowms 2y agoThis article says that big number is bad but sometimes you can make number bigger. Big number is bad because of bad experience with big number. If a project has 0 dependencies but uses the exact same code as a project with 100 dependencies which project is better? They are the same. So dependencies are not inherently bad. What if the dependencies also have another 100 lines of code that are not used in the project? I would say that doesn't really matter. In some cases it might lead to a slower build time or even a slightly bigger binary. The actual situation you will end up with is that you write your own code and it's nothing like the dependencies. This is great because you don't have to worry about the maintainer of the dependency wanting to add things you don't need or making mistakes. You only have to worry about you making mistakes or having made mistakes. Mistakes you will maybe never encounter and mistakes you will never find because most of your code will never be looked at again. The dependency you could have used did so you would have to deal with pesky updates that might not affect you. You could also choose not to do any of the updates of the dependency. You just pin all dependencies to a specific version and never update. Whenever there is an issue you just pull in the dependency and fix the issue yourself. Now you've got the best of both worlds, you didn't have to do the work upfront of generating the code with AI and you still get to maintain everything yourself. But we also know that using dependencies can be bad, experience has shown that. But why were those experiences bad. Leftpad was a problem of a package disappearing because it was not version pinned and the package manager allowed it to dissappear. This problem has been solved. Then there is the issue of abandoned packages, version incompatibility or packages that move away from your use case. But how different is this from pinning all dependencies and maintaining them from that point. The point that open source contributers and dependency users have made before is that once you download the code it's yours. You are always the maintainer of whatever code your project uses. This means you are responsible for maintaining the dependencies you use. In the most basic sense you should start a fork for each dependency and start to maintain it. But that is an enormous task so not a solution. You can hope you picked correctly and the package will be maintained forever but you will surely pick some that will end up abandoned. Another solution could be to pay someone else to maintain the dependency or a fork of the dependency. If there are more projects that do this you can actually build on a stable basis where you can trust the dependencies are good. The number can be big but not bad. Otherwise you will have issues with whatever path you choose. Because fundamentally as a user of open source you are not a customer but a raccoon looking in a dumpster for code.
- burjui 2y agoOne day I needed to parse and generate RISC-V instructions. I wrote a custom bitfield implementation, nothing fancy: no derive macros or any crap like that, only u32 bitfields specified by an array — [(RangeInclusive<u32> /src/, usize /length/, RangeInclusive<u32> /dst/]. One function + a bunch of tests. It worked great. Then I tried the `bitfield` crate, which claims to be as fast as code I would've written by hand. It had dependencies and was two orders of magnitude slower. Basically, it was as fast as code that I would've written by hand in Python.