Hacker News new | past | comments | ask | show | jobs | submit login
I've Just Liberated My Modules (medium.com/azerbike)
1573 points by chejazi on March 22, 2016 | hide | past | favorite | 797 comments

The fact that this is possible with NPM seems really dangerous. The author unpublished (erm, "liberated") over 250 NPM modules, making those global names (e.g. "map", "alert", "iframe", "subscription", etc) available for anyone to register and replace with any code they wish.

Since these libs are now baked into various package.json configuration files (some with 10s of thousands of installs per month, "left-pad" with 2.5M/month), meaning a malicious actor could publish a new patch version bump (for every major and minor version combination) of these libs and ship whatever they want to future npm builds. Because most package.json configs use the "^1.0.1" caret convention (and npm --save defaults to this mode), the vast majority of future installs could grab the malicious version.

@seldo Is there a plan to address this? If I'm understanding this right, it seems pretty scary :|

[1] https://medium.com/@azerbike/i-ve-just-liberated-my-modules-...

So we need gpg signed packages :> And... all packages should be namespaced under the author who published them. And... I kind of want to say "once it's published, it's forever".

> And... I kind of want to say "once it's published, it's forever".

This is effectively the norm with more traditional, curated package managers. Say I release a piece of open source software, and some Linux distro adds it to their package manager. Under a typical open source license, I have no legal right to ask them to stop distributing it. They can just say "sorry, you licensed this code to us under X license and we're distributing it under those terms. Removing it would break our users' systems, so we won't do it."

The difference is that NPM is self-service - publishers add packages themselves, and NPM has chosen to also provide a self-service option to remove packages. I honestly wouldn't have a problem with them removing that option, and only allowing packages to be removed by contacting support with a good reason. (Accidental private info disclosure, copyright violation, severe security bug, etc.)

  I honestly wouldn't have a problem with them removing that option, and only
  allowing packages to be removed by contacting support with a good reason.
  (Accidental private info disclosure, copyright violation, severe security 
  bug, etc.)
Even Rust's Cargo won't allow you to revoke secrets [1]. I think this is the correct policy.

[1] http://doc.crates.io/crates-io.html#cargo-yank

Aside from secrets there is also sensitive data. If someone accidentally uploads some personal information, they need a way to remove it if, say, they receive a court order ordering them to remove it.

If they receive a court order, and there is no technical way to do that, then the court is out of luck. "A court might order it in the future" is not a design constraint on your decisions today.

Sure there's a technical way to do it: you unplug the server hosting it (or more likely, your hosting provider does that for you).

No court is going to shed any tears over fact this has wider consequences than if you'd been able to comply with a narrower takedown request.

This combined with the cost of hosting (I remember the ruby community freaking out over rubygems costs a couple years ago) makes me think maybe we're evolving towards decentralized dependency hosting. Something like Storj where users offset hosting fees with blockchain payments when dependencies are fetched.

The go solution seems more reasonable and achievable- the host is part of the namespace. Instant decentralization.

There's nothing preventing decentralization with npm now; it's a matter of configuration. Tying the namespace to a host seems more like instant excessive coupling.

Tying namespaces to a hostname isn't really that controversial -- it's no different than email.

If you want to be your own provider then host your packages on your server(s) and tell your users to add npm.cooldev.me/packagename to their configuration.

If you don't want to host your own then you can choose from a few public providers like npmjs but then have to be subject to their guidelines, policies, and fees.

Throw in some automatic bittorrent support in the client to help offload costs and you've got something great.

npm already supports all of that except the bittorrent bit, with the proper configuration, and without requiring that idiosyncratic namespace convention. [0] I don't think bittorrent is actually relevant to most use cases. Most people complaining here just don't want their site to go down, so they should vendor or fork all their deps and run their own registry to support that. Downstream users of public modules can either go through npmjs or perform the same vendoring and forking work themselves.

[0] https://docs.npmjs.com/misc/registry

There have been links to child porn in the Bitcoin blockchain. To date, this has not resulted in any courts preventing full nodes from running in the US.

This why sites that don't allow package authors to "unpublish" have contact information so that data deletion can be handled on a case-by-case basis.

I'm not sure how the court could force you to do something you can't possibly do...

"So what you're saying is, your computers cannot possibly not continue damaging the plaintiff's interests." "That's correct." "You're being honest with me." "Yes, your Honor." "Will the computers continue harming the plaintiff's interests if shut off?" "... That would be dreadfully inconvenient, your Honor." "Do you have a more convenient solution?" "No, your Honor." "You are hereby ordered to turn off your computers in 48 hours." "... You can't do that." "I can do a lot of things, including jailing you if you disobey my lawful authority. 48 hours."

Engineers often think that they are the first people in history to have thought "Hey, wouldn't it be easy to pull one over on the legal system?" This is, in fact, quite routine. The legal system interprets attempts to route around it as damage and responds to damage with overwhelming force.

What Patrick says is technically true. But before granting the "extraordinary remedy" of an injunction, U.S. courts would apply the traditional four-factor test, which includes assessing:

+ the balance of hardships between allowing the conduct in question to continue vs. issuing the injunction;

+ whether the damage being caused by the conduct in question could be satisfactorily remedied by a payment of money as opposed to a mandate or a prohibition; and

+ (importantly) the public interest.

See, e.g., the Supreme Court's discussion of the four-factor test in eBay v. MercExchange, 547 U.S. 388 (2006), https://scholar.google.com/scholar_case?case=481934433895457...

How about a blockchain-based NPM? Can't take all the computers down.

Legal, shmegal.

You can still be jailed for contempt of the order, though.

"I've found a clever workaround for court orders" doesn't work around that bit.

