21 ms·
Never use a dependency that you could replace with an afternoon of programming
- randyrand 6y agowhy not just copy the code from the dependency into your own sources?
- wonderlg 6y agoIndeed, one could even automate the process, some sort of tool that automatically copies the dependency’s code, kinda like an install. I think someone already wrote such tool.
- btilly 6y agoYou don't believe in software licensing, do you?
- wrkronmiller 6y agoVendoring dependencies is usually not the same thing as ripping off someone else’s code. It usually just boils down to keeping a copy of the version of a dependency you used.
- btilly 6y agoCopying someone else's code and putting it in your software repository is an excellent way to find yourself violating a wide variety of open source licenses. This is actually one of the most common causes for GPL violations. And companies have gotten into serious trouble for that. Either rewrite the code, or maintain it as a dependency and follow the licensing rules. Don't simply copy code from it into your project unless you have explicit reason to believe that that is OK to do.
- deleted 6y ago[deleted]
- randyrand 6y agoAt my work we can only use BSD license as libraries.
- vzidex 6y agoI'm not sure if I agree - commonly-used packages will have known and documented faults, while validating something you (your organization) created can be challenging. Dance with the devil you know and all that.
- renewiltord 6y agoI recall using an unusual library a while ago where the author had embedded their own log4j-style implementation. I couldn't configure that the same way I configured other logging. Hardly a problem today since I just write to `stderr` and have the container log aggregator push elsewhere but boy was it annoying.
- mcqueenjordan 6y agoAvoiding dependencies is a noble goal, and something to be valued, but this simple rule is too simplistic. The problem lies in the fact that there are a great many things I can hack together in an afternoon to "replace" some kind of external dependency, but the quality discrepancy of these hacks is highly variant. My understanding of what can or should be done in an afternoon might differ with my colleagues'. Unfortunately, like all things in engineering, you have to carefully reason about the pros/cons, requirements, and costs. After that analysis, you can make a judgment on depend vs. build (also, buy vs. build).
- lgessler 6y agoAgreed. For libs that are "afternoon-y" in their scope (so, not an HTTP server or crypto), if you need to get off the fence you can use some cheap heuristics to assess the quality of a library without auditing its code. For instance, you can look at its popularity (in downloads or Github stars), its release/version history, its number of open issues, and its development activity. If I see high issue counts and many major releases with breaking changes, I'm going to avoid it. If I see 2+ years of stability with mostly minor releases, low issue counts, and high use rates, I figure it's going to probably be better than whatever half-baked solution I could scribble in an afternoon.
- kmike84 6y agoI wouldn't consider a high number of open issues a problem on its own. All big popular projects with a history have a high number of open issues. There are some exceptions, who may be closing isses aggressvely, but it is more about a style of managing of those issues, not about project health. Over time an issue tracker inevitably becomes a collection of hard-to-reproduce bugs, incomplete patches, underspecified feature requests, random tracebacks, etc. Maintainers can choose to just close everything which is not actionable immediately, or be in comfort with such issues, and let them live in the bug tracker. I personally like a style when an issue is closed only if it is fixed, or if it doesn't contain useful information, or if it is a duplicate. A better indicator is activity and responsiveness of the maintainers in the issue tracker.
- 6y ago
- jasonpeacock 6y agoThis is horrible advice. There's a reason that you don't write your own hashtable implementations. Yes, I can write a hashtable implementation in an afternoon, but it's going to have bugs that I'll spend the next year fixing, and still not achieve the performance of the pre-built version. All that work of finding existing solutions and learning how to use them? That's part of the job. Find a bug in the dependency? Submit a patch. Worried about the dependency changing? Lock the version. Too many external repos to retrieve those dependencies? Use a local cache. Don't reinvent the wheel.
- alkonaut 6y ago> I can write a hashtable implementation in an afternoon, but it's going to have bugs If it has any bugs that would surface in a year of production (while the dependency version wouldn't) then you didn't write an equivalent in an afternoon. The advice, if it's to be useful at all, must be things that you could completely replace in the same quality, in an afternoon. It's the left-pads and is-odds, to begin with.
- avmich 6y ago> that you could completely replace in the same quality And the quality of the original might be questionable for many cases.
- asplake 6y agoNever use a dependency if you could write something of equivalent quality in afternoon. Seems reasonable enough.
- avmich 6y agoI'd extend "afternoon" to "half a week", but in general I agree with OP. > Yes, I can write a hashtable implementation in an afternoon, but it's going to have bugs that I'll spend the next year fixing, and still not achieve the performance of the pre-built version. The meaning of "afternoon work" should be considered "of good enough quality". Tests, structure, reasonable docs, all that. It shouldn't be a fastest written something, it should be a normal code. > and still not achieve the performance of the pre-built version. Some losses in performance are acceptable for greater visibility and better fit for the project. If you need non-trivial performance gains - well, those are also achievable by code, are you sure you can actually write such code in a few days? > Find a bug in the dependency? Submit a patch. That's the point. To submit a good patch, you have to internalize the system. It's easier to do if the system is yours - doesn't do much except what you need. > Worried about the dependency changing? Lock the version. Now you've locked yourself out of upstream bug fixes. > Don't reinvent the wheel. Here is a wheel patented in 1972 in US, with noticeable benefits over the traditional idea: https://en.wikipedia.org/wiki/Mecanum_wheel https://en.wikipedia.org/wiki/Mecanum_wheel :) . We do reinvent the wheel whenever we need to have an actual wheel for a device, not an abstract concept. Similarly, we write for loops, "reinventing" them for our specific purpose. Those are all different wheels, loops and needs. Don't mistake the "idea" of a hashtable with an implementation.
- sreekotay 6y agoAgree-ish - buttt makes me think: How about... dont keep a dependency you could replace with an afternoon of programming? Factor, re-factor, and (most especially) DELETE should be tools in the toolbox -- but see if you need it/keep it (e.g. protoype it in, etc first) before you re-write.
- avmich 6y ago> Factor, re-factor, and (most especially) DELETE Lines of code is a passable metric for the quality of work if they are considered "spent", not "created". That is, the programmer's work is better, all else being equal, if it takes fewer lines of code. Who said so? Knuth, Wirth, Dijkstra, Perlis?..
- aziytuiam 6y agoA hundred afternoons later my small application is finally completed; now I must maintain update and document it all for ever rather than relying on third party components. What I really wish is people would look closer to home; for example use some of the thousands of functions that ship with your operating system before downloading a package.
- vorticalbox 6y agoI have this problem at work with our node apps. With things like reduce, map, the like their is less need to rely on lodash or underscore for them.
- fastball 6y agoThe problem with node is that it doesn't ship with a stdlib. That being said, lodash has worked great for utility stuff. It encapsulates like 99% of utility functions I need in my apps.
- tmaly 6y agoThis reminds me of the Node left-pad module problem in a way. I think if something is so trivial to write, you should write it rather than using a dependency. If it is non-trivial, I prefer the official standard libraries for a programming language. That is if a solution exists in the standard library. I think the Go standard library with its batteries included mantra and the level of support it gets is good example of a library that should be used when a solution exists within it or by utilizing it.
- brightball 6y agoOr just C&P the relevant open source code (license allowing). Removing a dependency doesn’t have to mean writing from scratch.
- gmueckl 6y agoIf you copy the code into your project you at least need to keep track of the original authors and licensing or you're in violation of the copyright 99% of the time.
- brightball 6y agoOh, of course. Definitely.
- closeparen 6y agoThe single best way to avoid dependencies is to use a language with a large standard library. Given the variance in standard library coverage, it’s rarely productive to argue about this topic in a language agnostic way. Using only stdlib in Go is very different from using only stdlib in JavaScript.
- smabie 6y agoThe best way to avoid dependencies is to use a language that is built in a way such that dependencies are worthless. Like APL, J, or kdb+/q. All of these languages are incredibly small, have almost non-existent standard libraries, and yet are designed in such a way that a large standard library becomes superfluous. Having a large standard library speaks poorly of the composability and orthogonality of language primitives.
- yoz-y 6y agoSure, if the problems you are solving are well suited for languages like APL, J or kdb+/q...
- smabie 6y agoCall me an iconoclast, but I think array languages are more suitable for general purpose programming than even general purpose languages.
- rrampage 6y agoAs someone who is not well versed in APL/J/K, how do they deal with structured data like JSON? Is there some sort of DSL like jq built into them?
- smabie 6y agoBecause kdb+/q has such few datatypes and you can't define anymore, it's very easy: q) .j.k"[2.2, 3.5]" 2.2 3.5 Serialization is also trivial: q) .j.j 0 1 2 3 "[0,1,2,3]" In general, sending stuff across memory boundaries (files, network, ram, etc) is exceedingly trivial in kdb+/q. To execute a function on a remote server, simply connect to a server and send across the call to the handle. For example, to send synchronously compute 1+1: q) h:hopen `::6666 q) h(+;1;1) 2 You can send over anything you want, even the entire source code of program to be executed! This is a really flexible environment, where you can create really powerful app-engines. All members of a cluster can send code, data, and messages to any other node, async or sync. Much like Common Lisp and SmallTalk, you can easily connect to production nodes and modify code while the service is running. It's rare to find such a dynamic, flexible, and interpreted language that also has world class performance, even often beating hand written C. Combined with an integrated database, you get a distributed system that can't be beat, at least performance-wise. And the craziest thing is that all of this sits in at 650kb executable with libc has the only dependency. And all probably in less lines of code than a simple javascript webapp!
- scandox 6y agoFrankly my own code is usually the worst dependency I could have.
- thrownaway954 6y agoso true :(
- sparker72678 6y agoProbably good advice, but when was the last time a programmer accurately scoped a problem when they said it will take “an afternoon” to build?
- tluyben2 6y agoThat is the issue I have with it: ‘an afternoon’ is already way too vague. Make it ‘5 minutes’ (left pad etc) then I think it works out.
- axlee 6y agoIs that really 5 minutes? (For when left-pad was relevant) var cache = [ '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ]; function leftPad (str, len, ch) { // convert `str` to a `string` str = str + ''; // `len` is the `pad`'s length now len = len - str.length; // doesn't need to pad if (len <= 0) return str; // `ch` defaults to `' '` if (!ch && ch !== 0) ch = ' '; // convert `ch` to a `string` cuz it could be a number ch = ch + ''; // cache common use cases if (ch === ' ' && len < 10) return cache[len] + str; // `pad` starts with an empty string var pad = ''; // loop while (true) { // add `ch` to `pad` if `len` is odd if (len & 1) pad += ch; // divide `len` by 2, ditch the remainder len >>= 1; // "double" the `ch` so this operation count grows logarithmically on `len` // each time `ch` is "doubled", the `len` would need to be "doubled" too // similar to finding a value in binary search tree, hence O(log(n)) if (len) ch += ch; // `len` is 0, exit the loop else break; } // pad `str`! return pad + str; }
- TheDong 6y agoOne of the points of the article is that when you code a dependency for your purpose, you get smaller code. For example, I know I'll always pass it a string, so I don't need to type-check. I started with the problem of "I need a function that pads a string with a character out to some length". Coding it up took under 1 minute, easily under 5 minutes. function leftPad (str, len, ch) { const neededPadding = len - str.length; if (neededPadding <= 0) { return str; } return ch.repeat(neededPadding) + str; } It took me longer to write this comment. The fact that the left-pad code has optimizations (which don't matter for the place I'm using it) and type-checks (which don't matter; my higher level unit tests would catch that mistake) is beside the point.
- mcphage 6y ago(1) Most programs don't have that many direct dependencies, especially smaller dependencies. It's often dependencies of dependencies. In npm, adding just `jest` will make your `node_modules` directory explode. (2) if Linus's Law is "given enough eyeballs, all bugs are shallow", then having fewer eyes on a library means more bugs. (3) Oftentimes you think you can replace a dependency with an afternoon of programming, but it turns out, it's not quite as simple as you think. (4) Sometimes you only use a small piece of a library to start with, but over time use more and more. If it's your own code, then you're going to be continuously refactoring, updating, rewriting it. If it's a library, then you can just start using the additional pieces as you need.
- orthecreedence 6y agoEven if this is true, the problem is you don't know what's going to take an afternoon of programming. How many times have we all said "should only take an hour" just for it to take four days? If someone spent the time and effort building something you need, I don't see a problem with using it. It all depends on what kind of system you're building, what the security and stability guarantees are, and in general what trade-offs you want to make. In other words, "never" is usually bad advice.
- moltar 6y agoNever use store-bought bricks if you can replace them with an afternoon of brick making. https://youtu.be/D59v74k5flU https://youtu.be/D59v74k5flU
- jamil7 6y agoI knew which video it would be before clicking... But to your point they're often not really "store-bought" bricks though. More like bricks someone was giving away on the side of the road, you're free to use them to build your house but with no guarantees they work and the instructions are missing or incomplete. Oh and they're the wrong shaped brick but you only figure that out later.
- Justsignedup 6y agoI'm the opposite. I always think I can solve it in an afternoon and always realize there are a lot of intricacies. Fuck making popup positioning in browsers. That shit is hard to get just right.
- dheera 6y agoUgh please just don't use popups at all. I block every single one I see with custom CSS rules. GDPR cookie warnings, "please subscribe", stupid "can i help you" chat popups, everything.
- loopz 6y agoWhen coding, be prepared to put it in the garbage bin! If you're prepared for this, you can code things more quickly, and not worry about the code slowing you down later. This works when you're unsure exactly what to build and need to iterate (agile). First build is an iteration, not arbitrary "sprints" or "increments"! The cost of rebuilding MUST be budgeted though. If you don't have this freedom, things are bound to suck one way or another. Then, next best thing, build it as simple as you can, and put effort into making it composable and pluggable. So you retain freedom to swap out components. This is also an investment, and takes some more time and effort. If you even can't even have that, results are bounded by those restrictions.
- jdmichal 6y agoMy rule is, don't use a dependency to implement your core business. Is JSON parsing our core business? No, so why would we ever write -- and thereby commit to supporting for its entire lifetime -- JSON parsing code? All the code you write and support should be directly tied to what you as a business decide are your fundamental value propositions. Everything else you write is just fat waiting to be cut by someone who knows how to write a business case. To be clear, this is about the lifetime support of code. It's very, very rare that code can be written once and never touched. But that long tail of support eats up time and money, and is almost always discounted in these conversations. I don't even care that Jackson JSON parsing has years of work behind it, when I can hack together a JSON parser in a day. I care that Jackson will continue to improve their offering without any further input, while that's not true of my version.
- xamuel 6y agoWell, one special edge-case would be where you only need to parse some extremely tiny subset of JSON (for example: you only need to parse dictionaries whose keys and values are positive integers, like {1:2,3:4}). Then, depending how expensive the full json parser is, it might be worth your while just writing the limited parser yourself. Of course, you might say, inevitably feature-creep will expand the list of things your parser needs to parse, but that's not a law of physics. Sometimes in certain limited, well-defined projects, it really is true that YAGNI.
- aliceryhl 6y agoThere are fully correct JSON parsers you aren't going to beat, even if you implement a subset. [1] [1]: https://branchfree.org/2019/02/25/paper-parsing-gigabytes-of-json-per-second/ https://branchfree.org/2019/02/25/paper-parsing-gigabytes-of...
- Ma8ee 6y agoNo, I won't beat them. But if it a limited subset that I can implement with twenty lines straightforward code, that will often be cheaper. I've been on projects where they imported xml-parsers many times bigger than the rest of the whole codebase just to send a well formatted order number.
- mberning 6y agoMike Perham in 2016: https://www.mikeperham.com/2016/02/09/kill-your-dependencies/ https://www.mikeperham.com/2016/02/09/kill-your-dependencies...
- nijave 6y agoShared dependencies can also reduce, code though. Do you really want 10 slightly different implementations of the same thing after you've brought in a few large dependencies?
- MrStonedOne 6y agoThat almost never pans out because they all end up pinning different versions of the same library.
- wonderlg 6y ago“Almost never” is still more frequent than “never,” so it’s still positive.
- aoeusnth1 6y agoI don’t have enough afternoons for this.
- lordnacho 6y agoIt's a matter of judgement, but here's a few observations: - With a little experience, you know what gets fiddly and what doesn't. Today for instance, I needed a way to remove tags in an SVG document, which looks a lot like HTML tags. I quickly ended up finding that Regex is not the solution (a well known guy on SO wrote an answer that looks like a huge warning sign). I also couldn't enumerate all the corner cases. So I found a lib that does it, along with an SO answer that turns it into a two-liner. - Dependencies vary in quality. Some are basically like another standard lib. Boost for instance is very well used. The tough ones are where the lib seems to be "finished", where there seem to be few commits recently, but the project was once lively and functional. IIRC libev comes to mind here. And then there are the totally dead projects, where there's a load of issues open and nobody saying anything. - Try to lock down versions. If you get a thing working with a certain version, there's no reason you need the newest new as soon as it's pushed. You can probably live with doing a scan for updates now and again. - Your afternoon of programming needs to have a clear end. That hashmap you wrote will very likely spew out issues over the next few days. CSV parser, maybe. Bessel function, that'll work.
- JadeNB 6y ago> a well known guy on SO wrote an answer that looks like a huge warning sign For those who are in today's 10000, you might mean this piece of art: https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 https://stackoverflow.com/questions/1732348/regex-match-open...
- topicseed 6y agoTotally agreeing with this but the issue is maintenance. Sure, I can find a package and copy and paste a few files and make it my own — or do it from scratch even! But then, that's not really my core domain, so I'll most likely never touch that piece again anytime soon. A quality package tends to have that covered (with a small risk, too if it's an untrusted source).
- tobyhinloopen 6y agoMy strategy: Use dependencies, but don’t depend on them.
- whalesalad 6y agoSo true. Oftentimes I will look at the source of a simple ruby gem or node package and see that it is actually really just one single file, with 100 various .yml/spec/lint/test/cloud/coverage/cov/tox/blah landmines in the repo to confuse you. In those cases, I'll copy-paste the code with attribution back at the top of my source file. The headache is not worth all of the pomp and circumstance for some of these tiny little tools.
- Rantenki 6y agoThis is not good advice for these reasons: - Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law. -> It's gonna take longer than an afternoon. Always - Opportunity cost: Your app needs to DO something, and spending time building dependencies steals quality from your core business proposition, even if it's a small (Haha: see previous point) dependency. - While there are a ton of crap libraries out there, there are also a lot of good ones, which include hard lessons learned, about even simple tasks. You _could_ rewrite a very simple http client in an afternoon (telnet hostname 80\n GET / HTTP/1.0\n\n), but you'll probably have a ton of glaring flaws just waiting to bite you _badly_.
- gm 6y agoNo. Some reasons: 1) As everyone else has said, we are horrible at estimating. 2) We think we might only need 1% of an external dependency, until we do not. Case in point: By this criteria, no one needs a grid/datatable library.So we write it "in an afternoon". Then we're asked for an export to Excel. Later on we're asked for pagination with large data sets. And then an export to PDF. How many afternoons did that cost you? 3) Writing new code is an excellent opportunity to create new bugs and implement bad design because we're on hurry since it took nowhere near an afternoon of code to write and we cut corners. Anyway, those are just three that come to mind immediately. This is not an argument against the "afternoon rule", but is really an argument against making simple-sounding black and white rules to solve to problems that are inherently complex, and are thus, gray areas.
- ogre_codes 6y ago> We think we might only need 1% of an external dependency I've seen the opposite just as often. Someone things an external dependency can just plug in and solve the problem, then 16 hours later they've made the basic thing work with an external dependency with a bunch of internal code on top of it. Now you have a pile of fragile code which breaks when the dependency changes underneath you, you have a bunch of in-house code supporting a thing which might not be getting up-line support anymore, and you still have a bunch of internal code to maintain. > Case in point: By this criteria, no one needs a grid/datatable library.So we write it "in an afternoon". Then we're asked for an export to Excel. Later on we're asked for pagination with large data sets. And then an export to PDF. How many afternoons did that cost you? You can always migrate to a library at a later date if the scope changes. More-so, you don't know how the scope is going to change, how do you pick a dependency based on future scope changes?
- gm 6y agoThat's exactly what my point is: This is way too complex to boil down to a simple rule of thumb to apply to all cases. There are arguments and counter arguments (and real-life examples and counter examples) ad-nauseum. It's better to say: "Hey experienced people: How would you decide whether to introduce an external dependency or roll your own if the immediate requirement at hand seems small enough to write on your own in half a day?". Then we can get into a fun conversation that will boil down to "It depends."
- tuyguntn 6y ago20 afternoon dependencies -> now you have month of work, more code to test (and write tests), more code to support in the future, more code to understand for new developer. Add edge cases which you are not aware of, you are screwed my basic rule if dependency has small code base (<300-500 lines) I will copy/paste that chunk of code into repo and refer original repo (assuming LICENSE is appropriate)
- pacomerh 6y agonothing takes an afternoon of programming if it needs to be QA'd. At least this is not good advice for a company. Possibly for personal projects.
- earthboundkid 6y agoBut you can add a dependency in less than an afternoon? The exact same objection applies in both cases.
- jedberg 6y agoThis sounds like pre-mature optimization. If the library does what you need it to do, use it. If it becomes a problem later, then optimize it. That last thing you want to do is spend a bunch of time reimplementing code when: 1) It may not matter at all, 2) You might miss important edge cases, or 3) You got everything right but you still have to maintain it forever. If it's going to take you three days to integrate the library, maybe it's not such a good library, or maybe it's really complicated because there are a lot of edge cases. In that case, dig into the code and see if you can figure out what it's doing. But if you think you can spend an afternoon rewriting a library that would take three days to integrate, there is a good chance you might be missing something important.
- lolc 6y agoI remember starting with an overloaded library from NPM where I used some basic functionality. That worked fine for a while. When later I got lost fixing a defect in the tangle, I just ripped out the parts I needed and made a trimmed version. The interface remained the same, for the parts I was using. Nothing to adapt. In this way I had little investment in the beginning. And once I knew what I needed, it was another small investment to clean the code.
- bellwether 6y agoThis is a bad rule and even worse advice.
- Beldur 6y agoFrom the GO Proverbs: ,,A little copying is better than a little dependency." https://www.youtube.com/watch?v=PAAkCSZUG1c&t=9m28s https://www.youtube.com/watch?v=PAAkCSZUG1c&t=9m28s
- SavageBeast 6y agoNever having thought about it before, I realize I usually go the opposite way. By writing about a days worth of code on something - if only to realize its true scope - then going in search of a lib of some kind to handle the dirty bits.
- ChicagoDave 6y agoI've always called this the "guy in the basement" effect. In the beginning, the guy in the basement would have an awesome idea for a library. He would spend 27 hours a designing it, coding it, testing it, and making it awesome. The "guy in the basement" moves out because his partner wants to spend time with him. They start to live lives outside of the world of maintaining open source libraries. The partner asks, "Are you getting paid for all of this?" and the guy says, "No. It's open source. It's a good thing." but in saying it out loud to his partner, his priorities shift. Over the next year, the library deteriorates. It gets forked, other people ask to maintain it, he relents, but no single person has the vision. The library becomes a mish mash of priorities and no longer has the awesome cohesion it once had. Everyone using the library is very sad. Some are angry. An awesome replacement appears from another guy in the basement. The cycle repeats.
- gspr 6y agoI'm sure I could write a basic HTTP client implementation for the current needs of my project in an afternoon. That doesn't mean that I shouldn't be using libcurl or whatever instead, though. It's perfectly reasonable to conclude "my need is a subset of a larger but well-defined task for which there's a bunch of mature, proven and widely available libraries – I should leverage them".
- fwip 6y agoA huge benefit of using dependencies in your codebase is that other members of your team (including future members) have a good chance of already knowing how the dependency works, and how to use it. If I rewrite package Foob because it only takes me 3 hours to write (let's call it Boof), and my colleague Mary on another team also does so, then the chances that our needs, specific implementations & usage patterns are the same, is pretty low. When I transfer to her team six months from now, I have "my" code that I know how it works, and I also have "her" code that I don't yet understand. I've got to relearn the new interface. Or, if we see this as opportunity to unify our needs across codebases/teams, one of our libraries get the features of the other bolted on. In this way, we're just spending our combined time building a less-good Foob, instead of actually doing something useful. But instead, if Mary says that Foob is high-quality because she looked at the code, checked the community, etc, then I can just trust her judgment. Foob already has most the features that I thought I ain't gonna need. I can re-use Foob in multiple projects, and the documentation for Foob is certainly better than what I would have written in an afternoon, so future team-members will also pick up Foob faster than my Boofy custom implementation.
- foobarian 6y agoI had this experience with a particular React hook recently. We ended up with like 5 teams implementing very similar functionality, and then when developer #6 came along and tried to replace them all with a common implementation it broke 2 out of 5 use cases because of very subtle edge cases. I guess React runtime behavior is kind of high on the scale of how hard code is to reason about, so maybe this wouldn't happen in an easier codebase. But still a very instructive exercise.
- dkarl 6y agoI think the mistake described in this blog post needs a name. Let's call it premature dependence. Like premature optimization, premature dependence compounds your maintenance burden over time because you predicted a problem which, if you had waited for evidence, would never have materialized. In premature optimization, you imagine that a simple solution won't perform adequately, so you invest in building a more sophisticated solution up front. In premature dependence, you imagine that a simple implementation won't adequately address your needs, so you bring in a feature-rich dependency right away. Both are driven by the fact that we spend the vast majority of our time, effort, and emotional energy dealing with rare cases. You don't spend hour after hour, day after day, meeting after stressful meeting talking about the database that scaled fine or the code you wrote once at the beginning of the project and never touched again. If you don't account for how the successful stuff disappears into the background, your model of reality will be skewed by rare traumatic events. (Which is kind of the point, evolutionarily speaking, since it serves as a kind of crude risk analysis, but it's not hard to do risk analysis better than your amygdala does.) Of course, applying the rule in practice requires judgment. Some problems are inherently difficult; some explosions in complexity are predictable; you don't have to pay long-term costs on POCs and failed experiments; if you say you support ISO-XXXX format then you had better support every obscure corner case; etc. But it's good to keep in mind that the long-term cost of an extra dependency can be greater than the long-term cost of a few hundred lines of unchanging, unit-tested code.
- pjmlp 6y agoI rather take the afternoon for dealing with business related stuff, documentation, unit tests, architecture diagrams, improving the CI/CD pipeline.
- drchiu 6y agoI mean... this depends. I use Rails mostly in my work, and in recent years I’ve pared down the libraries I would use (ie. that will go into the Gemfile). I generally stay away from any other externalities beside this list of libraries, and so I make it so that they’re almost “my own.” Seems to be a good balance between getting too dependency dependent vs veering off to reinvent the wheel.
- vishnugupta 6y agoObviously each situation is unique, however, I’ve been burned more often by trying to clean up hand rolled out code than using a library. I can recall quite a few instances where engineers, even experienced ones, went down this path ended up trying to reinvent such age old technologies as version control system, web server, just to name two.
- MrStonedOne 6y agoDependencies are part of the same calculations that normal programming follows. Easy to program vs Easy to maintain vs Easy to understand vs Easy to scale vs Easy for the cpu to do. Dependencies are easy to program, you include them. Dependencies are hard to maintain, in that you can't expand or change their behavior. Dependencies can be either hard or easy to understand (compared to your own code). Dependencies are hard to scale, something you coded yourself can avoid validating inputs that have already been validated, or otherwise be smarter about how it does things to avoid overhead. (one example would be a system for parsing info from a large amount of data, most dependencies will make you either store it all in one place on disk or memory, where a custom solution can more easily stream it to avoid memory or disk overhead. (take a ftp server that wants to calculate and store 5 hashes for each of the files uploaded, it can either have 5 libraries each read the file after upload, or it can load the entire file back into memory after upload or it could just stream the info to 5 custom rolled hashing systems that handle calculating the data as its being uploaded and written without needing to re-read it from disk after upload. one will be faster and scale better.)) So half the articles about dependencies on hacker news can be broken down to one message: Don't use a dependency when rolling it yourself is better for your use case. The other half are about conveying why and when rolling it yourself can give you benefits for your use case.
- ak39 6y agoI agree with this philosophy. I see the writer has used popular memes to convey the problem with humour. I would also add this quote from the movie "Heat": "Don't let yourself get attached to anything you are not willing to walk out on in 30 seconds flat if you feel the heat around the corner."
- cmckn 6y agoMany others have mentioned the problem with estimating time cost. I think the core issue is that very few things actually take _only_ an afternoon of programming to build. One good example of this is a general application framework like Dropwizard or Spring. These are relatively giant dependencies; and you could fairly easily do without them early-on in a project (or maybe for the life of a project). But, odds are, you'll spend an afternoon (or several) in the future refactoring to use such a framework, because xyz feature would benefit from that foundation. The judgement call of using it early or late is why we get paid the big bucks!
- earthboundkid 6y agoOP here: A lot of people are objecting, "What if you estimate wrong, and it takes more than an afternoon?" This objection is very bad. It is not possible to add a new dependency in less than afternoon because you need to evaluate alternatives, test it, learn how it works, make sure it's not accidentally GPL, etc. So there are not two methods, the less-than-an-afternoon method and the more-than-an-afternoon method. There are two methods that both take at least one afternoon. If you estimate wrong and you can't write the code in an afternoon… Then stop working on your handwritten version and find a dependency? But now you know what the dependency is really supposed to do and why it's non-trivial, so you're in an even better position to evaluate which ones are good.
- nullc 6y ago> But now you know what the dependency is really supposed to do and why it's non-trivial, so you're in an even better position to evaluate which ones are good. I came in here to say this. If you think you're not qualified to write the function, you're probably also equally unqualified to choose someone else's implementation of it. There is a lot of stuff out there-- stuff which is widely used-- which is not fit for your purposes, ... perhaps not for anyone's. And there is no replacement for a bit of domain expertise.
- Shank 6y agoNot a lot of people can correctly write cryptography code on the first try, but we definitely advocate for people pulling well known cryptography libraries and using them instead of building their own, for obvious reasons. Not many people are qualified to write a lot of things, but are capable of making sound dependency judgements with heuristics. The trick is to use good heuristics and to not use a library for every tiny thing.
- nullc 6y agoIt's my experience that people very often do not make sound dependency judgements on cryptography dependencies. They probably do better than writing it on their own, but that isn't necessarily saying much-- and I think the difference isn't actually that great (essentially the thing they pick will often tend to have same flaws as what they would have written, because essentially we're drawing from the same distribution). I agree that heuristics could help but not much time is spent discovering and socializing what those are, particularly to the extent that they are domain specific. Naive heuristics can also backfire. E.g. it can be easy to mistake contentious behaviour with flaws and end up preferring code that has absolutely zero mitigations against an attack over code that discloses the limitations of their mitigations.
- yoz-y 6y agoNot Invented Here Syndrome[1] [1]: https://en.wikipedia.org/wiki/Not_invented_here https://en.wikipedia.org/wiki/Not_invented_here
- superjan 6y agoI agree with the author in that you should think twice about adding a dependency. I’d be willing to invest way more than an afternoon, depending on the circumstances. Adding a dependency is also work. How much depends on your work environment, so you should think for yourself.
- fchu 6y agoThat's too simplistic and not realistic. I'd rather go for an heuristic that's the dependency management equivalent of "Ask for forgiveness, not permission": 1.Find the best library that is good enough to solve your current needs, double-check to understand its capabilities and shortcomings (to internalize any known future needs), and code against it. 2. Invest the time to build your own stuff only when you start to see limitations in future iterations. By this time you'd also have a battle-tested understanding of both the dependency's shortcomings and your own requirements
- deleted 6y ago[deleted]
- jkingsbery 6y agoIn my 12 year professional career and 10 years of programming before that, I can't count how many times I thought something was an afternoon of programming and I was terribly terribly wrong. Generally good advice to be conscious about taking dependencies, but it's also worth sanity checking that something is really "an afternoon of programming."
- TeMPOraL 6y agoAgreed. One has to learn to be realistic, and account for time spent thinking, debugging and testing when coding from scratch. left-pad is an afternoon project. SQLite connector may be a week project. Full JSON parser? Let's book a month to be safe.
- bob1029 6y agoI agree with this in principle. There is nuance, but the only way I look at 3rd party dependencies is as liabilities, normalizing for function. The only question for me from this point is "Which dependencies are the biggest liabilities for us?" The answer to this question depends wildly on what exactly it is that you are trying to do. Overall, our strategy is to typically use a 3rd party dependency by default in order to quickly get a MVP rolled out. Once we have a clearer picture of how we can solve some particular problem in a concrete way, we make a decision regarding whether we should drop that dependency or keep it around. Most of the time, we will develop an interface which exposes our need for the dependency in a vendor-agnostic way. Then, we can target any arbitrary implementation against this interface and quickly swap them around as required in DI. The biggest question in these discussions is always going to be "Well... how long would it take to write our own?". Even if someone is being realistic and gives you something 2x as long as you were hoping for, you should consider all of the other factors. Keep in mind that if you write it yourself, you can probably iterate on it without much difficulty as well (i.e. custom change requests that a 3rd party would completely ignore). Conversely, if you have to maintain it and its really buggy, you can't hope someone else is going to eventually solve your problems for you.
- spankalee 6y agoFor small dependencies it's often not the implementation that matters as much as the tests. And even if you think you can write all the tests in an afternoon, they're often born out of actual usage, which you can't replicate so easily. I'd say if a dependency is small enough that you can write it in an afternoon, you can even more easily read it's source and tests and decide if it's high enough quality to use as-is.
- blocked_again 6y agoThat's like 90% of NPM.
- kuon 6y agoThis is interesting, because I had this issue. In one java lib I wrote, I needed to build an URL, so I naively pulled apache http common URL builder, got it done in one line, and went on. But a few time later, I realized (well someone reported an issue) that depending on the android version, it would break. My first reflex was to try to bundle just what I wanted using some graddle class renaming plugin, it was a nightmare. Then I just realized how stupid and lazy I had become, being able to just pull dependency for anything made me forgot I could just write the code. In the end I dropped the dependency and wrote what I needed myself. If you are interested, commit here: https://github.com/kuon/java-phoenix-channel/commit/2a3a976d3a189d762c4eac739d7ad824e6ce6380 https://github.com/kuon/java-phoenix-channel/commit/2a3a976d...
- wendyshu 6y agoI'd say the opposite
- jdonaldson 6y agoBe right back, going to delete my html parsers deps and roll my own with some regex. https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 https://stackoverflow.com/questions/1732348/regex-match-open...
- anonymousiam 6y agoWhat about "do not re-invent the wheel"? If you are schedule driven, then you'll want to get the coding done ASAP. Take an action for later to reduce dependencies, and prioritize it appropriately. Also, keep a local copy of the version you pulled and reference that for builds so you are not at the mercy of some maintainer/repository that has no stake in your game.
- wan23 6y agoI once worked for a startup that had a custom C++ basic library for strings, arrays, smart pointers and things like that. At some point I spent the better part of a week looking into a bug that, long story short, was caused by a bug in our custom String class. Please don't do this. Every line of code in your project that your team maintains is a liability.
- KaiserPro 6y agoyeah nah, life is far too short for that. Part of the reason why I use python is not because its "brilliant" its because it has most of the stuff you need built in. I'm too old for supporting my own tech debt. Yes, its slow, yes there are bits that stink of poo. But 95% of the time there is something that'll do the job, most of the time. I'm not going to put my self on the hook for supporting the 0.5% cornercases the appear in 85% of all incident reviews. Should I need something specific, then of course I'll write it, but only after google has said no, or the libs I've found don't work. Its a silly rule, and I imagine stems from a young buck wanting to prove them selves. Thats great, but I finish at 17:00, and I don't ever intend on staying late. I suggest everyone tries it at least once. It'll make you a better engineer, honest.
- ChrisMarshallNY 6y agoI tend to avoid dependencies, if at all possible. I wouldn't mind spending a week of programming to avoid some dependencies. Of course, there is no "one size fits all" rule, here. If it's a "one-off" internal tool, without much impact, then it would not be worth spending much time on, and a dependency might be exactly the right thing (famous last words). I'm pretty obsessive about quality, and like to ensure the best quality possible in all my work. The weakest link, and all that, so dependencies need to be vetted very carefully. There's some things that just can't be done without dependencies; sometimes, crappy ones (like SDKs), but that's less frequent than you'd think.
- therealdrag0 6y agoThat's interesting. Kudos for your craftsmanship. IME those who write code instead of using a dependency are those who DON'T seem to care about quality. They can't be bothered to see if the problem is already solved. They can't be bothered to design a good interface and extract the code into a re-usable module. Just just solve their own immediate problem, which then gets re-solved in different ways a dozen times in different projects in the company. This is what I find frustrating and what I find 3rd party dependencies protect against. They define a set of culturally accepted/known APIs/Functionality that is consistent and doesn't have to be relearned between repositories.
- ChrisMarshallNY 6y agoIn my experience, I have seen some Jurassic-scale disasters, because of poor dependency choices. I think a lot of people just google for dependencies, and then add the first one that has a slick Web site, without thinking much about the code they are adding. I am not a "never dependency" person, but I am anal about quality. Totally obsessed. I feel that quality is something that many, many programmers eschew, in favor of bling and buzzwords. For me, I won't put my seal on something until I have tested it six ways to Sunday. In some cases, it may be unit tests, but, more often, it is a test harness, which can be a much more ambitious project than a few XCTests[0]. In fact, I am running into a lot of folks that don't know what a test harness is; which is jaw-dropping. Since I do a lot of device control stuff, unit tests are not particularly useful. In order to create unit tests that would be effective, I'd need to design a huge mock, and that would not be worth it; likely introducing more problems than it solves. An example is that I am currently developing a cross [Apple] platform Bluetooth LE Central abstraction driver[1]. This needs to have test harnesses in all the target systems (iOS/iPadOS, MacOS, WatchOS and TVOS). I actually have it driving a released app[2] (which is really just a "productized" implementation of the iOS test harness), but I do not consider the module ready for release, as I have not completed all of the test harnesses. I am in the middle of the WatchOS harness now. I may "productize" the MacOS test harness. My test harnesses are really serious bits of code. Complete, ready-to-ship apps, for the most part. Going from a test harness to a shipping app isn't a big deal. [0] https://medium.com/chrismarshallny/testing-harness-vs-unit-498766c499aa https://medium.com/chrismarshallny/testing-harness-vs-unit-4... [1] https://github.com/RiftValleySoftware/RVS_BlueThoth https://github.com/RiftValleySoftware/RVS_BlueThoth [2] https://apps.apple.com/us/app/blue-van-clef/id1511428132 https://apps.apple.com/us/app/blue-van-clef/id1511428132
- hyperpallium2 6y agoClarify: actually within an afternoon, not looks-like an afternoon (include debugging, testing, docs, api design, etc see Brook's 3x). So, e.g. leftShark().
- wwright 6y agoNever spend an afternoon programming something that you may have to waste future time debugging and supporting when a dependency already handles it perfectly.
- jaeming 6y agoI once decided to write my own UI pagination component. I thought it would be fun and, why bring in a library for something so simple? Three years later, we now use this component for all our pagination. Probably four of us know it really well by now as it turns out, there have been many bugs around it. Turns out pagination was not such a trivial problem to solve when you consider all the edge-cases and crazy PM requirements. Every once and a while some engineer who's fixing a bug on it will ask, "why in the world did we write this? Why don't we just use this bootstrap pagination instead?". I ask in return, "would it fix the bug you currently have with it?". Every single time the answer has been no. It's almost always centered around the state of how the parent component is using it. I wrote with the intention of using querystrings to store pagination state in the url, but someone else at some point decides to store their pagination data in memory and just adds a few props and now it's doing it two different ways, etc... I think the criminal offense here was not writing pagination from scratch. It was that I didn't extract it into a library and write some basic documentation.
- akvadrako 6y agoIt does sound like you’re agreeing with the premise of the article. Pagination is hard but it’s even harder to find a library that meets all your requirements and doesn’t have bugs.
- rurp 6y ago> Many times, the best approach is first searching online and reading the code to a few other solutions, then writing your own with the knowledge you’ve gained from seeing how they work. I think this is a great approach. Any general solution library will be much larger and more complex than one project's use case. Seeing how other people have solved a given problem can give a dev a nice jump start on creating a compact solution to their given problem. For whatever reason many devs just love using dependencies and almost always underestimate the long term costs, in terms of maintenance and vulnerability risk. I once had to write a simple utility script that was literally 5 lines of Python. All it did was loop through a list and perform a couple simple actions. As I mentioned it to the PM, another dev jumped in and said, "Oh hey, there's Library_X that we can install that will totally handle that for you". I responded that the library could very well be great, but script was already done, had only taken about 15 minutes to write, and would be very easy to reason about and update down the line. Reading about and implementing a whole new library to do the same thing just didn't seem useful. The other dev sounded unconvinced.
- alephu5 6y agoIn my experience this is quite typical in the python community, I think it's a consequence of the batteries-included philosophy. Many people are very averse to using primitive data structures and operations to solve their problems, so working with a python codebase is like gluing libraries together
- Igelau 6y agoBRB, going to go roll my own AES -- what could possibly go wrong?
- nullc 6y ago> BRB, going to go roll my own AES -- what could possibly go wrong? Probably not much more than picking an AES library written from someone else. It's fairly unlikely that your custom AES would function at all unless it was functionally correct. Your bespoke AES will likely have timing sidechannels, but so will most AES you go pick off the shelf. (in fact, if you happen to need CBC mode, virtually any AES you pick off the shelf will end up having timing side-channels, because most code that doesn't is GCM only)-- particularly because it's hard to be both high performance and side-channel free without using SIMD, and to do that you need to operate on multiple blocks at a time. In fact, since you happen to know your environment is targeting only hardware with AES-NI (in my hypothetical), you'll just use that and you'll even be free of side-channels too. The "abstinence only cryptography" advice was originally about inventing your own blockciphers and such, not implementing existing ones. Okay so you're smart and so you'll want to go take your AES from some highly reviewed sourse with lots of smart people. You pick.. say.. the Linux kernel. Welp if you picked the plain C implementation in it, congrats, you just got yourself a bunch of timing side-channels. There are, of course, plenty of things that can go wrong in making your own implementations-- so it's not entirely misplaced to apply it to implementations-- but sadly you are not more likely to avoid them by simply picking one written by someone else. If you understand the domain then you can select a good library and evaluate it, but if understand that you could likely also write your own. :( On the plus side, a simple blockcipher isn't the sort of dependency that is likely to have a substantial on-going cost either. It won't randomly change its behaviour (we hope, at least not until haxors take over the upstream repository), its functionality is simple and well specified, etc. So it is probably fine to use one from a library and the OP's advice doesn't apply. But all the reasons why the code you wrote would probably be broken? They probably still apply to the library.
- Igelau 6y agoYes, yes, yes, and yes, but the crucial difference is that vulnerabilities in the library are more likely to have the benefit of disclosure.
- idreyn 6y agoA year ago I needed a min-heap to build a priority queue at work. So first I grabbed 'heap' from npm (272k weekly downloads) and set it to work. But a few days later I realized my code was executing slower than expected because it sometimes needed to clone the data structure, and the clone instantiation would break the heap invariant in the array internals. It turned out there's been an issue open about this since early 2017. Then I went for the 'collections' package (35k weekly downloads) and brought in its heap implementation. That worked like a charm for about six months until a bug came in that made it seem like a completely different package was breaking. After almost a whole day of debugging, it turns out that 'collections' silently shims the global Array.from function (scream emoji) without mimicking its behavior when dealing with non-Array iterables presented by the other package. So finally I wrote my own heap -- well, I cribbed from Eloquent JavaScript [0] but I did have to briefly remember a little bit about how they're supposed to work. So while I don't totally buy the "Never..." rule in the post title, thinking more carefully about writing versus importing a dependency would have saved me a great deal of headache in this case. [0] https://eloquentjavascript.net/1st_edition/appendix2.html https://eloquentjavascript.net/1st_edition/appendix2.html
- 5Qn8mNbc2FNCiVV 6y agoThis would be a perfect spot to solve those issues and make the packages better... Or y'know, publish your implementation and have it used by people with the same issue
- newen 6y agoWow. Could not be more glad I’m not in the javascript world.
- gauchojs 6y agoAfternoon = around 10 lines of code
- loup-vaillant 6y agoThose are reason why I like small "single" file libraries in C and C++ (one header, one source file): you know where the source code is, reviewing it is relatively painless, and adding it to your project is dead easy. Yet I have seen people ignoring the benefits of a 2K lines dependency (in a single compilation unit), over an otherwise equivalent 20K lines dependency (in 100 compilation units) that requires the autotools. (The disadvantages of a particular lightweight dependency is a separate topic.) You want your modules do be deep: minimum interface for maximum functionality. Dividing the size of an interface by 10 for the same functionality is a pretty sweet deal in most cases. In my opinion, that deal is often underrated.
- pldr1234 6y agoNever take afternoon advice from a programmer about how to run a business. Because at the end of the day, that's what team management and engineering teams are. Functional units of a business. And advice like the OP's will lead you to death by a million shed bikes. But for side projects, sure, have fun with it.
- jjav 6y agoAdding a dependency is like adopting a puppy. Sure it seems free.. but it's not. It may be the best thing to do, but go in with eyes open on the costs. Something like left-pad, absolutely never worth it. Something like OpenSSL, basically always worth it (warts and all). Everything in the middle, evaluate carefully. When adopting a dependency you're adopting all their development practices. Do they break backward compatibility every minor release because compatibility is for the boring people? Never address CVEs? Every additional dependency constrains your future self by a little bit. These add up.
- Azatik1000 6y agoTotal bullshit
- methodin 6y agoTime it takes to build something is not even remotely the best metric for value or ease. Programming is never a box and things that took one afternoon to write at first could be thousands of lines long a year from now. To me this is as horrible as advice as it is to use dependencies for everything.
- rndmze 6y agoI am biased because the ecosystem I work on most of the time has good libraries for important stuff (hint, not javascript). I am not sure how this advice is supposed to work though : the number of problems that are solvable "in an afternoon" is very small. Especially the problems I know will take only an afternoon to solve and won't need to be maintained afterwards.
- zby 6y agoOn average programmers produce average quality of software. Libraries available online are often shitty - but most probably they are still over the average quality of all software, because there is a selection bias and more people are looking at them etc. So if average programmers replace average libs - then the expected result is that the overall quality of software would go down.
- moron4hire 6y agoEspecially when it comes to JavaScript, I tend to follow "never use a dependency that you could replace in a month". Here is something that has happened to me more times than I care to count: I have a dependency on some library. It's working well for me. I build some sort of small project with it, like the info website for my mother's business. Doesn't need to be updated very often, just needs to be there and have her contact information. A year later, I get some automated email telling me some dependency of a dependency of my dependency has some kind of obscure security issue. I'm busy. This project isn't supposed to be a core, constantly making project. I don't really have time to evaluate if the problem is an issue for me, so I go to just upgrade everything and appease the squawk box. Oh, turns out that in the time between when I used the library and the security issue was discovered, the developers have completely redesigned the whole thing and the only version that includes the security fix is a version that isn't compatible for my config scripts anymore. All because I didn't want to spend the time to write some stupid simple string concatenating code for writing an HTML template, I now have to spend time completely relearning this library. And probably rebuilding the build scripts, too, because nobody can just leave well enough alone. "Oh, but if you wrote the code, you might have written a security bug, too". And I could fix it on my own, too. When did programmers stop programming? Most of the arguments I see for ridiculous levels of package integration come from a place of devs not trusting themselves to write stupid simple code. Like left-pad. "Someone smarter than me has figured at all the edge cases". You don't need all the edge cases. You need to just learn how to do your job.
- AtlasBarfed 6y agoJavaScript, capitalizing the W in "worse is better".
- browsergap 6y agoI like this, but not things I wrote instead of using existing lib took weeks, not an afternoon. And I didn't think they would take an afternoon. If it's trivial, probably use existing lib. I don't know what my rule for deciding this is....I don't think I have one. I just make decisions. If I don't like a library I won't use it.
- ChrisMarshallNY 6y agoI should mention that one thing that I always do with dependencies, these days, is encapsulate them. I use things like Dependency Inversion or Dependency Injection, or simple "glue" APIs. This is from being burned by integrating dependencies into my projects, and painting myself into corners. It helps to do things like swap out DB backends, or things like mapping libraries. YAGNI is important, but it's also important to encourage flexibility. Dependency encapsulation is pretty much perfect for that. Of course, there are probably cases where it's impossible to use some dependencies without making them integral parts of the project, but it's been my experience that I can write lots of stuff, based on modules. My work is basically a clump of dependencies; it's just that I wrote the dependencies. I like modular architectures, with each module/layer as an independent-lifecycle project; complete with testing, documentation, and APIs. Takes a bit longer to write the modules, but the integration is quite smooth.
- rsanek 6y agoDoes it really take people "a few hours" to integrate a dependency? For personal projects it's more like 15 minutes, and even for stuff at work it doesn't generally take longer than an hour. Broadly I find that FOSS libraries are great when you stick with their happy path. If you have unique/specific requirements, it may make sense to build it yourself. But there's no reason you can't spend an hour trying to use something for free before re-writing from scratch.
- BenoitEssiambre 6y agoCarmack weights in: https://twitter.com/ID_AA_Carmack/status/1293311943995002881 https://twitter.com/ID_AA_Carmack/status/1293311943995002881 "This HN discussion https://news.ycombinator.com/item?id=24123878 https://news.ycombinator.com/item?id=24123878 is topical for me: at this very moment, I am implementing C++ MFCC code myself, because my attempt to integrate Kaldi (on windows) was unpleasant. It already took more than an afternoon, but I learned good things! \ I'm more sympathetic to the Use-All-The-Dependencies crowd than some might suppose. It definitely isn't my way, but I see them as a fellow subclass of programmer, evolved for other environments. It is amazing what can be cobbled together in a weekend now. \ The old Knuth vs McIlroy story is relevant: http://leancrew.com/all-this/2011/12/more-shell-less-egg/ http://leancrew.com/all-this/2011/12/more-shell-less-egg/ Generally, use-the-tools is correct, but sometimes you really do want a Knuth (or maybe a Carmack)." "
- andrewstuart 6y agoWhen Carmack speaks it's worth listening to. However in almost all cases, you - the reader - cannot achieve in an afternoon what Carmack can achieve in an afternoon. Few developers have the ability to build an alternative to a speech recognition dependency.
- kseifried 6y agoDunning-Kreuger, the long and short of it is many problem appear "simple" and take an afternoon.. right? For something that converts a date from ISO format to American (M-D-Y) sure it might be simple, but anything that listens or talks to the network (DNS? APIs? etc.) I guarantee you didn't think of all the corner cases. Also all those afternoons add up. Also the comment "You’ll know exactly how it works and what its shortcomings are." Hahahahaha. no. If that was true bugs wouldn't be a thing.
- AtlasBarfed 6y agoSo... why not just take the source of something you like and include it? Probably if one "thinks" they can do it in a half an afternoon, you can look at the source of something that simple for two or three things and just clone/renamspace/whatever to the source.
- timoth3y 6y agoI agree with the spirit of this article. However, the problem is that most of the time when we think "I could build that in an afternoon!" we are underestimating the complexity involved. Sometimes it takes an afternoon of coding and months of debugging.
- pacifika 6y agoAt lest in web development, the website is always changing thus so is the code. Therefore the maintenance burden favours bespoke code over libraries as the former is easier to adapt to changing requirements. However ultimately in reality a decision based on product ownership culture, when it’s more important to produce results now ( velocity) rather than in a few months time (maintainability). It’s hard to change culture.
- luizfzs 6y agoIt works great up to the point that you have one week to deliver a feature, and that one afternoon is the difference between you delivering a half-tested or well-tested feature. Also, as pointed by other comments, people are generally not good at estimating.
- luord 6y agoControversial to say the least. While I know the value of in-housing as much code as possible; I only think it should be done once (https://luord.com/2016/06/25/nih https://luord.com/2016/06/25/nih). After that one time, I've strove to limit the in-house code only to the actual domain and business rules of the application/system.
- flavious 6y agoMy rule scales with the scope of the dependency: "If you think that creating a wrapper around the library is too expensive, then the dependency is not worth having".
- kova12 6y agoI would actually advise another way: if you have to waste the whole afternoon putting algorithm together, then it probably going to be a week after you implement all tests and fix all the bugs. But even if it was just afternoon, still not worth it. You don't want to maintain what you don't need to maintain
- ezekg 6y agoTypical programmer, wholeheartedly believing they can build a something in an afternoon and be done with it. I don't care how well you scoped the project -- it almost always takes longer. It's naive and all this does is cost businesses time and money. It's usually much more economical to go with a third-party than to build everything in-house, which needs to account for the costs of new-feature dev and long-term maintenance. I have an entire business running on that premise.