11 ms·
I applaud this action and while I'd like to point the finger at NPM, there's no real other method to fix historical package versions that depend on this. It is
by larkinrichards 11y ago
I applaud this action and while I'd like to point the finger at NPM, there's no real other method to fix historical package versions that depend on this.
It is worth pointing to the silly state of NPM packages: Who decided that an external dependency was necessary for a module that is 17 lines of code?
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
Developers: less dependencies is better, especially when they're so simple!
You know what's also awesome? The caret semver specifier[1]. You could install a new, broken version of a dependency doing that-- especially when other packages using peerDependencies rely on specific versions and you've used a caret semver specifier.
[1] https://github.com/lydell/line-numbers/pull/3/files https://github.com/lydell/line-numbers/pull/3/files
- joshmanders 11y agohttps://en.wikipedia.org/wiki/Unix_philosophy https://en.wikipedia.org/wiki/Unix_philosophy
- maxaf 11y agoTaking an idea to the logical extreme is an effective means of invalidating said idea. How many UNIX utilities are 17 silly lines long? A bit of code duplication would go a long way towards bringing sanity to JS land.
- joshmanders 11y agoQuite a bit are pretty small.
- cballard 11y agoFor example: http://www.scs.stanford.edu/histar/src/pkg/echo/echo.c http://www.scs.stanford.edu/histar/src/pkg/echo/echo.c
- akkartik 11y agoErm, that's not a very good example. You're pointing out some ancient source file from back when unix had no package management. These days echo.c is part of coreutils, a large package which is economic to manage dependencies for at scale. It's interesting to think about the distinction between promiscuous dependencies (as pioneered by Gemfile) and the Unix way. I like the latter and loathe the former, but maybe I'm wrong. Can someone think of a better example? Is there a modern dpkg/rpm/yum package with <50 LoC of payload? Edit: Incidentally, I just checked and echo.c in coreutils 8.25 weighs in at 194 LoC (excluding comments, empty lines and just curly braces). And that doesn't even include other files that are needed to build echo. Back in 2013 I did a similar analysis for cat, and found that it required 36 thousand lines of code (just .c and .h files). It's my favorite example of the rot at Linux's core. There's many complaints you can make about Unix package management, but 'too many tiny dependencies' seems unlikely to be one of them.
- maxaf 11y agoThe main point in support of your argument is the fact that Unix utils are bundled in larger packages instead of shipping in single-command packages. Think of Fileutils, Shellutils, and Textutils... which got combined to form Coreutils! Ha! That leaves only Diffutils, for the time being anyway.
- deleted 11y ago[deleted]
- akkartik 11y agoBut none of Fileutils, Shellutils and Textutils was ever as tiny as many npm or gem modules. I thought how commands are bundled into packages was the entirety of what we were discussing. That was my interpretation of larkinrichards's comment (way) up above. Packages are the unit of installation, not use. Packages are all we're arguing about. My position: don't put words in God's mouth :) The unix way is commands that do one thing and do it well. But the unix way is silent on the right way to disseminate said commands. There you're on your own.
- swang 11y agoyes, let's blow up the entire concept that's worked fine for the ~5 years of node's existence because one dude did something extreme.
- dham 11y agoWoah woah. Hold on there. Lets not throw around strong words like "worked", "concept", "entire", "fine", "did" when discussing NPM.
- Maarten88 11y agoThis. I'm on Windows. Npm never worked for me, like not at all. Npm has cost me lots of wasted time, I know I should be thankful for this free product, but, but, Grrrrr...
- joshmanders 11y agoWindows has always been a problem for Nodeland, thankfully Microsoft is working on making that better.
- bryanrasmussen 11y agois unpublishing a module extreme?
- smsm42 11y agoI wonder how long /usr/bin/true source is.
- Havvy 11y agoOn Linux, it's 30ish lines, with half of those there to make false.c able to reuse some code. (I know, it's stupid.) In OpenBSD, it's 3 LoC IIRC.
- dalke 11y agoOn at least one OS I worked with, it was 0 bytes long because /bin/sh on an empty file returns true. (I think that was IRIX 4.x.) OTOH, that's slower than the executable from a 3 LoC do-nothing program.
- cjs2 11y agoLonger than one might think... http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true.c http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/true...
- Sanddancer 11y agoWhich is useful for binaries. Libraries, there tends to be a lot more aggregation. If this wasn't the case, you'd see libc spread over dozens and dozens of libraries like libmalloc librandom libstring libarithmetic libsocket libprocess libfilesystem libafilesystem (hey, async ops have a different api) libtime, etc.
- cballard 11y agoWhy would this be a bad thing? I don't need a random number generator if I just want to allocate memory.
- Sanddancer 11y agoBecause a lot of little libraries makes namespaces more complicated, makes security auditing more difficult, makes troubleshooting more difficult as you have to start digging through compatibility of a ton more libraries, makes loading slower, because you have to fopen() a ton more files and parse their contents, etc. Add on top of that those little libraries needing other, probably redundant little libraries, and you can start to see how this can turn the structure of your code into mush really quickly. At this point, optimizing runtimes to only include necessary functions, and optimizing files to only include necessary functions are both things that are pretty much a solved problem. For example, azer has a random-color library, and an rng library. Having both of those as azer-random or something means that someone automatically gets all the dependencies, without having to make many requests to the server. This makes build times shorter and a lot easier. Sometimes, in order to best optimize for small, you have to have some parts that are big. Libraries tend to be one of those things where a few good, big libraries lead to a smaller footprint than many tiny libraries.
- dylan-m 11y agoNot to mention maintenance. Low-hanging fruit here: left-pad, depended on by fricking everyone, <em>is owned by one guy</em>. That is not how you build a serious utility library that people should actually be using in real products. (You also probably shouldn't license it under the WTFPL, but that's another thing). When you aggregate under a common banner, you get maintainers for free and your project might have a bus factor better than 1.
- bye_amzn 11y agoLet it suffice to say that Linux distributions (and some closed OSes) try very hard to prevent package fragmentation. Experience has shown many times that excessive fragmentation leads to proliferation of unmaintained libraries.
- ubernostrum 11y agoIn this case the npm ecosystem is providing more of a surrogate standard library. Imagine if there were no libc, for example, and so people had to reimplement all those functions; would you really want one package per function because of how "Unix philosophy" it would be? This is where the JavaScript ecosystem is right now -- JS doesn't have the kind of robust standard library other languages take for granted, so you end up with a lot of these things that look like they should be stdlib functions, but are instead third-party packages the entire world has to depend on for a usable programming environment.
- esailija 11y agoI don't understand the standard library argument at all. Standard library is always limited, there is always something that's not included - then what? This has nothing to do with the JavaScript standard library but the insanity of NPM. There are modules that have even more dependents than `pad-left` despite being included in the standard library (e.g. https://www.npmjs.com/package/date-now https://www.npmjs.com/package/date-now, https://www.npmjs.com/package/is-positive https://www.npmjs.com/package/is-positive, https://www.npmjs.com/package/is-lower-case https://www.npmjs.com/package/is-lower-case)
- ubernostrum 11y agoThe argument is that things like formatting a string -- including padding it -- should not be add-ons, they should be built into the core distribution you get as part of the language.
- esailija 11y agoI didn't say it shouldn't be part of standard library, I am saying that there is always something that isn't part of the standard library. My point is: if this module was something that shouldn't be part of standard library, what argument would you then use?
- yoklov 11y agoI think you're assuming libc is more robust and useful than it actually is. Libc is extremely minimal (and is full of pitfalls as well). JS has an extremely large and robust standard library in comparison.
- Klathmon 11y agoPersonally i'm going to use an installable module for something even that small, because i can, and it works. The benefits from an install registry don't go away just because the module is very tiny... Why would i spend my time re-inventing the wheel for every little thing i do? And if i'm not reinventing, then i'd be copy/pasting which is much worse. At best that's a waste of time and effort to properly document the source, and at worst it's stealing or license violations. I don't care if a module is a single line, if it does what i need it to and is well tested, then i'll use it. That might seem silly, but the fact is that it's pretty much no overhead, and no software is immune from bugs (even a 16 line function), so updates might be useful in the future. Yeah, there is a chance that stuff like this can happen, but within an hour there were several alternatives to solve issues with installs, i'd say the system is working pretty well. Plus with proper software development techniques (like vendoring your dependencies) this wouldn't even be a problem at all.
- seanp2k2 11y agoBy this logic, every Stack Overflow snippet should be a module. I'm almost hesitant to suggest this since many people who read this will be capable of building such a thing.
- Klathmon 11y agoI'm not saying that everything should be a module, but that well designed, well tested bits of code should be modules. These 17 lines had 100% test coverage and were used by a stupidly large amount of people (read: battle tested), why not use it? As is pointed out elsewhere in this thread, echo.c is roughly the same size, does that mean it's not a worthy program?
- ploxiln 11y ago"echo" is not versioned and delivered on its own. It's part of gnu coreutils (which contains ~ 100 utilities), or part of various BSD core distributions (more than 100 utilities, plus the kernel and libc), and also built-in to shells.
- cballard 11y ago> Developers: less dependencies is better, especially when they're so simple! No! The opposite of that. Lots of little µframeworks, defining composable and generic types, is much better than a giant monolith. The Swift Package Manager is taking this approach, and I think it's great: https://github.com/apple/swift-package-manager#modules https://github.com/apple/swift-package-manager#modules The caret character doesn't appear anywhere in the semver spec, so whatever that does, it's non-standard: http://semver.org/ http://semver.org/ If your modules are small and well-defined, they probably won't need many versions anyways - they might just stay on 1.0.x forever. If you want to do something different, it might make more sense to just write another module.
- chrisfosterelli 11y agoThe caret character is a specification in NPM, not semver. It's designed to work within the semantic versioning rules to ensure you get the latest version which includes bug fixes, but also won't include breaking changes. For example, ^1.3.2 will allow anything greater than 1.3.2 but not 2.0.0. It also has special behaviour that makes it more strict for projects with a major version of 0. If your dependencies follow semver then you'll get bug fixes and security updates without having to do anything or worry about breaking changes. More info: https://nodesource.com/blog/semver-tilde-and-caret/ https://nodesource.com/blog/semver-tilde-and-caret/
- goldbrick 11y agoHow do you read an article like the one this thread belongs to and come away with "Seems reasonable, I need more of that"? Trivial dependencies are a code smell, a liability, and an operational headache.
- _ZeD_ 11y ago...and I am in my little python world with "batteries included"...
- douche 11y agoAnd I in Java and .Net world, where it is more like "nuclear reactor included..."
- ceejayoz 11y agoIt gets worse than that. https://www.npmjs.com/package/uniq https://www.npmjs.com/package/uniq https://www.npmjs.com/package/array-uniq https://www.npmjs.com/package/array-uniq https://www.npmjs.com/package/array-unique https://www.npmjs.com/package/array-unique
- chrisfosterelli 11y agoI think you're mistaken about the caret semver specifier. Using the caret for versions less than 0.1.0 offers no flexibility at all. For 0.0.x versions of packages the caret means "this version and this version only", so it won't break anything here... Source: https://docs.npmjs.com/misc/semver#caret-ranges-123-025-004 https://docs.npmjs.com/misc/semver#caret-ranges-123-025-004
- dwg 11y agoHaving a multitude of small utilities like this is a great thing with many advantages. It may seem simple to write leftpad, but if 1000 projects that need it all write their own version, there will be at least 2000 more software bugs out there in the wild because of it. If you think that's rediculous, you're not being realistic about the huge disparity in skill levels of industry programmers as well as the considerable rush under which many projects are done. Also important is that every time I can use a public ally available utility instead of writing it myself, it's one less thing I have to think about. The benefit of making less decisions really adds up, saving a ton of mental capacity to focus on the more important parts of my project. Even the simplest methods require some thought to design. I know there are disadvantages (such as what happened as the topic of this post), but there are also ways to mitigate them. As far as having many versions that all do the same thing, there is usually winners and losers over time. Because of this I believe that eventually the dependency graph shrinks overall. Note that I wouldn't advocate creating utilities for things that are not very generalizable.
- sorenjan 11y agoI've never used npm, but doesn't it take at least as long to find, evaluate, and install a package like left-pad as it would to just write the function yourself when you find you need it?
- karmelapple 11y agoPersonally, no, but even if it did, what if a bug is found in the future? The community fixes the bug, not necessarily you!
- esailija 11y agoThe possibility of having bugs in code you don't control (that usually has a clause for no warranties) is an argument for implementing it yourself, not against it. Don't forget how hard it is to get a maintainer even agree on whether something is 1. a bug 2. that needs to be fixed.
- icefox 11y agoSomeone with more JS experience can chime in, but isn't this really inefficient in JavaScript? Wouldn't appending rather than pre-pending be better due to the way strings and memory are handled? Or at the bare minimum create the left padding in the loop and tack on str after? Can you use ch.repeat(len) + str; yet in node or if not just do the same idea of doubling in size ch until len is satisfied? while (++i < len) { str = ch + str; } And isn't this a bug? leftpad("x", 2, '00') will return "00x"
- sb8244 11y agoLess dependencies is definitely better, but that doesn't mean "write the code because we can't install it via npm. A developer could come along, find this library, and hard-copy it into their source repo. The tested source code is there, and they don't have a dependency on npm. This wouldn't work quite so well for large packages (chance of bugs is high and so patches are important), but for something like this? Just ditch npm.
- sotojuan 11y agoThe solution (IMO) is between those: Use lodash's padding functions. It's modular by default so you don't bring in the whole library, JDD is a performance junkie, and it's lodash so it's not going to get unpublished. If not, writing it yourself works too. Or advocate for a better string stdlib.
- michaeldwan 11y ago"A little copying is better than a little dependency" - Rob Pike
- mstade 11y ago> Developers: less dependencies is better, especially when they're so simple! I tend to agree, but this is conflating the issue of having dependencies with delivery. It's perfectly ok to build small and compose large, with some of the smaller constituents being external dependencies, but the problem here is that the delivery of the packages isn't immutable and static. When you publish a package to npm, you don't publish it along with a copy of all your dependencies (by default, there are mechanisms to do this however.) The external dependencies will be pulled in separately when people install your package. What you're suggesting could still be done with an external dependency, just by making sure you it's only external at development time, but at publish it is truly bundled along with your package. This obviously comes with other costs, like the inability to dedupe packages.
- jessaustin 11y agoWho decided that an external dependency was necessary for a module that is 17 lines of code? This is an advantage of language concision. In coffeescript this isn't even a function, it's just a one-line idiom: (ch for [0...len]).join('')[str.length..] + str