News for hackers. Stuff that matters.
Re:Never use a dependency that you could replace with an aft... by sparker72678 on Tuesday August 11, 2020 @03:30PM (#24124867)
Probably good advice, but when was the last time a programmer accurately scoped a problem when they said it will take “an afternoon” to build?
Re:Never use a dependency that you could replace with an aft... by andrewstuart on Tuesday August 11, 2020 @03:46PM (#24125099)
I came here just to say this.

"This'll take an afternoon" - three weeks later......

Programmers are notorious for this.

BUT even apart from this problem ... you absolutely should use every dependency you can that will save you time.

Try to write less code not more. When you write code you write bugs, add complexity, add scope increase need for testing, increase the cognitive load required to comprehend the software, introduce the need for documentation..... there's a vast array of reason to use existing code even if you truly could estimate it and build it in an afternoon.

You also assume that you understand all the edge cases and fickle aspects of the dependency, all the weird ins and outs that the dependency author probably spent much resources understanding, fixing and bug hunting.

There's a hard fact that proves the above poster to be wrong..... how many dependencies took only an afternoon of time in total to write? Hard to say (maybe look at the github commit history) but I'd guess almost none. It didn't take the dependency author an afternoon, so why will it take you an afternoon?

Even worse .... you just lost an afternoon coding features for your core application.

Multiply this by every dependency that "you could build in an afternoon" and you'll be in Duke Nukem Forever territory.

I'd advise doing the opposite of this articles suggestion.

Find a dependency that will save you an afternoon? Grab it.

Re:Never use a dependency that you could replace with an aft... by VHRanger on Tuesday August 11, 2020 @04:00PM (#24125270)
Found the NPM user.

Dependencies have costs:

- Dependencies break over time. They have a nonzero maintenance cost.

- They impose API boundaries on you that may not fit your existing data structures

- It's harder to change underlying bugs

- They might introduce security issues

Sure, use dependencies. But there's a reasonable position between "never write any code" and "never take on dependencies". Of which NPM is one of the only ecosystems being at one extreme.

Re:Never use a dependency that you could replace with an aft... by BigJono on Wednesday August 12, 2020 @02:46AM (#24129213)
This is pretty much spot on. Except you also missed the main cost, which is the insane amount of time it takes to learn the 85 dependencies on your project to an extent that you actually understand what your code is doing.

Every single project I go into seems to have a smorgasboard of dependencies, then when I take the time to investigate one of them I find out it's being used incorrectly by at least 50% of the team because they don't even understand how they work at the most basic level. Which is pretty understandable because by the time anyone gets through understanding 10 of the 85, they've probably been kicked off the team for not actually building anything.

People love to say rubbish like "write less code!", as if LoC is the only metric that matters (weren't we past that thought process by the 90s?). Which goes a long way to explaining all the fucking terrible codebases I have to work with where it's impossible to accomplish anything without reading documentation for 8 hours, when it would take 20 minutes to just read even a semi-readable piece of code that implements whatever requirements you need from the dependency.

Re:Never use a dependency that you could replace with an aft... by greyhair on Wednesday August 12, 2020 @08:55AM (#24131559)
But then lets talk about internal dependencies.

On a C code project for a large Fortune 100 company a half dozen years ago, I encountered a pesky header include that made no sense. And that header was part of a patch that I really did not want to pick up, so I started digging into it.

Turns out that they had some constant in the code, and the developer just did a grep for that value in the source tree, and that constant already existed in an existing header file, so they just included it.

And that CONSTANT_VALUE_STRING had nothing to do with the technology that the C source was addressing. So some lazy slacker pulled in a random header file that contained the proper constant value for an unrelated technology.

The dependency on that was pure lunacy on so many levels.

And that was an internal dependency, not an external library.

So the lesson here? Not all dangerous dependencies are external.

Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @04:42PM (#24125735)
I could say all of the same things about the in house tools that the “architect” wrote three jobs ago - including the bespoke ORM, object mapper, and logging framework.

Or two jobs ago where two developers who had worked at the company for 10 and 15 years respectively were maintaining a bespoke 15 year old EHR written in PowerBuilder and depended on SQL Server 2003 - in 2016.

Every company thinks they are their own special snowflake where cross cutting concerns can’t be handled by a third party.

Re:Never use a dependency that you could replace with an aft... by JackFr on Tuesday August 11, 2020 @04:54PM (#24125864)
I’ve worked with dozens of guys who loved to reinvent config and logging frameworks, because ... I don’t know why.

I suppose because it was easier than working in the actual problem domain, which they knew little about and didn’t care to learn.

Re:Never use a dependency that you could replace with an aft... by nothal on Tuesday August 11, 2020 @06:06PM (#24126577)
Herding devs to work on the boring-useful things instead of the interesting-solved things is slightly easier than herding cats.
Re:Never use a dependency that you could replace with an aft... by karmakaze on Tuesday August 11, 2020 @09:31PM (#24127787)
Funny you should bring up these as examples. I've made (1) and (3) using an existing object mapper. They were made out of limitations with JPA/Hibernate and for higher-level functionality in logging. The ORM was never sent to prod. The logging events were gold. Specific events were 'major' and filtering on a user ID in a narrow timespan could show the expected/unexpected events for the traces as a sequence diagram through all the microservice layers. Clicking on an event then searched Loggly for all logs for trace-id at time. It got to the point that non-techs were answering customer issues with it and we hardly had to check/wait for Loggly to answer.
Re:Never use a dependency that you could replace with an aft... by andrewstuart on Tuesday August 11, 2020 @04:04PM (#24125325)
>> Found the NPM user.

Ya got me ... pypi, crates, NPM, gems, cpan I'll use em all! Shhhh.... if my employer finds out they'll fire me.

:-)

Re:Never use a dependency that you could replace with an aft... by parliament32 on Wednesday August 12, 2020 @02:14PM (#24135006)
Everyone who's used NPM in production for a not-insignificant amount of time has realized just how bad nodejs dependency hell can be. Unfortunately, webdev-du-jour has decided pulling in a hundred npm packages is better than writing a few hundred lines of code.

I keep hoping things like [1] are a joke but I'm starting to suspect they're not.

[1]https://www.npmjs.com/package/is-odd

Re:Never use a dependency that you could replace with an aft... by 5Qn8mNbc2FNCiVV on Wednesday August 12, 2020 @06:42PM (#24137930)
I'm sorry that my framework and bundler are using so many packages. Lemme just quickly install Android Studio and download a few gigabyte to develop and build my application. Ah yikes I'm on a different version, need to redownload now.
Re:Never use a dependency that you could replace with an aft... by parliament32 on Thursday August 13, 2020 @01:05PM (#24145572)
At least Android Studio doesn't break when you try to deploy it a few months down the line (with package lock), with the exact same version, because a dependency of a dependency of a dependency made an unreviewed and untested "security fix" that caused a regression.
Re:Never use a dependency that you could replace with an aft... by misterpurple45 on Thursday August 13, 2020 @05:21AM (#24141423)
And the is-odd package.json requires is-number! Jesus...
Re:Never use a dependency that you could replace with an aft... by ori_b on Tuesday August 11, 2020 @03:58PM (#24125246)
And when you run into a bug or design problem in a dependency of a dependency of a dependency?

It often takes less time to write some code than to understand someone else's code.

Most programmers I've worked with get lost easily when jumping through layers of other people's code. I certainly do.

Solid, well tested dependencies that solve hard problems are worthwhile. But dependencies have a cost in debuggability and maintenance, so it's worth using them with care. And often, they aren't worth the time, when compared to writing a dozen lines of code.

Re:Never use a dependency that you could replace with an aft... by eberkund on Tuesday August 11, 2020 @04:36PM (#24125669)
I get easily lost jumping through layers of code written by corporate developers in an afternoon. I generally don't have problems jumping through layers of popular, well documented and single-purpose third-party libraries.
Re:Never use a dependency that you could replace with an aft... by quest88 on Wednesday August 12, 2020 @12:24PM (#24133644)
Cross that bridge when you get there.
Re:Never use a dependency that you could replace with an aft... by kjeetgill on Tuesday August 11, 2020 @03:59PM (#24125254)
While I agree that if you think it'll just take an afternoon, for the sake of this article it had better!

But conceding that charitable assumption to the article, I agree with its basic premise: dependencies cost a lot of time in diffuse, non-codey ways.

There are AAA dependencies you pull into every project, but most other dependencies require a good degree of due diligence, evaluation, risk, and their own long-term maintainance.

Its not that it always tips the scales all the way to 'roll your own', but I think the cost of new dependencies is underrated.

Re:Never use a dependency that you could replace with an aft... by greyhair on Wednesday August 12, 2020 @09:22AM (#24131797)
But that analysis is part of the design process on the front end. You don't just 'take' libraries or utilities without evaluating them. And you don't just write bespoke libraries without thinking about the APIs.

So do your upfront work, by all means. It isn't an all or nothing decision.

Re:Never use a dependency that you could replace with an aft... by avmich on Tuesday August 11, 2020 @03:57PM (#24125226)
> you absolutely should use every dependency you can that will save you time

> Find a dependency that will save you an afternoon? Grab it.

Agree. The point of the article, though, is that dependencies are often saving much less time than they promise - so much less that it's better to avoid them.

Re:Never use a dependency that you could replace with an aft... by nomel on Tuesday August 11, 2020 @04:03PM (#24125313)
> "This'll take an afternoon" - three weeks later...... > Programmers are notorious for this.

From my experience with these personal failings, the problem usually comes from the question being phrased in the context like, "before you begin working on this, how long do you think this will this take you to complete?". If there's no opportunity to scope, with requires not insignificant work towards the solution, the estimates will always be wrong. If I understand the actual scope of the problem, which means have the architecture mostly worked out, and have a bit of experience (and luck), my estimates can be pretty close, usually eaten up by that oh-so-seductive feature creep that ruins my work file balance.

Re:Never use a dependency that you could replace with an aft... by OJFord on Tuesday August 11, 2020 @05:50PM (#24126439)
I recently read through the (free online) 'book' on Basecamp's 'shape up' methodology; I thought the 'hill chart' describes this really well - the work needs to be in progress going up the hill discovering what it's all about, before you get to the top and can accurately assess how much 'real work' (!) there is to do, and then it's all downhill from there.
Re:Never use a dependency that you could replace with an aft... by tome on Wednesday August 12, 2020 @07:04AM (#24130698)
> the (free online) 'book' on Basecamp's 'shape up' methodology

FTI: https://basecamp.com/shapeup

Re:Never use a dependency that you could replace with an aft... by scrozart on Tuesday August 11, 2020 @03:56PM (#24125214)
Exactly. I'm not reinventing the wheel. I may write some convenience wrapping around Spring Security, for instance, but why would I rewrite auth-z when it's a solved problem?
Re:Never use a dependency that you could replace with an aft... by vlovich123 on Tuesday August 11, 2020 @03:55PM (#24125210)
Depends how your dependency management system works. Some times it can take an afternoon or more just to integrate it into your build for c/c++
Re:Never use a dependency that you could replace with an aft... by avmich on Tuesday August 11, 2020 @04:00PM (#24125274)
Somehow here we assume a good programmer routinely makes errors in time estimation by an order of magnitude, yet conveniently forget cases when, say, a non-trivial GPL library is embedded as a dependency into a project, and customer is asking for code, and legal team runs with hairs on fire because company didn't plan to release the code...
Re:Never use a dependency that you could replace with an aft... by greyhair on Wednesday August 12, 2020 @09:33AM (#24131902)
But that is a completely different topic. Licensing is an issue, yes, but that is part of the upfront decision process.

In this day an age, this many years into open source licensing, if your team is not on top of that from day one, they have failed as a team.

I worked at Bell Labs from the mid 1980s to 2000, and by early 1990s (1992? 1993?) they already had a full internal team dedicated to open source licensing issues, including training and consulting. That was 27 or 28 years ago. Before some of the developers on this thread were even born.

Re:Never use a dependency that you could replace with an aft... by loup-vaillant on Tuesday August 11, 2020 @06:14PM (#24126650)
> you absolutely should use every dependency you can that will save you time.

Absolutely. As long as it does save you that time over the foreseeable lifetime of the project. Or you are deliberately incurring a technical debt because of some deadline.

On the other hand, saving an afternoon (or even a week), over the next two weeks means very little.

Re:Never use a dependency that you could replace with an aft... by kosievdmerwe on Wednesday August 12, 2020 @02:26AM (#24129107)
Essentially, it'll take you an afternoon to write and then weeks of work properly fixing the bugs and handling the edge cases. Potentially and probably, while you're trying to do something else.
Re:Never use a dependency that you could replace with an aft... by acdha on Tuesday August 11, 2020 @03:35PM (#24124938)
That was my first thought: I've seen these projects before — they're where you find 5 slightly different implementations of similar logic, no logging or tests, failures as soon as someone uses Unicode, etc. and I get an order of magnitude performance improvement by replacing that code with an external module which has had the other 19 afternoons' worth of work it actually takes.
Re:Never use a dependency that you could replace with an aft... by avmich on Tuesday August 11, 2020 @03:53PM (#24125181)
> and I get an order of magnitude performance improvement

Have you heard the adage about premature optimization being the root of all evil? Yes, even with the second part. What is the premature optimization here, in your opinion?

Most of cases developers create something new - that's the state of industry now, not too good but it's how it is. If you'd be refactoring the existing code - sure, find the problem, design the solution, have reasons going from A to B. If, however, you're writing new functionality, you don't know if you'll have problems of this kind with this code - so optimize for developmentality. You can remove those excessive crutches later - if and when you need them. In my experience, having them trumps looking into code and spending time figuring what it does mere months later - your own code, that is.

Re:Never use a dependency that you could replace with an aft... by acdha on Tuesday August 11, 2020 @04:46PM (#24125776)
The point was that when something is large enough to be “an afternoon”, it's probably more work than you're expecting and you haven't yet discovered important details. If there's something which does what you need, it's far more likely that _other people_ have invested time sanding off the rough edges which you have yet to discover.

If it's not hard to use that library you're probably better off unless it's a problem you understand very well and will see a real advantage to tackling differently. For example, if you use a library and don't like it that experience will still be useful for having clarified what exactly it is that you want to do and the rough size of what you're taking on.

Re:Never use a dependency that you could replace with an aft... by rini17 on Wednesday August 12, 2020 @12:40PM (#24133825)
But that is with ample benefit of hindsight.
Re:Never use a dependency that you could replace with an aft... by greggman3 on Tuesday August 11, 2020 @04:52PM (#24125842)
It really depends (haha) on what it is. I needed to copy a file in npm scripts. can't use `cp` because that fails on windows. I looked on npm to copy a file. First hit 197 dependencies, 1170 files, 47000 lines of JavaScript.

all I needed was

    const fs = require('fs');
    fs.copyFileSync(process.argv(2), process.args[3]);
Taking 197 dependencies means 197 things that need updates several times a year at a minimum. Any of those updates could break my code, introduce a bug, add a vulnerability on top of the ones already in the packages. So it's not like adding more dependencies is magically free.
Re:Never use a dependency that you could replace with an aft... by hinkley on Tuesday August 11, 2020 @05:41PM (#24126344)
In the interests of some sanity, I would like to say, all in one spot, that these are not mutually exclusive

- You should absolutely use community-supported tools to solve your problems.

- You should substitute idiomatic code for libraries.

You have made an argument for the latter that does not detract from the former.

Re:Never use a dependency that you could replace with an aft... by greyhair on Wednesday August 12, 2020 @09:41AM (#24131973)
This needs about 1000 upvotes. So much truth in so few words.
Re:Never use a dependency that you could replace with an aft... by benibela on Wednesday August 12, 2020 @05:14PM (#24137070)
Copying a file is really hard to implement

Lots of things can go wrong when writing a file: https://danluu.com/deconstruct-files/

Re:Never use a dependency that you could replace with an aft... by s3cur3 on Tuesday August 11, 2020 @06:30PM (#24126758)
I’ve been working on the same medium-size (fewer than 1M LoC) codebase for about 7 years now. I feel like over the years, my estimates of how long something will take have gotten better for one reason: I’ve found the scaling factor I have to apply to my intuitive estimate that brings into the realm of reason.

So, if I think something looks like about a day’s work, I’ll actually estimate it at about 3.5 or 4 days. Thus, for a project to qualify as “just an afternoon,” I’d have to naively estimate it at under an hour.

I rarely have time to spare, but I also rarely go over by more than maybe a third.

Your multiplier may vary depending on how horrifying your codebase is. On a side project with good test coverage, my multiplier is only about 2.

Re:Never use a dependency that you could replace with an aft... by jeffbee on Tuesday August 11, 2020 @04:30PM (#24125616)
This goes both ways. When was the last time someone properly scoped the maintenance effort of an external library? This goes double for external systems, like kafka or mysql. I've never seen anyone so far even get within two orders of magnitude of the real cost of operating kafka, much less an organization that accurately compared that to the cost of DIY.
Re:Never use a dependency that you could replace with an aft... by kiawe_fire on Tuesday August 11, 2020 @08:50PM (#24127587)
The "don't reinvent the wheel" argument often acts as though using a 3rd party lib is "free", and building it yourself is costly with no benefit.

This is sometimes true, but often not. From SFTP libraries to SVG rendering libraries, there have probably been about 3-5 major dependencies of my company's project that I have had to learn and extend or fix bugs in to make them work just in the last year.

And sometimes this means using our own fork that we have to keep maintained.

I'm not saying I would have rather written these particular dependencies from scratch, but they were definitely not cost free. Nor are they all of better quality than what I would have produced had I written them from scratch.

That's the other common refrain - to "defer to the expertise of the crowd".

Don't get me wrong, many 3rd party libraries are of great quality by amazing men and women who I am very thankful for. But certainly not all of them.

There's no magic that says "every third party library is made by an expert with the highest standards".

Re:Never use a dependency that you could replace with an aft... by tluyben2 on Tuesday August 11, 2020 @03:33PM (#24124899)
That 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.
Re:Never use a dependency that you could replace with an aft... by axlee on Tuesday August 11, 2020 @03:39PM (#24125010)
Is 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;
}
Re:Never use a dependency that you could replace with an aft... by ghj on Tuesday August 11, 2020 @04:03PM (#24125312)
This is so hilariously overengineered: not failing when passed the wrong types, arbitrarily caching padding of len < 10, etc

The most egregious is the bad big O analysis for a pointless binary search. The loop does indeed run O(log(n)) times but `ch += ch` still takes O(ch.length) which is growing exponentially. It ends up being a complicated way of still taking O(n) time while creating a lot of intermediate strings.

It isn't any faster than just creating the padding with a loop or `new Array(len).fill(ch).join('')` or `ch.repeat(len)`

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @04:23PM (#24125538)
Did you run benchmarks to validate those assumptions? The developers of left-pad did: https://github.com/left-pad/left-pad/blob/master/perf/perf.j...

It's not overengineered if thousands of downstream projects are relying on it, some of which might see significant benefits from those performance optimizations.

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @04:42PM (#24125746)
Too bad that's a flawed benchmarking methodolgy. JITs are notoriously hard to correctly profile and the benchmark lib isn't even sort of doing the right thing.

For example, it's missing warmup. The results aren't being consumed in a way that wouldn't optimize them away. The framework itself imposes a pretty large amount of overhead (moreso than I'd expect from leftpad).

It is somewhat likely that what they are measuring isn't leftpad performance, but rather how fast the JIT ends up optimizing the benchmark code.

I'd suggest watching this video https://vimeo.com/78900556

It's about microprofiling the JVM, but the principles are the same for other JIT based languages (such as javascript).

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @05:01PM (#24125922)
Yeah benchmarks can be much more difficult to get right than it might seem at first glance. Good thing they didn't try to write their own benchmarking code, otherwise they might have fallen into those traps you just mentioned.

Luckily, they didn't, and instead pulled in the the `benchmark` library as a development dependency. The author of said library works on V8, and already considered all those problems and much, much, more[1].

[1]: https://mathiasbynens.be/notes/javascript-benchmarking

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @05:19PM (#24126109)
You are making the assumption that the library doesn't have the flaws I mentioned. It does (You can go read the source yourself https://raw.githubusercontent.com/bestiejs/benchmark.js/2.1.... )

There's no portion of the code that does warmups. There's no portion of code that "blackholes" the results to keep the JIT from optimizing away the code under benchmark. There is a lot of code though... so that's... good?

You make the assumption that just because a lib is popular or widely used it is "correct" or "the best". When it comes to microbenchmarks, that's usually flawed. Very VERY few people actually get them right, benchmark.js is no exception.

That, of course, doesn't mean that benchmark.js can't be useful. For macrobenchmarks it will be roughly right. However, for something as small as leftpad, it's almost certainly not the right way to measure performance.

Re:Never use a dependency that you could replace with an aft... by phpnode on Tuesday August 11, 2020 @08:12PM (#24127391)
> There's no portion of the code that does warmups.

This isn't true - Benchmark.js will repeatedly rerun benchmarks until it gathers statistically meaningful results.

> There's no portion of code that "blackholes" the results to keep the JIT from optimizing away the code under benchmark.

True, and there's actually nothing benchmark.js can do to ensure that doesn't happen in the general case but when this does happen the results are usually pretty obvious - we'd see billions of ops/sec. Incidentally the left-pad benchmarks do not suffer from this issue.

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @05:26PM (#24126169)
Okay, you win. I'm not going to read the entire source of that package just to make a point. Though I do find it strange that the author of that library would write an entire blog post on the topic and then not take his own advice in the implementation of the library he wrote.
Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @05:37PM (#24126291)
Tell me, where in that blog post does he mention doing warm up cycles or avoiding having the JIT optimize away the method? (Hint, he doesn't mention that... so, no, he didn't actually miss his own advice.)

The article is completely consumed with getting the timing of benchmarking right. Which, to be fair, is a place where microbenchmarks often go wrong. It, however, isn't the ONLY place they go wrong.

Re:Never use a dependency that you could replace with an aft... by cjaybo on Wednesday August 12, 2020 @02:23PM (#24135106)
> Luckily, they didn't, and instead pulled in the the `benchmark` library as a development dependency. The author of said library works on V8, and already considered all those problems and much, much, more[1].

This is the "benchmark lib" that was mentioned in the very first sentece of the comment you replied to.

Re:Never use a dependency that you could replace with an aft... by ghj on Tuesday August 11, 2020 @05:09PM (#24126014)
They failed at writing a correct O(n) left pad in their benchmark:

https://github.com/left-pad/left-pad/blob/master/perf/O(n).j...

They are repeatedly appending a single character to the front of a string. This is actually O(n^2) so of course they are winning against it.

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @05:24PM (#24126154)
That would depend on the underlying implementation of the string object, no? (If the string is implemented as a linked list it's O(n))

Anyway, it makes no practical difference in this case, since the one they labeled "O(n)" is the naive implementation that most people would write if they implemented left-pad themselves.

Re:Never use a dependency that you could replace with an aft... by ghj on Tuesday August 11, 2020 @05:28PM (#24126183)
I highly doubt js engines would compile a string down to a linked list. But you're right they might compile it to a circular buffer or deque which can have O(1) prepends.

Quick googling shows that this optimization might exist but only for firefox and only if you use "unshift": https://lannonbr.com/blog/2020-01-27-shift-optimizations https://jandemooij.nl/blog/2017/12/06/some-spidermonkey-opti...

But it's very unlikely that the jit can optimize `str = ch + str;`

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @07:00PM (#24126956)
Depends on the form that `str = ch + str` takes inside the loop. But yeah, the way they wrote the code makes it less likely to work well.

    let padding = '';
    for (let i = 0; i < len; ++i)
      padding += ch;
    return padding + str;
The above would probably get caught by the JIT and would essentially be optimized to what `ch.repeat(len) + str;` would do.
Re:Never use a dependency that you could replace with an aft... by layoutIfNeeded on Tuesday August 11, 2020 @05:46PM (#24126406)
String implemented as a linked list.

You’re a webdev aren’t you?

Re:Never use a dependency that you could replace with an aft... by imtringued on Wednesday August 12, 2020 @06:24AM (#24130377)
Re:Never use a dependency that you could replace with an aft... by Domenic_S on Wednesday August 12, 2020 @04:05PM (#24136230)
Haskell's default String implementation is a linked list; no need for the snark
Re:Never use a dependency that you could replace with an aft... by TheDong on Tuesday August 11, 2020 @03:52PM (#24125164)
One 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.

Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @04:45PM (#24125766)
Unless you are doing front end code, why does the size of the code matter?
Re:Never use a dependency that you could replace with an aft... by Ma8ee on Tuesday August 11, 2020 @05:04PM (#24125947)
Less code is (in general, to certain limits) easier to understand and requires less maintenance.
Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @05:17PM (#24126082)
If I am using code that someone else writes and maintains it is easier to maintain.

But I can maintain code that uses Entity Framework (or Dapper) much easier than I can maintain code based on a custom ORM that the “architect“ wrote.

Re:Never use a dependency that you could replace with an aft... by Ma8ee on Tuesday August 11, 2020 @07:06PM (#24127007)
As long as it works and is well documented, yes. But the moment there’s a bug somewhere or the docs aren’t adequate for your needs, you are in much worse trouble.
Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @07:44PM (#24127240)
Again my general rule - you (generic you) are no special snowflake. What are the chances that you come across a bug in a library that has had 2,176,677 (in the case of Dapper) or Entity Framework (supported by MS) that no one else has come across, found a workaround, and posted the answer somewhere on the Internet compared to your code where you didn’t think about a corner case?
Re:Never use a dependency that you could replace with an aft... by danShumway on Wednesday August 12, 2020 @12:51AM (#24128690)
Literally all the time.

I can count on one hand[0] the number of JS dependencies I've used in enterprise/large projects for extended periods of time where I've never needed to manually debug the library or read the source code. For enterprise software, sometimes the easiest solution is to directly hotpatch a vendored version of the dependency.

This is especially true with dependencies where bugs are fixed in major versions, but where upgrading and dealing with breaking changes would require significant code refactoring.

To drive the point home, I've been bitten by bugs in NPM itself.[1] Fixing that required reading through the source and manually swapping out one NPM's internal dependencies to a newer version.

And it doesn't matter if someone somewhere has had the same problem and posted it on the Internet unless I can find their answer online faster than I can fix the problem myself in my own library. Often this is not the case, filtering through issue trackers and trying to find the one blog post or comment that tells me how to solve the problem can be a big time sink.

[0]: Okay, maybe 2. But the point stands, it's not a rare or exceptional occurance.

[1]: https://github.com/npm/npm/issues/18942

Re:Never use a dependency that you could replace with an aft... by BigJono on Wednesday August 12, 2020 @03:28AM (#24129468)
I've had some serious train wrecks because of shit NPM libraries over the years.

Probably the worst was with a decently popular library someone had brought in, that tried to do a refactor from callbacks to async/await, without understanding at all how async/await worked. They'd leaked an async operation in the library code, so 'await'ing a specific function call in their API that returned a promise, didn't actually await everything the call was doing, ending up in a debugging nightmare. Of course their perfectly manicured suite of 8000 tests with 110% test coverage didn't catch it either, because the number of people who can write good quality tests is shockingly low, and library-writers aren't somehow magically ahead of the pack in that regard.

JS really feels like PHP did back when I was a newbie learning that shit. In other ecosystems, the 95th percentile devs seem to write all the libraries, so everyone comes here and posts repeatedly about how great dependencies are. In JS, it's the average dev writing all the libraries, and the average dev's code is enough to make my brain bleed.

I'm a big proponent of different advice for different ecosystems. If you're doing front-end JS, the pendulum has swung so far to one side that 'NIH syndrome' is treated like it's going to lead to the fourth reich, which makes 'chill out a bit on dependencies' pretty good advice if you're looking to get a leg up in the industry. But I'm sure there's other ecosystems where the same advice will just leave you with a tangled mess while your competitors leapfrog you in productivity with a good 3rd party dependency.

I'd say take any advice in threads like these with a grain of salt unless it's given in a bit of a narrower context. Taking some one liner about software engineering in general and applying it to your specific project is probably just a coin flip as to whether it's going to improve your code or not.

Re:Never use a dependency that you could replace with an aft... by TheDong on Tuesday August 11, 2020 @04:49PM (#24125806)
"smaller" there was short-hand for "more focused, purpose-built to your problem, less generic".

All of those properties make the code easier to reason about and test.

Being easier to reason about, and being a more exact abstraction for my needs, are both incredibly valuable properties.

Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @04:52PM (#24125841)
More generic is better. If I go into a codebase that uses standard libraries. Even if I don’t know how to do something about it someone on the Internet does. Your custom framework - not so much.

I don’t have to care about how the underlying libraries work. I can treat them as a black box.

Re:Never use a dependency that you could replace with an aft... by TheDong on Tuesday August 11, 2020 @05:04PM (#24125952)
> I don’t have to care about how the underlying libraries work. I can treat them as a black box.

When I wrote haskell, the majority of the libraries did just work, and I didn't have to dig into their code to find bugs often.

When I wrote javascript, hundreds of the libraries I used did not just work. I usually had to care very much about their details because they were poorly implemented, full of bugs and incorrect abstractions, and often abandoned soon after.

I agree that there's benefits in reusing some well-socialized and well-implemented generic frameworks and abstractions. It's not worth using generic abstractions that are not well understood, buggy, and don't match your needs closely. In that case, write your own.

More generic is not always better. Above, I'm arguing that it's important for code to be easier to reason about. If a generic abstraction helps with that, cool, but it's not always going to be the case.

Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @06:14PM (#24126649)
That’s also why I stay away from the clusterf%%% of front end development and JS if possible except for simple AWS Lambda scripts that have one dependency - AWS SDK.

Any other scripting I do with Python. Any more complicated development it’s using a language with an ecosystem with adults - C# or Go.

Re:Never use a dependency that you could replace with an aft... by TheDong on Tuesday August 11, 2020 @06:51PM (#24126917)
Kinda ironic that you say "More generic is better" a few comments above, and then also cite Go in a positive light.

Rob pike espoused "A little copying is better than a little dependency", and go refuses to add suitable abstractions to build generic reusable pieces.

Go has a strong culture of doing exactly the sort of thing I was talking about, and you were arguing against.

Re:Never use a dependency that you could replace with an aft... by toast0 on Tuesday August 11, 2020 @05:27PM (#24126180)
What do you do when the black box doesn't work?

Almost everything I work with has bugs, so chances are I'm going to run into one. It's a lot easier for me to fix bugs when there are fewer layers and more of them are written by me. Of course, I can't write all the layers, but if they run on my service, I have to be prepared to fix them, or suffer from them being broken until a benevolent force fixes them for me. (Sometimes that happens, but usually not for the harder problems)

Re:Never use a dependency that you could replace with an aft... by scarface74 on Tuesday August 11, 2020 @06:15PM (#24126658)
Until I have to come in behind you after you’ve left for greener pastures and I have to figure out your bespoke framework and libraries.
Re:Never use a dependency that you could replace with an aft... by toast0 on Tuesday August 11, 2020 @06:24PM (#24126712)
Don't worry, I would never write a bespoke framework. I'd write a custom one. :P
Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @03:53PM (#24125182)
This is actually a great example of why you SHOULDN'T use left pad.

I've not profiled it, but I'm going to guess that now-a-days this will be faster than the current implementation on npm.

    function leftPad (str, len, ch) {
      str += '';
      len = len - str.length;
      if (len <= 0) return str;
      if (!ch && ch !== 0) ch = ' ';
      ch += '';
      return ch.repeat(len) + str;
    }
Why? because the VM is (very likely) going to do exactly what the cache would have done. It can replace `ch.repeat(len) + str;` with a presized string allocation and a memcpy of ch + str characters.
Re:Never use a dependency that you could replace with an aft... by goldenkey on Tuesday August 11, 2020 @03:56PM (#24125216)
This code checks for ch !== 0, yet the bypass branch afterwards calls .repeat. The Number type in JS has no repeat method.

Static typing would actually fix this kind of coding error.

Re:Never use a dependency that you could replace with an aft... by reificator on Tuesday August 11, 2020 @04:00PM (#24125282)
> This code checks for ch !== 0, yet the Number type in JS has no repeat method.

> Static typing would actually fix this kind of coding error.

That's not a coding error, that's addressing an oddity of JS coercion rules that a less experienced developer could easily have missed.

> if (!ch && ch !== 0) ch = ' '

That code says that if `ch` is falsey and not equal to 0, then set it to a space. The only arguable falsey value that should be excluded here is a literal `false`, but that's not a single character and is fairly ambiguous either way. I'd certainly fall on the side that a literal false should not be converted to `'false'` here.

> ch += '';

The next line converts to to a string by adding it to the empty string.

> return ch.repeat(len) + str;

So by the time it gets to this line we know ch is a string.

Static typing is great, but the bug you claim is there is not actually there.

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @04:07PM (#24125363)
FYI, I edited the post after the bug was pointed out to eliminate it and bring this method up to parity with leftpad.
Re:Never use a dependency that you could replace with an aft... by microcolonel on Tuesday August 11, 2020 @03:57PM (#24125233)
What magic would enable that? I don't think the VM is likely to cache a string of 6 spaces, it has no way of knowing that would be a common parameter, and no heuristic to determine that it's likely.

It may specialize or inline, but that's a separate matter.

P.S. I think there's a bug here.

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @04:10PM (#24125395)
JIT is the magic sauce and this a pretty regular optimization.

    Step 1, inline repeat.
    Step 2, remove the intermediate array allocation
    Step 3, allocated a string array sized for the pad + str
    Step 4, Use one of the many CPU instructions to repeatably copy the padding character and then the `str` into the same array of characters.
None of these optimization would be out of the question for the Jit (and I'd expect them). You don't need the cache at all, it's just a waste. The only thing it saves it creating the intermediate string which is HIGHLY likely to be optimized away with the simple code.
Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @04:35PM (#24125660)
They benchmarked it. Their implementation was faster than ch.repeat: https://github.com/left-pad/left-pad/pull/11#issuecomment-20...

Nowadays there's a native padStart function and the left-pad package is deprecated as a result.

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @04:47PM (#24125784)
They used a flawed benchmarking methodology.

JITs only optimize hot code which means any benchmark without a warmup is going to measure cold + hot code time.

Further, JITs will optimize away unused results. They aren't using the leftpad results in any meaningful way.

What they are likely measuring is how long it takes for the JIT to optimize the benchmarking framework.

watch: https://vimeo.com/78900556 for how to microbenchmark a JITed language.

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @05:06PM (#24125974)
Yeah benchmarks can be much more difficult to get right than it might seem at first glance. Good thing they didn't try to write their own benchmarking code, otherwise they might have fallen into those traps you just mentioned.

Luckily, they didn't, and instead pulled in the the `benchmark` library as a development dependency[1]. The author of said library works on V8, and already considered all those problems and much, much, more[2].

[1]: https://github.com/left-pad/left-pad/blob/master/perf/perf.j...

[2]: https://mathiasbynens.be/notes/javascript-benchmarking

Re:Never use a dependency that you could replace with an aft... by cogman10 on Tuesday August 11, 2020 @05:24PM (#24126151)
I know, I read the benchmark suite code. The benchmark suite itself isn't doing the things I said it isn't doing.

Sure, It's popular. It's also wrong.

Re:Never use a dependency that you could replace with an aft... by Ajedi32 on Tuesday August 11, 2020 @05:27PM (#24126175)
Okay, you win. I'm not going to read the entire source of that package just to make a point. Though I do find it strange that the author of that library would write an entire blog post on the topic and then not take his own advice in the implementation of the library he wrote.
Re:Never use a dependency that you could replace with an aft... by tluyben2 on Tuesday August 11, 2020 @04:18PM (#24125477)
Well, my point was more that if a programmer thinks '5 minutes work' it's often 10+ minutes; so when a programmer thinks 'an afternoon', you can possibly lose a week. And then the article really doesn't work.

And yeah, I would and do write leftpad myself it it's not in the stdlib. But if there is a large library full of similar (string) functions that I might need, I would include that library. Not a singular dependency for this type of function.

Re:Never use a dependency that you could replace with an aft... by reificator on Tuesday August 11, 2020 @03:57PM (#24125223)
Yes, particularly when you know the types that will be passed in. True that typechecking in JS can be a little timeconsuming, so it might take 10-15 for me to write a general purpose left pad.

Also I seem to remember that someone benchmarked the cached version and found it to be slower than the naive approach anyway. I could be mistaken there.

Re:Never use a dependency that you could replace with an aft... by mjevans on Tuesday August 11, 2020 @08:07PM (#24127350)
The issue I have with this is a lack of specification. Left pad _what_?

Numbers or ASCII-only-printing? OK that's a reasonable. Is there a desired overflow behavior?

Past that it becomes more an issue of where and why. The suddenly not-trivial example includes questions about fonts, layout, and multi-byte characters. Emoji, etc.

Incidentally, in pseudoscope:

Create a valid full-space pad string (termination / etc), then decrement back from the end of the source string and over-write the pad characters from the end to the start of the string, exiting either on no more pad characters or no more input.

A second algorithm might combine those two steps as one pass, fill the output buffer from back to front. Only for C style strings would this be an issue given the dynamic end point for the data structure.

Re:Never use a dependency that you could replace with an aft... by ogre_codes on Tuesday August 11, 2020 @04:09PM (#24125380)
> Probably good advice, but when was the last time a programmer accurately scoped a problem when they said it will take “an afternoon” to build?

This is why you time box things. Spend XX hours trying to get a thing working and if you aren't close, you grab a library and move on.

Re:Never use a dependency that you could replace with an aft... by _the_inflator on Tuesday August 11, 2020 @03:59PM (#24125256)
I agree with you.

We all too often forget the scope: requirements, developing, testing, to say the least.

My favorite example is NPM. While the author has a point, I tend to rely on the wisdom of the crowd. Sometimes there is a reason why a couple of million developers - in the case of NPM packages - seem to be lazy.

In my experience, we ended up copy/pasting and modifying some code and syncing it with the "superfluous" package. Good intentions, badly executed.

Leftpad was the right itch at the right time and people found better ways to deal with NPM. NPM got better after that, as well as native implementations.

Better cope with NPM than fight it, my 2 cents.

Re:Never use a dependency that you could replace with an aft... by rlonn on Tuesday August 11, 2020 @03:34PM (#24124910)
This is the wisest comment in the whole thread.
Re:Never use a dependency that you could replace with an aft... by nitwit005 on Tuesday August 11, 2020 @04:05PM (#24125348)
You can tell it won't take just an afternoon 30-60 minutes in.

Besides, in reality pulling in and using the dependency takes time as well. There's no real guarantee it's cheaper in terms of developer time.

Re:Never use a dependency that you could replace with an aft... by phodge on Tuesday August 11, 2020 @08:08PM (#24127363)
Ironically, these days with front end development I'm finding it hard to accurately scope how long it will take to incorporate 3rd-party dependencies. The docs make it seem straightforward enough, but they don't cover how to use it correctly under TypeScript instead of ES, or how to use it with Angular instead of React, or how to build it with Rollup instead of webpack, and I often spend an entire day googling obscure blog posts on how to get a dependency working in my own ecosystem.
Re:Never use a dependency that you could replace with an aft... by avmich on Tuesday August 11, 2020 @03:43PM (#24125067)
Well, when the programmer was burned too much by incorrect scoping before?

Don't buy generalized statements like "programmers are always underestimate efforts needed", or even, for that matter, "a task always requires all the possible time it might take" (Parkinson's law). There are exceptions from them :) which sometimes, in a good team, look more than laws themselves.

Re:Never use a dependency that you could replace with an aft... by wuliwong on Tuesday August 11, 2020 @03:45PM (#24125089)
Generalized statements like "Never use a dependency that you could replace with an afternoon of programming." :p
Re:Never use a dependency that you could replace with an aft... by avmich on Tuesday August 11, 2020 @03:47PM (#24125114)
Agree. So this shouldn't be considered a rule. Just a good advice, as many things in programming :) .
Re:Never use a dependency that you could replace with an aft... by klyrs on Tuesday August 11, 2020 @06:40PM (#24126837)
I do this all the time. My head tells me "five lines, tops" -- corresponding to about 10 minutes of "programming." Add in testing, bugs, another 10-20 lines of comments and docs, we're looking at an afternoon.

Never do I give that raw 10-minute estimate to anybody, because it can be wrong by a factor of 10.

Re:Never use a dependency that you could replace with an aft... by swiley on Wednesday August 12, 2020 @06:35AM (#24130473)
Most things really can be done in an afternoon if you’re in the right mood.

They just won’t have unit tests, and they’ll probably have lots of defects and other technical debt.

Re:Never use a dependency that you could replace with an aft... by m463 on Tuesday August 11, 2020 @03:55PM (#24125199)
I think "don't use a dependency" is premature optimization anyway.
Re:Never use a dependency that you could replace with an aft... by sibane on Tuesday August 11, 2020 @06:52PM (#24126926)
It takes an afternoon to do after one week of research and exploratory coding.
Re:Never use a dependency that you could replace with an aft... by greyhair on Wednesday August 12, 2020 @08:46AM (#24131473)
Never
Re:Never use a dependency that you could replace with an aft... by GoToRO on Tuesday August 11, 2020 @04:29PM (#24125607)
It was yesterday.