
One liner NPM package “is-windows” has 2.5M dependants, why on earth? - whack
https://twitter.com/caspervonb/status/1139947676546453504
======
thomascgalvin
Even the guys on our Node team joke that the node modules folder is
abhorrently large. More massive than a black hole is the most common meme.

I think there's two things going on here. One, Javascript has taken Don't
Repeat Yourself to an absolutely insane extreme. Python claims "batteries
included" and Java boasts "there's a library for that", but it's at a higher
level than stuff like is-windows.

Most libraries are large and include a lot of functionality, and something
like is-windows would be found inside a larger dependency like system-utils.
Similarly, a Java dev would import Guava, not immutable-list and and multiset
and multilist.

Second, I think many Javascript devs see themselves more as plumbers than
developers. The goal seems to be to stitch a bunch of dependencies together to
achieve the desired outcome, rather than _developing_ the desired outcome.

I've seen plenty of people rip FileUtils.writeStringToFile out into a
standalone utility class, because they didn't need all of commons-io as a
dependency. In order to do that, you need to know how writeStringToFile works,
and be able to fix whatever breaks when you separate it from its ecosystem.

Devs that pull in is-windows don't have that kind of ... curiosity, I guess is
the right word. There's no desire to see _how_ is-windows works, or to see if
they can improve it. It does what they need, so they include it as a
dependency and move on, end of story. The overhead, and more importantly the
security issues, involved just aren't a factor.

I do wonder if the short lifespan of many UI projects is a factor, too. If
you're just going to rewrite the UI in six months, there's no reason to make
it efficient or maintainable.

~~~
qudat
> Even the guys on our Node team joke that the node modules folder is
> abhorrently large. More massive than a black hole is the most common meme.

This "argument" gets brought up every time there's an article about NPM. The
STD library for node is relatively small so a lot of that work is outsourced
to third-party libraries. The node binary is 17mb for mac os x, the node
modules for a project end up 100-800mb maybe? So let's say binary + library
size reaches 1GB. Now go and download visual studio to work on a C# project
and wait for 15GB to be downloaded. I'm not arguing that relying on a third-
party ecosystem is great as it does have legitimate security issues, but
filesystem size is not the problem here.

~~~
tntn
Why are you comparing the size of application dependencies to the size of an
IDE that includes several compiler toolchains and tons of other build-only
stuff?

~~~
slooonz
Because node_modules generally includes a "compiler toolchain" (webpack) too ?

------
Raphmedia
This line is tested against and super optimized. By requiring this, you are
future proof. The maintainer is active and writes tests. It's also a bit
esoteric and hard to undestand.

`return process && (process.platform === 'win32' ||
/^(msys|cygwin)$/.test(process.env.OSTYPE));`

Here's is what's probably going on in the head of the people who require it:

"What does this do exactly? Why do I need to test against 'win32'? Should I
also test against 'win64' or 'x64'? What if it changes later on? Do I need to
keep track of Windows versions and then change all my apps? What if I write it
without testing for 'cygwin' and someone else in the project do? Will the app
only work partially on some hardware? What if some new OS comes out?"

Don't get me wrong, it's not perfect and is a security hole. But that's the
reason it's done.

~~~
OskarS
You really think that line is "super-optimized"? It generates and executes a
regex to check if a string has one of two different prefixes. I don't know a
lot about JavaScript internals, but I would imagine that is both forces memory
to be allocated (and garbage generated) as well as being significantly slower
than a basic prefix check. If doing this is considered "super-optimized", I
don't even know what this industry is any more.

~~~
ChrisSD
It's not even testing prefixes, it's testing the whole string. It's the
equivalent of:

    
    
        process.env.OSTYPE === 'cygwin' || process.env.OSTYPE === 'msys'
    

Though I don't know enough about V8 to say how each is optimised.

~~~
Raphmedia
Here, test it. If you test it multiple time you get slightly different
results. Both seem to be similar. You would have to ask the author why they
went with the regex solution to know why they chose that one. Knowing
Javascript, there's probably a pitfall we are not thinking about.

[http://jsben.ch/uFK8t](http://jsben.ch/uFK8t)

------
aethertap
I will often use things like this, not because I don't know how it's done, but
because I have a hope that whoever made it will maintain it and keep it
working properly under future changing conditions. Today, it's easy to see if
the platform is windows. Later, that may change, and if this code is
maintained it will save me headaches. If lots of other people are also using
it, there's a very good chance that it will be updated quickly and that weird
corner cases I'm not aware of will be already taken care of.

~~~
asdkhadsj
Yea, I agree completely. While I tend to reinvent plenty of wheels, I don't
find the idea of importing a package designed for one small task, bad. _(edit:
missing word)_

_Especially_ if it's used by a ton of repos. If, as your example says,
something changes where `is-windows` needs to be updated it's likely to either
be updated or break so many codebases that someone will update it.

There's a bit of chaotic safety in relying on a web of dependency trust like
this. On one hand more people invested in the behavior of a simple package
gives you more confidence. On the other hand, it means more developers are
depending on more packages, introducing possibly more brittle behavior.

The latter _(brittle behavior /deps)_ has been my experience fwiw. While I
don't dislike the idea of `is-windows`, I do dislike introducing more points
of random failure. In general if I don't have the idea that my own
implementation of something like `is-windows` is likely to need maintaining
then I'm happy to do it myself and remove a dependency.

Coming from Rust mostly, but I wonder if the safety of the language aids this
problem too. For example, I imagine `is-windows` level of dependencies is far
less problematic in Rust than NodeJS.

------
AdmiralAsshat
This kinda of thing (see: the "left-justify" fiasco) seems unique to NPM. Why
is that? Python packages are very easy to import as well, but you don't see
this kind of madness in most python programs.

~~~
voltagex_
Python has a standard library.

~~~
hprotagonist
and you see the other madness there, in which parts of stdlib are absolute
garbage so you will always install requests and lxml anyway.

~~~
Cacti
I’ve been using Python for 20 years and have never used either of those
libraries. People _do_ use Python for more than accessing web services and
processing HTML, you know.

Besides, the stdlib, and Python packaging in general, is unquestionably light
years ahead of NPM.

~~~
jessaustin
Oh wow am I glad to read that! What is the python equivalent of "npm publish"?
What do I need to install and configure in order for that to work?

~~~
Cacti
It’s “twine publish”...

And yes the setup is more extensive than NPM, which is exactly why the PyPi
ecosystem isn’t the steaming pile of shit that is NPM.

~~~
jessaustin
Haha "twine". [0] Seems like a real mainstream tool there. Of course I know
from previous python debacles that while npm just uploads the directory
structure that already works in development, with python one has several
obscure and changeable package preparation steps to perform first.

You're using some colorful language ITT. "unquestionably light years ahead",
"steaming pile of shit", etc. This sort of idiom is good for convincing
children. Whom are you trying to convince?

[0]
[https://www.python.org/search/?q=twine&submit=](https://www.python.org/search/?q=twine&submit=)

------
netfl0
The DRY culture taken to the logical extreme ends up exactly here.

Perhaps someone influential can create an acceptable definition for when it is
OK to "repeat yourself". The node.js package dependency culture is toxic.

~~~
alexkavon
I see it as a combination of that and no incentive to review the code you
require. We live in a “I need it to just work because everyone wants the dream
of tech seemlessly working” age. This will probably become more and more
common as the market opens up and the easier jobs (work?) become more and more
blue collar. JS lends itself well to entry level devs that just want to write
code and not understand needs or how an application works and why code is
needed...and the exacerbation continues.

~~~
duxup
Is this just JS entry level devs bringing in is-windows just because?

I have my doubts about that. I suspect it is more a question of what other
packages they bring in... that for some reason use is-windows.

I think that is a difference and points to a different set of folks who for
some reason, use this thing.

------
frou_dh
One-line NPM packages promoting naive excessive code-reuse are eyebrow-raising
but not as bad as it gets.

How about fundamentally inane things like giving a cutesy obfuscated name to
swallowing exceptions?

[https://github.com/electerious/nice-
try/blob/master/src/inde...](https://github.com/electerious/nice-
try/blob/master/src/index.js)

[https://www.npmjs.com/package/nice-try](https://www.npmjs.com/package/nice-
try)

Used by 1.1 million other packages apparently.

------
jakelazaroff
The reply by @mcclure111 [1] is good:

 _> When I write code, I want to write things semantically— I want to call an
isWindows() function, not idiomatically compare a string process.platform
(node only) to a string that could change in the future._

 _> If I have "semantic" functions like isWindows, I want it in a library, not
one-off in my project. And if I have a library management system, it's great
if the libraries are highly granular— IE, a standard library where each
function is one library sounds great._

 _> …It's just that, instead of maintaining a standard library set containing
many small granular sublibraries, the javascript community decided to make
every single one-function library an attack/vuln injection surface OH WELL_

[1]
[https://twitter.com/mcclure111/status/1140007877547106305](https://twitter.com/mcclure111/status/1140007877547106305)

------
thrower123
It's a bit more than `process.platform == "win32"` but the bulk of it is
boiler-plate for the insanity of multi-standard JS module definitions.

[https://github.com/jonschlinkert/is-
windows/blame/master/ind...](https://github.com/jonschlinkert/is-
windows/blame/master/index.js)

If you go read the code, you are doing more than most JS developers do when
they pull in a massive sequoia of dependencies.

~~~
datpuz
There's also more to it than checking process.platform: 'process.platform ===
'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)

~~~
caspervonb
Checking for Cygwin is a false positive (IMHO at-least)

------
tlrobinson
I’m glad people publish packages like this, but feel like there needs to be a
better way to consume them.

What if you could do `npm install-inline ./src/utils is-windows` and npm
downloaded the module and inserted it inline in your utils directory, along
with a comment referencing the original package, version number, and license
information (if required). There could be an update-inline command as well.

This seems like a ok compromise between “install 376 micro libraries” and
“copy code snippets off StackOverflow”.

------
diminish
Here's an idea. Why doesn't NPM or some big guy maintain a node "standard
library" which pulls top 1000 most used small npm packages into a single one?

~~~
WkndTriathlete
The best part about that would be the endless arguments about which license
was appropriate for the thousand different licenses aggregated together.

------
tonyedgecombe
I wouldn't use it but I can see why this might happen.

The correct solution would be process.platform === "win32" but if you aren't
familiar with Windows then you might not realise this includes 64 bit Windows
or Windows Server.

If process.isWindows() existed in the standard library nobody would be
concerned about it.

~~~
OskarS
Ok, but lets say you're doing something that requires an isWindows() function.
You search NPM, you find this package. At this point, do you not even look at
the code? Like, even a glance would make you aware that all it's doing is
comparing with "win32", which you can trivially do yourself. So why use the
package at all, then? All it adds is overhead.

No, clearly the people who use this package has not taken even a second to
review the code, because it if they had, they'd know that it was trivial.
Security-wise, that's deeply troubling.

~~~
slooonz
Wait, do people look at the code of the librairies they’re using in
Java/PHP/Python/C++/Go/… ?

------
chrisfinazzo
Humans are stupid and cannot learn anything

[https://www.davidhaney.io/npm-left-pad-have-we-forgotten-
how...](https://www.davidhaney.io/npm-left-pad-have-we-forgotten-how-to-
program/)

------
tootie
I think it's a question of maintenance. You can check if process.platform is
"win32" or "win64", but what happens when they release a 65-bit architecture
and all your code breaks?

~~~
Operyl
Your code would break if you pulled in the dependency, too, until you updated
it. I don’t think that matters much here.

~~~
tootie
Then maybe we need a SaaS solution to determinine if we're running on Windows.

------
stupidcar
I think it's funny how so many people have an allergic reaction to using a
package manager to add fragments of small but non-obvious code to their
codebase, but have no issue with frequently using Google to track down one-
liners on Stack Overflow, which they then copy-and-paste into their codebase.

Why is you acting like a slow, biological package manager for small bits of
code better than using a real package manager for the same purpose?

~~~
tntn
1\. The code you pull in will not get updated unless you do it explicitly.

2\. The code you pull in will not get exploited when someone masquerades as
the package owner. (How many widely publicized cases of this have there been
by now, 5? 10?)

3\. Presumably you read the code enough while copy-pasting to be sure it isn't
mining Bitcoin or something.

------
heavenlyblue
Welcome to the times when we import code by semantics, rather than it’s
pragmatics. We’re getting to the next step of evolution in engineering.

Suggestions: series of wrappers for Array renamed as possible applications of
Array for those who don’t know what an Array is.

------
duxup
At one point could this have been a more complicated thing to determine and
later less so, so the code changed to just the one liner?

~~~
ChrisSD
The first commit on git boils down to:

    
    
        function isWindows() {
            if (typeof process === 'undefined' || !process) {
              return false;
            }
            return process.platform === 'win32';
        }

~~~
duxup
Man... what heck was the point of making that?

------
brlewis
Spelling correction: dependents

~~~
caspervonb
Not in proper real English it's not.

------
jrvxo
[https://www.npmjs.com/package/is-odd](https://www.npmjs.com/package/is-odd)

is-odd 831,460 weekly downloads

~~~
SketchySeaBeast
It's very easy to flippantly go "why would you ever use that???", but I'm
honestly wondering what is the actual justification for the use of such a
package. I see it does some initial checking (which will take more lines in
your own code to deal with), but I can't figure out why someone would actually
use that.

~~~
tastroder
This one year old reddit discussion [1] seems to indicate that the package was
used in another, pretty popular and more complex, package by the same author.
The dependency doesn't look current anymore but it might be downloads of
previous versions.

As for justification and usage I couldn't tell you, apparently it was only
used once in that whole codebase anyway (also according to that thread).

[1]
[https://www.reddit.com/r/programming/comments/886zji/why_has...](https://www.reddit.com/r/programming/comments/886zji/why_has_there_been_nearly_3_million_installs_of/)

~~~
OskarS
Even worse: it is only used one time in the entire code-base, and that one
time was to check whether or not a value returned by the string length
function was odd.

What.... why.... the only concievable point of a package like this is that at
least it does the kind of type-checking needed to compensate for JavaScripts
weak typing system, but why do you need to check the type of String.length?!
Do you really think it's going to start spitting anything other than a
positive integer? Fucking hell....

~~~
imtringued
0 is not a positive number.

~~~
OskarS
Fair enough, "non-negative integers" then.