OK, now tell me how you can remove this file from BitTorrent (it's Fedora 18 KDE)


I'll wait

It's not about whether the removal is logistically possible, it's about whether a court can punish someone for failing to carry out the removal.

Even when the former is actually impossible, a court could still punish for the latter. "Ha ha ha I use technology to cleverly show how futile your orders are" is not the kind of thing you want to say to a court with broad contempt powers.

The court can't punish you for not being able to do the impossible. That's ludicrous. "We have shut down all of our servers, yes. We can't stop people from downloading this, no"

That's because all laws make sense and all people who enforce and judge them are understand this.

Pay damages, then.

Pay damages because someone else uploaded something by accident and you can't fix it? It doesn't work like that.

It only doesn't work like that in the context of safe harbor laws.

If the safe harbor law protection doesn't apply, and the defendant is responsible for the illegal behavior, the defendant can absolutely be held legally liable and pay the legally-appropriate punishment.

Why should you pay the damages for something that's not on your server?

If the "forbidden" action was previous to proceedings and carried out in good faith by unknown parties, it would be very hard to sanction anyone.

Just live outside of the United States, and you'll be fine.

Yeah, there's literally no other courts outside the USA.

Yeah, because the US doesn't have treaties with most of the world...

Would that work if you did it before the court order?


that's why we'll kurtzweill ourselves into the computers that can't be shut down!

Or something like http://ipfs.io/

IFPS is cool, however pretty far away from being usable as a package management system... Some package management system could use it as a backend, though.

In fact, gx[0] is such a package management system.

[0]: https://github.com/whyrusleeping/gx

Yep, but someone should implement that first. Package repositories have pretty much centralized control still, and will have for foreseeable future.

npm already replicates to hundreds of other servers. Right now, it is practically infeasible to actually remove packages permanently.

That's why I'm looking into IPFS(https://ipfs.io) as part of my infrastructure. How that would look then, with IPFS...

> "So what you're saying is, your computers cannot possibly not continue damaging the plaintiff's interests." "That's correct."

> "You're being honest with me." "Yes, your Honor."

> "Will the computers continue harming the plaintiff's interests if shut off?" "No it wouldn't, your Honor.".....

And suddenly things like NPM can transfer the data to other machines, and those machines themselves can also provide to others. Deletions are impossible if people still want the content.

And IPFS guarantees that if a single node has the data, then any node can download it and also be part of the cloud that provides the data. Once it's out, it's impossible to retract.

> The legal system interprets attempts to route around it as damage and responds to damage with overwhelming force.

In other words, Hulk Hogan vs Gawker.

They would force the provider to facilitate the removal.

What if such a system was implemented using IPFS[0] (or similar) for storage?

[0] https://github.com/ipfs/ipfs

I'm surprised all package managers don't use an IPFS-like system that uses immutable state with mutable labels and namespaces. Now that IPFS exists, and provides distributed hosting, it's even easier.

As much as I agree, IPFS is still very much under construction and I don't think any known package managers got started after IPFS was reliable.

You can experiment with ipfs-backed git remotes though. That's already possible.

gx is a generic package manager on top of IPFS that uses git-style hooks for adding per-language support. It's already being used to manage dependencies on the go-ipfs project: https://github.com/whyrusleeping/gx

Bonus: there's also a IPFS git remote implementation! https://github.com/cryptix/git-remote-ipfs

Yes the IPFS implementation might change but not the content multihash addressing. Linking to data with those addresses is the generic 'package management' that solves all these problems (references to mutable data at mutable origins, circular dependencies, data caching, namespace conflicts). The specifics of resolving links will hopefully be something we don't think about much.

I've played around with ipfs.js for resolving links into eval'd js at runtime and imagine a npm replacement would be pretty trivial. The IPFS peer to peer swarm seems stable to me but you could also dump all your hash-named files into a s3 bucket or something as a fallback repo.

No signatures, no (at least!) an IPFS mirror as a backup option - how can one trust NPM or the likes?!

NPM doesn't even have immutable versions. Many would love to see this improved.

What you mean by that? It used to be possible to republish a version (it broke our build when a dep was republished with a breaking change, that's how I learnt about it) but this was fixed some 2-3 years ago IIRC

Somewhat related, I just coincidentally stumbled upon https://github.com/alexanderGugel/ied . "Upcomming Nix-inspired features", to paraphrase their README, could well prevent this debacle.

(And btw, We Nix users very much do hope to start using IPFS :).)

There’s already apt-get over Freenet:

Git has crypto for a reason. Every package manager must have it too.

There is already gx package manager: https://github.com/whyrusleeping/gx

Looks like the npm team will not be removing the ability to unpublish packages - see reply by core committer "othiym23" on https://github.com/npm/npm/pull/12017


There are a lot of problems with NuGet, but they got this right. I do wish there was a way to mark a package as deprecated, though. For ages, there was an unofficial JQuery package that was years out of date.

`npm help deprecate`

Yep, unfortunately the same does not exist for NuGet.

Read the whole thread. Rather concerned by the final one. "Locking temporarily" to get away from the discussion?

That feels sort of like the online discussion equivalent of sticking your fingers in your ears and going "la la la I'm not listening".

I don't expect someone in their position to be unable to ignore a conversation and "take a break" but I would expect them to be capable of doing so without resorting to "suppressing" the ongoing group discussion.

Or it's a "we're discussing internally, and would rather not deal with the shit-show that Github issues becomes once the issue becomes politicized and rampant misinformation and misguided activism take over."[1] There will be plenty of time for people to froth at the mouth and complain that they chose one way or the other once they've made a clear decision, which as of the locking the thread to collaborators, they have not (the current thinking has been outlined, but they said they are thinking about it).

1: See the recent systemd efivarfs issue at https://github.com/systemd/systemd/issues/2402 and associated HN discussions, which was solved through a kernel fix. Pitchforks abound.

I suspect your right, but honestly... His choice of language sounded much less like 'were thinking as a team', and much more like 'your all talking too loudly, you've given me a headache, so i'm going to shut you all up for a while'.

You mean the response that says, verbatim: "I'm thinking about the points that have been made, and I'm sure that we as a team will consider them going forward" ? Sure, he also says for now the behavior won't change, but that's the sane thing to do with the errors are rare, as changing something too quickly may introduce new bugs or unforeseen problems. Honestly, your interpretation of that comment is the exact reason why it's good to shut it down for a little while. The conversation gets so charged that even a "we need time to think about it" response is viewed negatively.

GPG isn't strictly necessary if you trust NPM's authentication system (of course, that's a big "if" for many folks).

Publish forever (barring requests to remove for legal compliance or whatever) is a good idea. Or at the very least, it should be a default option. And if you install a dependency that isn't "publish forever", you should get a warning.

This is what happens with Clojars. It is possible to remove packages, but it requires a manual email to the admins, along with an explanation, e.g. published internal lib accidentally. This prevents scenarios like this, but also cases where people want to 'clean up' things they no longer need, even though others are depending on them.

I think I'd just want to add that namepsacing by author doesn't entirely fix the problem. For the fewer instances where there is a collision, we still have this issue with lawyers asserting trademarks.

"Would the real Slim Shady please stand up?"

We want multiple 'kik's and multiple Shady's simultaneously. So record the gpg sig of the author in package.json, and filter the name + semver against just their published modules when updating.

Depending on how unique you need to be:

npm install <module> --save

npm install <author>/<module> --save

npm install <gpg>/<module> --save

On a side note, npm-search really sucks. It lacks a lot of fine-grained filtering. I'd love to be able to search by tags, or exclude results with an incompatible license, or even prioritize results by specified dependencies. npm-search needs love.

That's a good idea, but what if Kik lawyers come knocking on your door saying that you're breaking the law and this package cannot stay there forever, or for any moment longer?

Well it shouldn't be hard...oh wait. This is javascript. Good luck then. :)

Do they seriously not use any sort of public key cryptography to sign packages? Frankly, for a project that's been around as long as NPM, that's downright irresponsible if that's the case. That's like package management 101.

Most of the programming language Package managers that I've seen either don't have the facility or it's not widely used.

Maven central requires GPG signatures for every package, so all major libraries on the JVM have GPG signatures.

(Whether anyone's checking them is another question, but at least you can if you want to)

I really doubt anyone checks them. It's not integrated or enabled by default, there's no way to pin keys in the build files, etc. GPG isn't the solution to such problems, unfortunately.

In one of my old projects (bitcoinj) we did write a Maven plugin that let you put the hashes of the dependencies into your build file.

However it's rare to see Maven/Gradle builds that accept version ranges. And once downloaded it's cached.

There's a plugin for checking it in maven ( http://www.simplify4u.org/pgpverify-maven-plugin/plugin-info... ) that allows pinning the keys.

Ranges are rare but I'm not sure why - maven actually has very good support for them. I guess it's just that they're not the default?

Version ranges can create inconsistent builds. That's why they're not default and that's why they're not really recommended.

A spectacular failure just waiting to happen.

For example, RubyGems it's possible to sign them, but it's not used as much as it should be because option security never gets used. Waxseal is a gem to sign other gems.

Generally though, it's a worse vulnerability than bitsquatting because it gives quarter to silent, advanced, persistent threats by definition. (Dynamic, untrusted code modification either in-flight or at-rest in difficult to prevent/audit ways.)

The primary way for change to happen is for some company to get hacked, but then it will only change for that one platform because most people are reactive not proactive. Changing this proactively seems painful, but it's less onerous than the risks of the alternatives. The key point is to make end-to-end verification and public key management mandatory and simple.

Ideas for improvement:

- Add 2 factor authentication for npm publish

- When you npm install, add a warning for all the versions that got published without 2 fac

- pre-install/post-install scripts should require user to accept or refuse. The simple action of running npm install shouldn't run arbitrary code.

- make shrinkwrap by default (and fix all the issues with it) so that running npm install doesn't use different versions when used over time.

- make updating a version an explicit decision via npm upgrade

Hmm, how does that help?

  User A: Publish package X1.0 (with 2 factor auth)
  User B: Download with npm package X1.0
  User A: Unpublish package.
  User C: Publish package X1.0, malware code (with a different 2 factor auth)
  User B: Somewhere else, download and install package X1.0
For that to work, every package should be signed in package.js so that when you download a different version, you know about it. Also, I don't think it should be possible to alter previous versions. Package X1.0 should always be X1.0.


Seems like it's impossible to re-upload X1.0, which fix this issue. I thought once a package was unpublished, it was possible to republish the exact same version.

When a package transfers ownership or is removed/re-added, it's not possible to republish the same version as one that has previously existed.

Of course, this doesn't save you if you're installing `^1.0.0`, the maintainer deletes the package, and someone else uploads a malicous `1.0.1`.

The package.json should allow pinning publisher usernames and optionally public keys, and shrinkwrap should pin hashes, not just versions.

I edited my post while you were writing yours ;-) Thanks for the clarification.

> Is there a plan to address this?

Too late. Every package name on the list has been claimed already by a randomer with unknnown intentions.

I'm left thinking of how Go does it, whereby repositories are downloaded via git or whatever version control software's URL. Making it impossible for the admins of "NPM" to take down a package. Add in IPFS and you've got one heck of a "package manager" I guess Go's approach is not really a "package manager" but nobody can truly stop you from downloading from a git repository, and if they do, you can go to the forks etc.

The same can happen with GitHub repositories, though, that is how the vast majority of Go packages get published.

It's almost as if privately controlled, centralized archives are a bad idea.

1. However, it would deal with GP's problem - that is, that somebody else could upload a package with the same name as one of the ones removed and cause ... surprises the next time someone runs npm install.

Github repos are namespaced to their owners, at least, radically reducing the potential for this kind of thing.

2. /s/github/whatever . As long as there's a public URL from which something can be cloned, the idea still works, as long as that URL doesn't someday point to something completely different. Again, not impossible, but less likely than with NPM.

3. There are, like it or not, real advantages to centralised archives - discoverability, optimisation of dependency resolution, etc. 'Privately controlled' is an elastic idea - it seems to me that there's a difference between a non-profit foundation, say, and a for-profit company like NPM or GH, but both are 'privately controlled'. The question is whether these advantages outweigh the disadvantages. In my opinion, they do.

About your third point, discoverability and optimization of dependency resolution can be solved by a proxy, in a decentralized system, like the one used in Go.

IPFS with public keys per developer and signing of packages would solve that.

Except Go isn't GitHub specific, I could use BitBucket, Gitlab, or any service I setup myself. Even locally, just like git itself I suppose. Go supports other tools like Mercurial as well as others.

Hasn't hurt Java devs any. Although we have plenty of mirrors and no concept of unpublishing.

The vendor experiment provides a nice solution to that problem. Check in the vendor directory into your own repository and you always have the required source code available, even after the original author removes his repository on github.

It's just as bad. Commits can be re-written and/or deleted. I've always been surprised that anyone thought release management based on SCM commits was a good idea. It's not.

Without IPFS, pretty sure authorities can order to take down the repository and all of the forks.

This seems like a serious security risk. Is there any solution? Would using version numbers without the caret work?

Not only is there a solution, but it's pretty well known computer science. Use public key cryptography to create a digital signature. It's not even a novel use of this -- .NET has been using this to sign assemblies and packages from day one.

I think he means a solution to the current problem of the packages being replaced with malicious ones, not the problem with npm not supporting package signatures.

Package signing by the package's author /is/ the solution, right? This way the only entity that can publish a valid update is the the package author. This still has the problem of bootstrapping the trust relationship, and leaves the door open to the author publishing a malicious but signed package or the signing key being stolen and used to do the same. However if you don't trust the package author to be responsible or take precautions against the keys being stolen then you're essentially taking on the burden of implementing of your required functionality.

We also need some way to link packages to authors. In the Java world packages are supposed to be in a namespace that's the reverse domain name, so you could (potentially, theoretically) connect that up with something like DNSSEC and enforce that people can only publish packages for domains that they control. (Though even that is really just punting the problem up to the DNS registries).

I like your use of "Look, even .NET does this, people".

Signing using private key?

There is no need to sign. Just keep a cryptographic hash (SHA256 is a good bet) of the package in the dependencies manifest, and check it after download.

Using a git repository gives you that for free.

Attacker changes package, then changes hash in manifest to match. Checks pass, users are compromised.

Attacker clones git repo, creates new commit with trojan, pushes to repo with compromised credentials. New users clone compromised repo, others pull and fast-forward. All hashes are valid.

You need to read the Strong Distribution HOWTO: http://www.cryptnet.net/fdp/crypto/strong_distro.html

I don't get it. If I keep a hash of every dependency in my project, and an attacker change a dependency, I will detect the attack by computing the dependency hash and comparing it with the one stored in my project (for example in the dependencies lock file), which cannot be changed by the attacker.

> ...which cannot be changed by the attacker.

That's fine on your personal system, where you manually update your package's dependencies and manually update the hashes of your package's dependencies.

Now, what happens if an attacker compromises the repo where people download your package from? Or what if he executes a MitM attack on the repo or a user who downloads from it? He can change the entire package, including all manifests, all hashes, etc. Users who download it will be none the wiser. By the time someone notices and corrects it, people will have downloaded the compromised versions and be infected.

The only thing that protects against this is strong crypto signatures. For example, if a Debian mirror were compromised and an attacker uploaded compromised packages, users would be safe, because apt would refuse to install the packages, because they would fail signature verification.

Please read the link I gave. It explains everything in detail.

SHA1 collisions are affordable for large actors now and getting cheaper all the time, so git, with its SHA1 assumptions hard-coded, unfortunately doesn't protect you anymore. But the local hash approach is a good one, proven in pip 8 (Python) and npm-lockdown (JS).

More for new versions of same software where the account might be highjacked but hopefully the key wasnt. I dont think a hash would help.

You can use github and get namespacing under the author.

IMO, this could end npmjs of they don't fix the issue.

You don't get any prepublish hook when pushing to a git repository though, so you can't do things like preprocess with babel, typescript, etc, unless you check in the compiled source.

You do, actually, if you've setup the git repository correctly.


Check out the pre-push, pre-receive, update, and post-update hooks.

Those hooks aren't tracked in the repo though, are they? In many cases that will be inconvenient.

They're placed in the repo itself, under .git/hooks, rather than in the working tree. If you want to version them, you can always place a symlink in .git/hooks and have it point to a file inside the working tree. Note that this won't work for bare repositories (which have no working tree), but usually in that case you want a separate deploy process where a sysadmin (or build script) manually copies over files, to prevent a random dev from borking the repository, which a bad update hook can easily do.

(This doesn't help with the GitHub case. But then, as we saw from the recent CocoaPods story, using GitHub as your CDN is probably not a great idea either.)

Well, sure, but that's complicated, and ".scripts.prepublish" in package.json is not. I'd love to have the git knowledge to do what you've described here without googling and frowning, but I don't have that yet, and I've been using git for years. Whereas I could use package.json to accomplish the same task on basically the first day I used npm.

And always use head? I think we still need versioning (potentially fuzzy). Also, isn't that what bower does/did?

You can provide any tag, sha, or branch which can be supplied as an argument to git checkout.

Also explaining nicely with real life to the face why you should only use specific versions, or at least specific ranges for your dependencies.

Legally isn't it totally NPM as a company to publish existing versions of left-pad because those versions were already released under a license that allows redistribution, whether the author wants them to or not? Or can the author effectively veto this?

Good question. Under something like GPL or Apache, npm (or anyone, really) would have a clear legal reason to continue using and redistributing the code; there's nothing the copyright holder can do about that (unless you actually violate the license terms). Under WTFPL, that's certainly the intent of the license, but I haven't heard any court declaring a case based on WTFPL, so you don't actually know what the courts would make of it. But in general, yes, I'd bet a court would let people do what the f* they wanted once they got some code under WTFPL.

The separate question is: ethically or business-wise, do they want to continue publishing code from an author who explicitly tells them not to? Legally they (almost certainly) could, but as a FOSS business, would they want to?

Software Licenses are pretty easy for the basics - after you read the whole thing.

From what I can tell[0], left-pad was released under the "Do what the fuck you want public license"[1], so I suppose NPM can do whatever the fuck they want, including redistribution.

[0] https://www.npmjs.com/package/left-pad (although I suppose its possible the library was added after the package was re-added -- I don't see a license on the GitHub page)

[1] http://www.wtfpl.net/

could we just move our javascript package manager to an organisation rather than a commercial company?

then please use named scope as default like@cycle/core @reactivex/rxjs.

That's how it used to be, more or less. Then they commercialized "to better be able to support the infrastructure".

All the more reason to seek better alternatives?

That's not how it works. You can't publish left-pad 0.0.3 again.

Yes, but I can publish an evil left-pad@0.0.10, and if you're not shrinkwrapping or any sub-dependency has left-pad: "^0.0.3", it will pull in the evil 0.0.10 version.

EDIT: I stand corrected. See below, looks that's not the case specifically for "0.0.x" versions, but gets progressively more relaxed if there's a non-zero minor version specified. However, many of the unpublished packages had varying major and minor versions, which would have the more loose caret range behavior.

No it won't... The caret specifier for 0.0.x packages means "this version and this version exactly".

He's right, for `0.0.x` versions it means "this version and this version exactly"


And to be honest, it's news to me. Sorry i impulse downvoted you...

No problem! It's not super well-known since they switched from tildes to carets and tildes didn't behave that way.

Some examples of how it works:

    ^1.2.3 := >=1.2.3 <2.0.0
    ^0.2.3 := >=0.2.3 <0.3.0
    ^0.0.3 := >=0.0.3 <0.0.4

Why dont they just use that version notation ? (>=0.0.2,<0.1.0) will be much simpler

For every single dependency in most projects that honor semver? ^ is just an extremely convenient shorthand.

You're right, I added an edit to my comment.

That's an interesting side effect.

Wouldn't (shouldn't) npm block same named modules from being uploaded with a different username?

Proposal: go with a java based naming system: com.yc.mymodule.

All installations would require the user to use com.yc.* in package.json and all users would be required to register as a com.yc style organization name. Thus only one user can remove/add that exact module.

npm has namespaces, but they are optional and not hugely adopted as of yet.

Hmm but then is the scope/namespace reserved for each user that reserves/uses it? If I publish @andy9775/left-pad can someone publish under @andy9775/other-module or can only I publish under @andy9775/...?

If so, why is no one using this???

Yes, namespaces are specific to your username. Nobody else can publish packages under your username namespace.

I think it's less common because it was released along with private modules and is often conflated with them. Basically all packages are still namespace-less. TBH I never thought about the benefit they'd have until now.

So left-pad is too important to be removed but Kik isn't? What if the author had originally called left-pad Kik? Why is it ok for the Kik trademark holder to break thousands of builds but not the module author?

This is a very good question. I was going to make the argument that the author merely continued what NPM Inc. started, and that if you fault him, you should also fault NPM Inc., but then I noticed that NPM Inc. didn't unpublish his module, but transfered the name to another account, which is much worse, if you think about it.

The ultimate conclusion is that if it's anyone's fault, it is the fault of the person who relies on NPM Inc. when building his software.

I'm a known downer of npm and node in general and this illustrates how bad npm is about this... You can't just change owners to kik on npm without the previous maintainer's permission. NPM has violated the trust of the community and will continue to do so until someone forks npm and makes an honest community out of it.

What's next? If I have foo.bar domain, can kik come and say I can't have foo.bar/kik or kik.foo.bar? To the people who think npm is right, what if you owned foo.bar and Google decided they didn't want to deal with kik lawyers and redirected kik.foo.bar to kik.com?

> I noticed that NPM Inc. didn't unpublish his module, but transfered the name to another account, which is much worse, if you think about it.

Jesus. This is a disaster. At this point, the only responsible thing to do is to avoid NPM.

I feel like the best way to avoid a disaster like this is for developers to avoid using registered brand names when they write their packages.

It's not difficult, since there are all sorts of rights brand owners can't get you on.

1. You don't really need a catchy name for an open source project, since you're not in competition for funds. Call it something descriptive. Descriptive words can't usually be protected, so you should be fine.

2. In most countries, using your personal name is fine irrespective of any IP rights.

3. If you want to use a catchy name anyway, check on the USPTO TESS database for registered rights. If any are live, choose another name.

Remember when Groupon tried to register Gnome for software applications[0], and the open source community (rightly) came out in force supporting the Gnome foundation? But when it's the other way round, it makes no difference.

The problem isn't IP law, it's just bias.

[0] http://www.pcworld.com/article/2846632/groupon-decides-to-le...

...and do the same for the 200+ or so independent countries in the world with their own databases?

You, my friend, are being US biased.

couple of days ago i was all smug from upvotes for calling npm best practise.

i take that back, npm is a security risk that should be avoided.

now i need a new package manager.

Notice that I didn't talk about the node package manager, but about the author and the company NPM Inc. (and their registry service).

It's not that your "build got broken", it's that you had a broken build process. You are the one at fault. You chose (perhaps unconciously) to rely on various entities, their services, their whims, and they proved to be unreliable.

The simplest solution for those who write an application is to commit the dependencies into the repository as well. This significantly lowers the amount of entities relied upon when building it. (Alternatively, have your own registry, whatever.)

Then you can discuss issues like the ideal module granularity, ethics of this or that actor, names and trademarks, etc. without worrying about your "broken build".

Well, now I'll upvote you for saying something else that seems wise, so it's all good.

That's a good point. Very inconsistent behavior by NPM here.

ooh gosh, they should really do something like ban new projects from using those names until they figure out a better solution, hopefully with the module author.

Seems that we should now prefix any package name with a random string like 'skdjdihsawqy'. This way you could maybe avoid to be the target for some of those 'has to proof itself' lawyers.

Or, you know, prefix with author's username, a la Github.

This would solve classes of issues with the npm ecosystem (many of which remind me of trying to register a domain name) like name-squatting, trying to think up a marketable-but-untaken name, and ownership transfer.

OP claimed a bunch of sweet dictionary words (concat, iframe, door, bud, alert, map) and new owners are now claiming them and it's a security disaster. But it'd be a lot less interesting if they unpublished "azer/map", "azer/alert", "azer/iframe", etc. and new owners republished under their own names.

Elm packages got this right: http://package.elm-lang.org/

Like, can my github username be kik? And if I have created years before they founded kik?

How many years before github would that be?

(Edit: this was written under the assumption that the lawyers in question are working on behalf of kik, the cheap clothes company, not kik, the messenger company. The original article is unclear about that)

This really has to be attacked at the root: let's all stop pretending that a sequence of characters can be owned. Before the web came along, people were completely sane about the protection of brands. Nobody had delusions about string ownership, but deceptive abuse of brand names was suppressed just as well. Enter the web, and suddenly corporations start thinking they somehow deserve exclusivity for their stupid little three-letter-acronym, at first on the DNS, now, apparently, also in search engine hit lists ("oh noes, someone might google themselves onto github instead of our site, people will start wearing NPMs instead of our clothes!").

Ding Ding Ding!!!

That's pretty interesting. I wonder if it's within npm's legal right to distribute someone else's IP in such a way that they do not desire. Granted the license is WTFPL but does that include taking over the IP itself?

> Granted the license is WTFPL but does that include taking over the IP itself?

In some jurisdictions you have "moral rights" in addition to your copyright - but even in those, I'd expect the WTFPL constitutes a license to falsely claim authorship of the covered code. I mean, the text pretty clearly authorizes you to do so on its face, and courts lean pretty strongly towards reading words under their plain, normal meanings. IANAL.

IANAL either, but moral rights are often (usually?) inalienable, so I doubt any license can waive them in those jurisdictions.

That said, I don't think "un-unpublishing" code (even under your own account) is the same as claiming ownership, just redistribution.

> Granted the license is WTFPL but does that include taking over the IP itself?

IANAL but "do whatever the fuck you want to" would seem to include literally everything including taking over the IP.

Yeah I get the "do whatever the fuck you want" but in a legal sense I wasn't sure that could (or did) include actual ownership. I thought that had more to do with copyright and any other IP transferring. Then again I also said I had no idea :)

The more I think about this license, the more I wonder if it's even legally enforceable. How do you enforce a license whose only terms are that it has no terms?

The WTFPL's own website mentions that it's never been tested in court.

> Granted the license is WTFPL but does that include taking over the IP itself

Well, I'm certainly not a lawyer, but I personally think thats in the spirit of the "Do What the Fuck You Want to Public License"... And at the end of the day the IP is still owned by the original author; the distribution of it has changed.

Post Berne, I believe copyright is the default. It may be WTFPL but it appears to be surprisingly hard to actually put something into public domain based on the brief reading I've been doing.

Uh... which part of "DO WHAT THE FUCK YOU WANT TO" is actually unclear here? Is there a word or phrase that you're not grasping?

"DO WHAT THE FUCK YOU WANT TO" clearly includes not only taking over the IP but also RE-LICENSING IT under whatever terms you like. That's kind of what "DO WHAT THE FUCK YOU WANT TO". Do. What ever the fuck. You want to.

How is this unclear? I'm kind of baffled.

Licensing doesn't really have anything to do with copyright / trademark / IP in general. It just grants you the ability to use something in the way specified.

I'm not aware of case law where a license has been able to move the original IP from one party to another; I've only heard of that happening through standard legal documents.

But I also pointed out that I wasn't sure how it would shake out anyway and was seeking feedback.

But why are you saying the copyright was transferred? I don't see anything that implies that. Someone got a copy of the code under an irrevocable license that grants them to right to re-publish it, and that's what they are doing.

> But why are you saying the copyright was transferred?

I don't think I did?

> I don't see anything that implies that. Someone got a copy of the code under an irrevocable license that grants them to right to re-publish it, and that's what they are doing.

Yeah mostly curious if the original author could, say, use the DCMA or something similar to force npm to take it down if he really wanted to.

I mean, you mentioned "take over the IP" and "move the original IP from one party to another", but I don't see why you're asking that, as NPM hasn't taken over any IP (nor has the new user), they simply redistributed the code.

npm didn't take it over, another user did and npm helped re-publish the unpublished version. I already answered the why I asked that..."mostly curious if the original author could, say, use the DCMA or something similar to force npm to take it down if he really wanted to."

But the user didn't take over the IP, it only took over the name on NPM's registry.

As for the DMCA, usually not since most FOSS licenses are explicitly irrevocable, but with the WTFPL, who knows.

> But the user didn't take over the IP, it only took over the name on NPM's registry.

That's almost the same thing. Like if someone dropped their domain name and you grabbed it up. The customer / user isn't going to notice a difference but it's now being represented by someone else.

I don't think anyone cares enough to really do anything about this though. Mostly curious if it was possible to do something about it but I'm guessing the waters are pretty untested.

This is extremely severe. Any package i install might after x levels of sub-dependencies pull in one of these names which are potentially pwned. React and Babel pulled in a few of them to take some well known examples.

I would say the whole npm is pwned until these packages are either restored or that the package name is blacklisted/reserved. Is it possible to blacklist packages locally so I get warned if they are pulled in as sub dependencies? I don't trust every package maintainer to be quick enough to remove these dependencies.

Because NPM knows a module has been unpublished, it can try to be smart about it and change existing package.json so there will be no more updates to that module.

I also think dependencies should be non-flat/tree/static. So that you only have to trust one dependency, and not all of it's child dependencies and their dependencies too. You should only need to manage your own dependencies, not other peoples dependencies.

There should also be a way to contact everyone who use your module, so you can tell them about critical bugs etc.

I wrote to kik's chatbot, maybe she has a heart https://twitter.com/andrejlr/status/712887779185831936?s=08

As I understand it, even if a package is unpublished, that does not (normally) free up its name.

NPM could go blockchain. Tune for fast commits, eventual consistency and slow deletes. Slow enough to allow modules with global names to be replaced. https://github.com/ethereum/wiki/wiki/Ethereum-Development-T...

One interesting thing to me, is that it is pretty clear that the kik lawyers pretty dramatically over enforced their trademark.

For those who don't know, the purpose of trademarks is to prevent customer confusion; essentially we don't want people to be able to sell cheap knock-offs of someone else's thing without the general public being able to easily distinguish between them. In practical terms, trademarks are "scoped" by their "goods and services" declarations.

For example, Apple the device manufacture[1] and Apple the record label[2] could both be trademarked because they had non-overlapping goods and services declarations... until iTunes started selling music[3].

If you look at kik's trademark application[4], you can clearly see that the trademark is limited to chat/media consumer applications, a pretty obvious over enforcement.

[1] http://apple.com

[2] http://applerecords.com

[3] https://en.wikipedia.org/wiki/Apple_Corps_v_Apple_Computer

[4] https://trademarks.justia.com/858/93/kik-85893307.html

Most Germans wouldn't know that kik is also a chat app ;-)

"KiK is the largest textile discounter chain in Germany and operates about 3,200 stores in Germany, Austria (since 1998), Slovenia and Czech Republic (since 2007), Hungary and Slovakia (since 2008), Croatia (since 2011) and Poland (since March 2012)."


Being from Germany, I had initially assumed that was in fact the company in question. I was wondering why a textile discounter would care about some NPM module...


There is a British company selling eCigs called Kik.co.uk too.

Seems Kik is a fairly common term, even for companies.

This shows the claims from kik messenger are not valid, at least in Germany.

The Apple thing doesn't work though, for a specific reason: it's a very common word/name.

Smith is a very common surname. If one person starts the Smith Automobile Company and another person starts the Smith Farm, obviously there's no issue there. That's because none of us invented "Smith", it's understood to be a common name, etc.

On the other hand, if I start "The Google Paper Company", I'm pretty damn sure I would quickly and easily lose that case, despite the fact that google does not sell paper. And nobody would think that is weird, because Google is very obvious an invention (Yeah, I know, "googol", but the spelling makes it unique).

"Kik" is a lot closer to the "google" situation than the "apple" situation.

That is not how trademarks work. Feel free to start the Google Paper Co. Uniqueness is not a merit for trademark infringement. To infringe you have to be a competitor.

That is how some trademarks work. Google is by now a famous mark and, as such, gets additional protection beyond what mere mortal companies do: http://itlaw.wikia.com/wiki/Famous_marks

I guarantee you won't last long if you start a Coca-Cola School of Hairdressing, even though the beverage company doesn't compete for that business.

If that is the case, then it just further invalidates the argument for Kik because it is most certainly not a famous mark.

Famous and "Unique" aren't the same thing. I was responding to the theory that because "Google" is a made-up word, they'll receive extra protections. That's false. That said my example was a bad one, since Google is a famous mark Google Paper Co. would likely be infringement.

Feel free to start Kik Paper Co, however.

That is incorrect. You are also infringing if people could reasonably assume an affiliation due to your use of the trademark, which would definitely be the case with Google Paper Co. You're basically piggy-backing on (and diluting) the brand recognition they've built.

You are correct in that my Google example would likely be trademark infringement because Google is a famous mark. Kik is not a famous mark, so for this case the famous/well-known aspect of trademark infringement is entirely moot.

And keep in mind that the OP I was responding to was arguing that if the name is unique it gets extra protection. That's false. Fame offers extra protection, uniqueness does not.

"According to Kik Interactive, as of December 2015, Kik Messenger had approximately 240 million registered users, and was used by approximately 40 percent of United States teenagers." https://en.wikipedia.org/wiki/Kik_Messenger

Are you sure a court wouldn't consider that qualifying as a famous mark? I'm not going to dig into case law, but my guess is it very well could be.

"Evidence relevant to the fame of a trademark may include sales, advertising and revenue figures; geographical scope of use; channels of trade; registrations in home and other countries; past enforcement efforts; and the results of consumer recognition surveys (provided the survey methods are approved by the courts in that jurisdiction)." http://www.inta.org/TrademarkBasics/FactSheets/Pages/FamousW...

> Are you sure a court wouldn't consider that qualifying as a famous mark? I'm not going to dig into case law, but my guess is it very well could be.

Teenagers represent 9.5% of the US population meaning that 3.8% of the US population (using their 40% figure) have "used" their app. Alternatively the 240 million registered users would imply about 3.5% of the total global population has used it.

I can say that I honestly have ZERO doubt that "kik" would never be ruled famous by any possible measure.

I don't know whether you're right or not, but I do know it isn't prudent to have ZERO doubt about anything - but especially legal matters - without first doing the relevant research. And even then, courts disagree all the time, so I can't imagine ever being 100% certain that a ruling would never go a certain way.

To be even reasonably certain in this case, I would need case law of similarly well-known brands being challenged. Do you have some? Capturing 40% of their target market seems pretty well known to me, but again, that's meaningless without the case law.

Check out the case law about Mcdonalds v Quality Inns (re: McSleep Inns)

Mcdonald's was able to show that there would be consumer confusion DESPITE Mcdonald's not doing hotels nor Mcsleep inns not doing food.

As a result, Mcdonalds basically has an open trademark enforcement on "Mc-" whatever.

While I'm not fond of the judgement here, it was nonetheless decided thusly, and contradicts your otherwise accurate (so far as I know) statement. (And to weaken my own point, I believe Apple lost a similar case about i<whatever>, so nothing here is clear and reliable.)

That's not necessarily true if Kik were planning to open up some kind of API. Also, the way the law works in the US encourages corporations to overreach. If you don't try to protect your trademark from every possible angle, it can lead to your loss of it in a court battle. A lot of times, lawyers will send out letters without caring how the recipient responds -- they only need to have sent the letter at all to have covered their bases.

> That's not necessarily true if Kik were planning to open up some kind of API.

Surely opening up a new API doesn't give them retroactive rights to the name in that space.

It doesn't have anything to do with the API. Kik (the company) registered the name and have rights to the name.

Technically, Kik (the company) registered their trademark in the class "Computer Software" [0]. That means that no-one else can use the word Kik (and the logo) for this class of activity. The key issue is when the registration happened. Since they've been going since 2009, and Kik (the software project) only started in 2015, Kik the company was there first.

The reason their lawyers are asking for "Kik the project" to change name is because trademarks can become generic if you're not seen to protect your mark [1]. As a private company (particularly VC funded), IP has a lot of financial value: the business will be valuing their trademark. If they don't protect it then they'll be "throwing money away".

The fact that the business world (and VC's generally) highly value IP is why most people over-register. If they didn't go for wide classes, and then in a few years decided to work in a particular area they might not have rights to their "own name" in that class.

It's a case of the Open Source and Business world-views clashing.

[0] Someone else in the thread found the specifics but the link doesn't work for me. [1] Everyone knows the example of Spam.

> Everyone knows the example of Spam.

Please show an example of someone other than Hormel Foods Corporation marketing a meat product using any derivative of the name 'Spam' and getting away with it.

Spam was mentioned because it's a brand name that became generic because it wasn't protected aggressively enough. Coke, Xerox, and Kleenex are other classic examples of brands that are commonly used generically, and the company owning their trademarks must aggressively send threats (that they rarely follow up on) just out of legal necessity.

Spam very aggressively protects their trademark. So aggressively that it lost a trademark lawsuit against Spam Arrest. (They lost cause people don't get food and junk mail confused)

Indeed, Hormel once sent nastygrams about their trademark to the ASF over our Apache SpamAssassin software. Trademark owners can ask everyone to use or not use their own names. Actually going to court - or actually winning - is far far rarer.

As someone pointed out in another thread, you similarly couldn't name a package something like "facebook" even if Facebook had no API.

there is a package called facebook: https://www.npmjs.com/package/facebook and it doesn't seem to be owned by facebook?

facebook may be a bad example. they named themselves after a generic directory that many colleges have been giving out for decades.

See also: YellowPages.com, Salesforce.com, etc. Just because something exists in real life (and used to describe a non-digital version of the same thing) doesn't mean it can't then be trademarked.

Sum had to change the name of its yellow pages application to nis because yellow pages is copy righted.

You don't seem to be very well informed.

> A lot of times, lawyers will send out letters without caring how the recipient responds -- they only need to have sent the letter at all to have covered their bases.

That is not what happened here though.

Any chance someone at Kik the company wanted to create an npm module and decided the escalation to lawyers was the right way to resolve things? Seems like the lawyer was more interested in getting possession of the name on npm then actually fighting for a trademark. It doesn't even sound like they bothered with a formal cease and desist.

Guess that answers that. Bob may have been going beyond what he should have or what they intended but in the end he represented Kik and they have to take responsibility for that.

Yep, I was going to say the same thing. As you say we can look up the US trademarks [1, 2] and see that this mark covers:

    Computer software for use with mobile phones and portable
    computing devices to:

    - download audio, video, digital photos and programs;

    - electronic payment systems, namely, a computer application
      software used for processing electronic payments to and
      from others;

    - computer software for use with mobile phones and portable
      computing devices to create video and digital photos to share
      with other users; computer software for use with mobile phones
      to launch other applications and connect to other software
That's it.

[1] http://tmsearch.uspto.gov/bin/showfield?f=doc&state=4804:lir...

[2] http://tmsearch.uspto.gov/bin/showfield?f=doc&state=4804:lir...

USPTO Trademark Pro Tip: search links are session specific. Use the blue TSDR button's link instead:


"Providing an interactive website featuring online non-downloadable software" indicates to me that there could indeed be confusion in a repository of software code to be used by other applications.

I'd suggest it's certainly not obvious over-enforcement.

But TFA's "Kik" seems to be sort of a "project generator" like yeoman or something. There is no overlap between that and even the generously expanded description of the litigious "Kik" that you cite.

So, in your opinion, if I built a software application that let you design and order plate glass in decorative form to be placed in the walls of your house and named this app "Windows" would Microsoft's inevitable attempts at protecting their trademark be overreaching? The windows I named my app for are physical things and Microsoft's are virtual, but I'm releasing a software product called "Windows."

Both kik names exist in the realm of software. There's an argument to be made for confusion.

Yes, even this faintly ridiculous fake example of painstaking mental construction would be overreach. No one would ever download your hypothetical architectural software expecting to get an operating system.

As a public service, some toilet or compost bin manufacturer ought to start "violating" trademarks by naming toilets etc. after litigious companies. We'd all get a kik out of hearing them argue that database consumers are likely to confuse the Oracle database with the Oracle water closet. [EDIT: "Sure it's a CRUD app, but I'm more interested in Deletion than Retrieval!"]

Of course there are arguments to be made; lawyers are involved.

People with experience in software wouldn't likely confuse the two pieces of software. But most people think "computers" and stop there. Most people visiting an app store would see "Windows" for 99 cents, buy it, then complain when it wasn't Microsoft Windows. They wouldn't read descriptions, and they don't know what an operating system is.

Confusion. Microsoft is very likely to prevail in the infringement lawsuit.

Those products would not conflict there isn't a giant category called computers and further you can't just take a generic word out of the English language and take possession. Apple is a generic word for example but not in computer technology.

This matter has even already been litigated. Microsoft Windows is a valid trademark, Windows is not defensible.

Please see lindows aka linspire.

That case was settled and a decision from a court was never reached. That is pretty far from claiming a Windows trademark is indefensible.

Microsoft's claims were rejected by the court, which asserted that Microsoft had used the term windows to describe graphical user interfaces before the Windows product was ever released, and that the windowing technique had already been implemented by Xerox and Apple Computer many years before. Microsoft sought a retrial and after this was postponed in February 2004, offered to settle the case. As part of the licensing settlement, Microsoft paid an estimated $20 million, and Lindows, Inc. transferred the Lindows trademark to Microsoft and changed its name to Linspire, Inc. [0]

Oh yeah, it seems like M$ were on the verge of winning that appeal, and only discontinued (and paid Lindows a multiple of its annual profit) out of pity.

[0] https://en.wikipedia.org/wiki/Linspire

Funny that you picked that example windows is actually not a valid trademark at all. This has been tested in court.

Can you provide a link to a case? The only one I recall is about Lindows and that case settled out of court.

Just a general comment about the whole thread: trademark law is far more complicated and particular than you know (unless you're an IP lawyer; then you might appreciate it). Not only are developers used to problems that can have provable or obvious answers, trademark law really hasn't caught up with the speed of the internet, especially the instant and global reach that a domain name has.

- The only thing you can say about a trademark dispute like this, given the information that's public, is that "it depends on the specific situation as well as the perception of a large enough user base who might get confused".

- Trademark owners can ask (or C&D demand) just about whatever they want. What they could actually force you to do in a court is far, far less than what they typically ask.

They have the responsibility to defend their trademark, otherwise it could be abused by a rival claiming they did not adequately defend it. That said, NPM could have just said, "No, stop bothering us" and the lawyers might have backed down, satisfied their attempt to defend the trademark fulfilled their duty.

> They have the responsibility to defend their trademark, otherwise it could be abused by a rival claiming they did not adequately defend it.

Agreed, but you can do this without pissing off everybody in the universe.


Before, I had no idea who kik was. Now, I know them as a bunch of jerks.

Big fail for a "social media" company.

Yeah but literally nobody is going to care about this outside the programmer community, and we're not their target audience.

"Are you a developer? Kik has open-sourced tools and libraries to help you create great web experiences ..."

This is on their homepage. They want developer to use their Pedo enabler API.

>They have the responsibility to defend their trademark

This is not limited to only issuing cease and desists. Kik Interactive can offer a zero cost license for the trademark if they want to assert their ownership, but let the project continue to use their name.

Some lawyers do not favor low-conflict resolutions, and would not recommend such to their clients.

You do not have to defend your trademark against people who are not infringing it. You can only infringe a trademark when you use the mark in the same context it's registered in.


I hear this all the time but have never seen an actual example? Are there any? (Where defense was existent but perhaps incomplete, not nonexistent)

They weren't defending their trademark. They overstepped their declared industry and maliciously had another's software altered with no valid reason.

NPM should have already had policies in place to prevent this kind of tampering with its repository.

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

> 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

The caret character doesn't appear anywhere in the semver spec, so whatever that does, it's non-standard: 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.

Less dependencies are better. This job is to communicate everything you do in a software project: its reasons and its purposes for every piece. For example, application code that will never be in a public API does not need anything as complex and thoroughly considered than a generic library. When it comes to writing a 10 line function that is represented in an existing module, the most likely reason is that I am writing it for my own purposes and without having to explain why I brought in a package to answer a very small problem.

I implemented KeyMirror from NPM once. It's a simple array->object transformation. It's been in production for months without issue. But, I initially got guff from my boss over it for not using the package. If anything, the package is just an example proof-of-concept of an extremely simple idea. But, carrying the bloat of another package next to more relevant packages seems to be more important here than just merely owning a simple piece of code like this.

The 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/

This dichotomy is silly. You should write as little code as possible to do the job required, and should use only the dependencies required. This might be none, or nearly everything, depending on what your app or library is supposed to do.

...and I am in my little python world with "batteries included"...

And I in Java and .Net world, where it is more like "nuclear reactor included..."

...Only that, in Java, it's not exactly the nuclear reactor you want, which forces you to use someone else's solar power plant, and then they deprecate the original nuclear reactor (because it's known to leak uranium) in favor of a second nuclear reactor, which still doesn't work that well because it's the wrong polarity, so now you have three energy sources available in your project and if you plug your lamp into the wrong outlet everything explodes (see the Date/Calendar mess).

How 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.

Having 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.

It's not one less thing to think about which is exactly the point. If you install 1 dep and it has 100 deps you now have 101 things to think about.

Or, you could look at it, it's 101 fewer things to think about. Besides, we're talking about a package that doesn't have any dependencies.

It doesn't have any dependencies yet -- what if leftpad decides it should depend on "pad", which depends on "stringutil" which depends on "unicodeutil" and "mathutil", etc.

I'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?

No. I could find, evaluate and install that package quicker than I could write the code that carefully. And the second time I need it, it's just "remember, install". Also, keeps my code small and focused.

Do you not read the code of packages you're including in your projects? I usually do at least browse through the "beef" of the code for anything I consider adding as a dependency. And try to figure out what's the level of maintenance I can expect, history of bugs, sometimes try to contact the authors, etc.

In short: it would take me a whole lot more time to evaluate whether or not to depend on something as trivial as leftpad than to write it myself. I'm pretty confident I can do that in a minute or two and I trust my collaborators to not break it.

Personally, no, but even if it did, what if a bug is found in the future? The community fixes the bug, not necessarily you!

The 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.

The reality, however, is that if you took this point of view, you will spend your time reinventing the wheel, introducing bugs and wasting resources. That's how it works in real life.

If someone already wrote the base code, we can always fork it and fix a bug or add a feature ourselves if it runs contrary to what the original authors desires.

Even getting a response just so you can know what the original author desires can take a long time and there is no warranties or guarantees that you will even get any response. To me, all the downsides that come with dependencies are not even close to worth it for saving 15 seconds.

Who cares what the original author desires?

If you fixed the bad behavior you're experiencing, and the original author's effort saved you hours or days of coding, what's the downside?

Perhaps I'm not arguing for 15 second long code changes. But other than typing a single if statement, what takes literally less than one minute to securely change in any partially-complex project?

Fair point. One does run the risk of having bugs in code out of their control by using a package manager such as NPM, but one gains a swath of other programmers inspecting the modules for bugs. And in module repositories for interpreted languages, its very much in your control to fix any bugs you might find, regardless of what the maintainer might say about it.

Would simply copying something into your project as small as 17 lines make for a good compromise?

No - then you won't get updates easily and everyone reading your project would have to make sure that your copy of the module hasn't diverged from the original module before working with it, especially if it's a larger module that has full documentation and a community of people who know how to work on it.

I've never seen so many programmers advocate copy/pasting code before... it's really surprising!

Something about javascript makes people crazy...

That's what I thought, but what concerns me with 100's or even 1000's of dependencies is managing them. Things like figuring out which ones have security issues without reading the issue tracker for each.

I'm curious since it strikes me as a hard problem to solve: How do you resolve having to deal with security issues with tens or hundreds of dependencies (and their dependencies)? How do you even know whether they have a security issue or a version bump is just a bug fix without digging into each one on a regular basis?

How do you know that you, as a lone developer, aren't writing insecure, unperformant, buggy code?

That's a fair point. But what would concern me, as a lone developer, is liability if you get hacked due to a known vulnerability in an npm module. If the company is looking for a head to roll and someone points out it was a known and resolved issue in later versions that could be a problem for me.

Does npm let you tag releases as security fixes? That would make automation to discover it possible.

NPM itself is clearly faulty, but I don't think the concept of outsourcing logic to dependencies is. If something is complex enough to have a legit security vulnerability, it's probably the sort of thing I don't really want to write myself. And yeah, that comes with the responsibility to stay up-to-date. But pretty sure my head would rightfully roll anyway if I wrote my own bootleg SSH protocol and got my company exploited.

> 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.

That's... very naive. No one goes back and rewrites perfectly working code just to change a library. If it works don't touch it. Computers don't care, and if you rewrite it, you're introducing a bug. Also, there's plenty of new code to write! And oh yeah you have a billion little libraries, all used by an engineering culture constantly distracted by the new shinny, so you're going to be stuck with libraries that that haven't updated.

You're gonna have a bad time.

Personally 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.

The overhead is in your management of your dependencies. The size of the module isn't the problem, it's the fact that you end up using so many of them (especially recursively).

Consider this specific case. This author moved all their modules from one hosted location to another. Now, if you want to use these modules from that author, you need to update the scripts and configs that install them (some package.json files in this case). In a better world, like the C or Python world, you might need to update one or two urls which point to a couple of this author's popular libraries (maybe one you use directly, and one used by one of your handful of direct dependencies).

In this crazy npm world, this author has 272 modules. Maybe 20 are in widespread use ... it's already a lot of work to figure that out. Maybe you use a couple directly, and your dependencies have private recursive sub-dependencies on additional copies or versions of these or other of this author's modules! Maybe you have to cut your own versions of some of your dependencies just to change their package.json to refer to the new URLs! Anyway, you probably have to sift through hundreds of your dependencies and sub-dependencies to see if any of them are included in these 272 moved modules.

I've seen npm dependency trees with over 2000 modules (not all unique of course). That's totally unmanageable. I think that's why privately versioned sub-dependencies is a big feature in nodejs: so you can try to ignore the problem of an unmanageable dependency tree. But if you need to make reliable software, at some point you need to manage your dependencies.

I agree that NPM needs to push namespacing much harder, as that would make the whole process much easier.

Also a "provides" field could go a long way into stopping issues like this. Allow packages to say that they provide a package in them that is compatible with another in these version ranges.

That would let "API compatible" packages be dropped in to replace even deeply nested packages easily, and would allow easy "bundling" in big libraries while still allowing easy creation and access to "micro libs".

I really believe that composing tons of small libraries is the way to go, but there needs to be better tooling to make it work. In my (admittedly not extremely expirenced) opinion, bundling many small libs into one big package to make it manageable is a symptom of a problem, not its resolution.

This will become easier with rollup, webpack@2, and so on, which can effectively reduce the penalty of including large modules like lodash by tree-shaking out all of the parts you don't use. I would expect many more utility libraries to then be aggregated into a single package/repo and for users to simply pick and choose functions at will.

By 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.

I'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?

"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.

IMO that doesn't change anything.

The fact that in JS land it would be it's a standalone module means you get more choice in what you need (no need to pull down 100 programs if you only need 1 or 2).

You have the same amount of choice. There's no reason that you have to use the other hundred pieces of the package. In the Unix world, there's nothing precluding you from deciding to use the FreeBSD version of tar but keeping the rest of the GNU utilities there.

I guess it's a philosophical difference.

But to be fair this would have the same outcome if left-pad were part of a library that included another 50+ libs (that he also wrote and published, and subsequently un-published today).

More choice, but now you need 50 different modules from 50 different authors to duplicate what would be in one good standard library, any of which could have bugs or be pulled out from under you for a multitude of reasons that are beyond your control.

Choice can be a bad thing too - when there are 10 different modules for doing a moderately complex thing, you have to figure out which one is best for your project, and whether it's still actively maintained, bugs are fixed, how do they feel about making breaking changes, etc.

>now you need 50 different modules from 50 different authors

Not necessarily, take a look at lodash and friends. There is nothing stopping bundling of tiny modules into big "libraries" to be used.

As for the rest, you need to do that validation anyway. But if it were bundled in a large library there is MUCH more code that you need to review.

with something like the module "left-pad", it's a no brainer to use the library. I know that it's under an EXTREMELY open license, the code is really small, and by vendoring your dependencies (you are vendoring your dependencies right?) this whole issue would have been a 5-10 minute fix that only needed to be done when you want to upgrade your dependencies next time.

But also, if you're shipping things to users browsers, please cut out all the stuff you don't use. I don't want to download 100 extra module's worth of JS code because it was bundled.

Why not just put it into the core? Why should it even be a module at this point?

Because in JavaScript there are many different implementations of engines, and they run on all kinds of stuff. Adding something to the standard is not a small task, and it means that it's now extra code that needs to be installed on practically every single PC.

And that doesn't remove the need for a library like this (or your own implementation) for a long time because you can't rely on a brand new release to be available for everyone.

Realistically 17 lines of code is total overkill for this function. In many cases you could achieve the same thing more efficiently in a single line.

Feel free to show a smaller implementation that's more efficient.

I've seen several "one liners" in this thread already, and most of them either blow up when something that's not a string is passed in (regardless of how you view strict typing, js doesn't have it and this shouldn't happen), or are extremely slow comparatively (most of them creating and destroying an array every time they are called).

Plus this has 100% test coverage (even as trivial as it is, it still counts), and is "battle tested" (something like 2.5 million installs per month counts for something).

Sorry, but i'll stick to left-pad vs 20-seconds of thought one-liner.

> Feel free to show a smaller implementation that's more efficient.

How's this:

  function leftpad (str, len, ch) {
    ch = (len -= str.length) <= 0 ? '' : !ch && ch !== 0 ? ' ' : String(ch);

    while (--len > 0) ch += ch[0];
    return ch + String(str);
No local variables, less manipulation of the input string, the string grows at the tail which is more efficient, and the code is much shorter.

(With a bit of work you can use the longer ch string that is built to reduce the number of string appends even more by appending multiple characters at once. Although probably not worth it for this function.)

No offense, but that code is much more difficult to understand. If your goal is to minimize the amount of lines, then you succeeded. If the goal is to produce both correct and readable code, then there's room for improvement.

> No offense, but that code is much more difficult to understand.

I strongly disagree. My code has no magic initializers (the -1 in the original) and a simple linear code path, with no branching. It's very easy to read and understand.

The ternary operator at the top is simply read from left to right, it's not complicated.

> If your goal is to minimize the amount of lines, then you succeeded.

My goal was to maximize efficiency. Often that means less lines, but that was not the overt goal. And in fact this version runs faster, and uses less memory.

> If the goal is to produce both correct and readable code, then there's room for improvement.

You think so?

Then now it's your turn - rewrite this (or the original) to make it as readable as possible. I think you will find that a: mine is more readable than the original, and b: you won't be able to (need to) change much except to lift the len initializer out of the ternary operator in the first line onto its own line.

If you are talking about a module that everyone just includes and expects to work, then I'd imagine the goal would be a combination of correct and efficient, not readable.

I wasn't planning on passing a non-string to my function. The type-checking only needs to happen because this is a needlessly generic function

Okay, but then when you pass a string that's just `12` in and get `16` instead of ` 12` don't blame javascript...

I didn't intend to, although since I was going to prepend a string to the start that would be a rather surprising result

Re-inventing the wheel in 17 lines of code is called programming.

Someone 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"

Essentially all JS engines implement string concatenation lazily as ropes so there isn't much difference.

Well, you can do it in O(log(n)) time instead of O(n) time. But n is unlikely to be large enough for this to even matter a little bit.

"A little copying is better than a little dependency" - Rob Pike

In 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.

I 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/is-positive, https://www.npmjs.com/package/is-lower-case)

The 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.

I 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?

I 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.

Which 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.

Why would this be a bad thing? I don't need a random number generator if I just want to allocate memory.

Because 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.

Not 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.

Some of this things you mention are true, but:

> makes security auditing more difficult

What? If you go all the way, you just review all dependencies too. And if they have a good API, it's actually much easier. For example if your only source of filesystem access is libfilesystem, you can quickly list all modules which have any permanent local state.

Splitting huge libraries into well designed categories would make a lot of reviews easier.

> 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.

Also disagree. One-off builds shouldn't make a real difference. Continuous builds should have both local mirror and local caches.

Yeah but that's not the world of NPM. It's a clusterfuck of a maze of near duplicate dependencies with no hierarchy or anything. There's no organization or thought. It's just a bunch of crap tossed together to encourage cargo cults programming.

Think about the test matrix.

Taking 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.

Quite a bit are pretty small.

Erm, 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.

What on earth is cat doing that it needs 36KLoC (with dependencies)?

I'm starting to see where http://suckless.org/philosophy and http://landley.net/aboriginal/ are coming from (watch Rob's talks, they're very opinionated but very enjoyable).

Yup! In fact the only other data point I have on cat is http://landley.net/aboriginal/history.html which complains about cat being over 800 lines long back in 2002 :)

I didn't dig too deeply in 2013, but I did notice that about 2/3rds of the LoC were in headers.

>"When I looked at the gnu implementation of the "cat" command and found out its source file was 833 lines of C code (just to implement _cat_), I decided the FSF sucked at this whole "software" thing. (Ok, I discovered that reading the gcc source at Rutgers back in 1993, but at the time I thought only GCC was a horrible bloated mass of conflicting #ifdefs, not everything the FSF had ever touched. Back then I didn't know that the "Cathedral" in the original Cathedral and the Bazaar paper was specifically referring to the GNU project.)"

The version of cat.c here: http://www.scs.stanford.edu/histar/src/pkg/cat/cat.c has 255 lines in the source, and brings in these headers:

#include <sys/param.h> #include <sys/stat.h> #include <ctype.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>

which are needed for things like memory allocation, filesystem access, io, and so on.

One can imagine alternative implementations of cat that are full of #ifdefs to handle all the glorious varieties of unix that have ever been out there.

The 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.

But 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.

Underscore/lodash is a great bundle of functions that do simple things well. And it's a tiny enough library that there is really no need to split it into 270 modules.

I support packages of utility functions. Distributing them individually is a waste of resources when you have tree shaking.

I trust a dependency on lodash. I don't trust a dependency on a single 17 line function.

While I agree with you, tree shaking is relatively new in the JavaScript world thanks to Webpack 2 and Rollup.js before that, if you had a dependency you brought it's whole lib into your project whether you used one method or all of them. So just including Lodash wasn't an option for people who cared about loading times for their users. A 17 line module was.

Closure Compiler's advanced mode (tree shaking) has been around since 2010.

Lodash has been modular since 2013.

yes, 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.

Woah woah. Hold on there. Lets not throw around strong words like "worked", "concept", "entire", "fine", "did" when discussing NPM.

This. 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...

Windows has always been a problem for Nodeland, thankfully Microsoft is working on making that better.

is unpublishing a module extreme?

I wonder how long /usr/bin/true source is.

On 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.

On 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.

Let 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.

The 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.

I 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

Less 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.

> 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.

Who 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

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact