Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Last active April 1, 2016 04:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ELLIOTTCABLE/ea78fcd84d99546c5152948bccc23ad1 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/ea78fcd84d99546c5152948bccc23ad1 to your computer and use it in GitHub Desktop.
Thoughts on `npm unpublish`.
So, this has been an excellent thread, and against all my expectations … I think @jmelfi et al. have
actually swung me around. It's a *really* difficult question, and both sides keep bringing up really
good points, but … there's something really important and subtle here:
Buried in all the (if I'm being honest … super-silly.) ‘legal’ and ‘licensing’ talk¹, there's a
pretty valid concern being raised here; and I think @isaacs brushes up against it in his recent
replies: I'm starting to think that it may be acting in bad faith, for npm to disallow unpublishing
in the main registry.
1. Users *expect* a particular behaviour. There's a whole UX aspect to that, sure, and that's a
little less … charged … but in this particular case, because each possible behaviour can
seriously hurt one of the involved groups of people, it also becomes an, as @isaacs put it,
‘ethical’ discussion. The user's expectations, in this case, are shaped by other package
managers: and yes, crucially, *most other package-managers I've dealt with*, allow the users to
*remove their code²* from the package manager. When they come to Node, and effectively thus come
to npm, they have that expectation: while there are exceptions (I'd posit that they are few; for
instance, I wouldn't count CPAN, as it intentionally *segregates* archived code, and you must go
through *extra work* to depend upon it / use it. I'd be fine with a solution like that.), the
majority of other systems seem to work that way.
Thus, if that is their expectations, I believe it's … well, basically, acting in bad faith, to
break that expectation, most especially in this particular case because this is both a.
emotionally-charged and b. *not reversible* (precisely the topic of hand, of course.) In other UX
situations, breaking with users' expectations causes them an annoying extra few taps in an
interface, or a Google for documentation … in *this* case, it leads to a (potentially
embarrassing, hurtful, … who *knows* what) mistake that will continue to affect them in
perpetuity.
2. If we can all agree that this *hurts* real people, publishing to the repository (I'm not going to
try and assemble a huge list of how people might be hurt by this policy, as opposed to
inconvenienced, I feel I can leave that up to your imagination), then, as @isaacs put it, this
becomes a discussion of either a. who this hurts more, or b. which wronged-party npm, Inc. has a
greater responsibility to protect. I want to address these separately:
b. This may be non-obvious, but if we're being blunt, I think npm is heavily more beholden to the
*content creators* than to the consumers. In an ‘if you build it, they will come’ philosophy, the
dependants *will come* to npm, if the content is there. (This is evidenced by all of the
truly-terrible-to-use³ packaging systems out there, that are still heavily used, because they
‘got in there early’ and gained the preponderance of content / mindshare.)
a. Further, I'd posit that this is in fact *not as big a deal* for the dependants, as it's been
cast to be over the last few days. To go straight to Everyone's Faaaaaavourite Developer
Argument ... I hate to say it, but the people complaining may have been *doing it wrong*. This
is a whole seperate discussion that I'll not even get into here, but I've recently been
thoroughly convinced by a friend (@alextgordon, if you're listening ...) that **end-users**
(applications, etc) **should be vendoring their dependencies.** The authors of Real World
Products depending on CoolPackage should, frankly, have their own copy of CoolPackage, that's
being shipped into production by their own deployment systems; they should *not* be depending
on npm for deployment. (That's a conversation for a different place, I suppose.)
Meanwhile, for library-authors, again, I'd posit that this is *their problem* to solve (as
aforementioned end-users, hopefully, did by vendoring their deps); not npm's. At a glance,
there's lots of viable options, many of which really are very accessible: implement their own
solution, if the dependency was small; switch to an alternative implementation or tool, if it
was large; even obtain the presumably-open-licensed code and publish/maintain a fork⁴ for
their own users! I want to emphasize, though, that in *none* of these situations, is this a
world-ending, or even particularly urgent, problem, for the library authors: all of these
dependant-authors' products are, themselves, libraries or tools: the end-users thereof, having
(say it with me now!) *vendored their dependencies*, are safe until such a time as the
dependant-library-author can preform one of these actions. (“Hey, before 3.2.0, Packifier
depended upon CoolPackage, which [was deprecated]; I'll be replacing it in 3.3.0. Until then,
if you urgently need to deploy Packifier, I've hunted down a copy of CoolPackage [here] ...”)
(Yes, this is a lot of mild annoyance, spread across the ecosystem, for some
person-you've-never-met's feelings. I think we in the JS community, out of all the programming
communities out there, are possibly the *only* group to whom I don't need to justify that
effort needing to occur nonetheless.)
----
Because a lot of the above is pretty philosophical and detached, I want to provide a fictional
case-study, to bring this down to earth. (Rather obviously based on a particular individual,
mentioned elsewhere in this thread.)
Let's say Oakley, for reasons completely unnecessary to elucidate, decides that the software-
development scene is super-unhealthy for them. For reasons that I also believe are inherently
immaterial⁵, continuing to maintain any public web-presence w.r.t. their identity and past as a
software-developer would be as harmful to them as continuing to actively participate. (Remember the
[right to be forgotten][RTBF]?)
Oakley deletes their GitHub, officially disavows any association with their past work, perhaps
discarding with a pseudonym entirely in the process. In fact, let's assume for a moment that Oakley
is super-nice and has the spoons, and put the effort in to support some of their users through the
transition: they published warnings, they found new maintainers for the projects for which they were
able to do so, and they deprecated-in-advance the projects that they could not.
At some point, though, they'd done what they could (and remember: *this was not necessary*. I posit
that we owe them the affordance to do this, regardless of whether they have the ability / desire /
spoons to do the above); and now, the time has come to *depart*. They delete their GitHub (and those
projects that hadn't acquired new maintainers, new forks, *are gone forever*.) They [remove
themselves from Google][Google], they delete their Blog, their Twitter account, so on and so forth.
Now, they come to the npmjs.com page dedicated to their packages. They realize they must undergo an
onerous human-mediated decision process, to regain the *option* to have the remaining packages,
which haven't found a new maintainer, removed. (Remember all that effort they already put into doing
the kind thing? Maybe they don't have the energy *left* to deal with this rigmarole.) Then, once
they engage with the Nice npm Humans ... there's a difference of opinion, and those Oh-So-Nice
Humans decide that Oakley's reasons *aren't reason enough*. (Even if you don't think this would be
the case, because npm really *is* staffed by all the greatest, nicest people I've ever known: does
Oakley think that? This is precisely what's weighing on their mind as they try to decide whether to
even try.) Now, Oakley has no recourse. This is not okay.
----
Now, finally, given everything I've said above, I want to offer some real *solutions*. I think it
*is* possible to offer automated, technical unpublish (or more generally, I think it's possible to
protect the author's wishes.) in a non-human-gatekept manner, without completely ignoring the
desires, needs, and hell, mental-health, of the ‘other half’ of npm's userbase: the dependant
library-authors, like myself.
Assuming `unpublish` or similar is provided, we could:
- Enforce a cooling-off period. (Hell, make it proportional to some heuristic of the number of
downloads-per-month / the number of dependant packages: something with no dependants disappears
instantly, as `unpublish` currently works; something with very few disappears after an hour; and
it tops out, for Lodash or Express, at, say, a week.) Every release of the package is immediately
marked as deprecated / the equivalent of the above `npm disown` or whatever happens; but after
the cooling-off-period, if the author doesn't cancel the operation, *the package disappears and
dependencies fail to resolve.*
- Enact *social* costs. Warn the user, if you have a bunch of dependants, that the operation will
*immediately* e-mail 5,000 busy humans with a notification that they need to start planning to
replace your package. I may be fighting for the authors' health, here, but I'm not beyond trying
to shame them into doing what's best for as many people as possible. `:P` (It might seem a little
unintuitive, but I suspect that sometimes these sorts of ‘soft’ costs can loom much larger in
someone's mind, than the nominally-greater ‘hard’ costs of all these packages breaking.)
- Compromise. Allow auto-unpublish, but place some ‘reasonable’ limitations on it. What those would
be will need more discussion in this thread, but at a thought, it's ‘reasonable’ to disallow a
user from unpublishing, say, fifty packages, without talking to a human.
- Allow human-appeals in the *other* direction. I recognize that the dependants are people too, and
are also capable of feelings beyond ‘inconvenience’ about this. Although I really have come to
the conclusion that the only conscionable thing here is to err on the side of the author, I *do*
think there's definitely situations where the opposite may be the correct response. npm Humans™
may definitely be able to do some good by mediating between a truly-needful dependant and an
author who has unpublished; and in extreme cases, may even be in the right to resurrect an
unpublished package when the absentee-unpublisher is effectively unreachable.
- Finally, (and this is my favourite; I suspect this may be a solution that pleases all involved),
there's CPAN's solution: retain deprecated packages in a separate repository (obviously, one that
is inherently ownership-less: as mentioned above, `disown` should be an inherent prerequisite /
step of `unpublish`, no matter what else happens.) In fact, hell, I wouldn't even be opposed if
you went the extra mile: allow packages to *depend upon* disowned-and-‘archived’ packages. As
long as it requires *active effort* on the part of dependants, as long as it requires an active
admission that the dependant is going against the wishes of the author, and drawing on that FOSS-
licensed-right to continue to use the package ... then I think npm's due-diligence is fulfilled.
In fact, here, I think that bears repeating: **The point here, is that I truly believe that the
dependants need to each, individually, *actively*, indicate their willful acknowledgement of the
package-authors' wishes in unpublishing.** Whether that's by forking, vendoring, pointing your
dependant-library's end-users to an alternative archive of the code, or in the case of that last
suggestion, simply updating your dependency to `"@archive/CoolPackage": "=1.2.3"` and publishing a
new version of your own library ... you're acknowledging the reasons the package was unpublished, as
a human being, and asserting that after consideration, you still believe your needs to supersede
those: “The author decided the entire purpose of this package was untenable and insecure, but in our
specific setting, it's used in a restricted way, and the alternatives are inappropriate.” “I
understand that the author wishes that this work no longer exist in any form associated with them;
but I need to use it locally in development, until later in my project when I have the time to fork
their original work, anonymize it, and support it.” (Hell, even “I really, really don't care how the
author feels, I want to use this.” As long as *npm* has taken the route of defending the author, I
don't see that it's necessary to concern ourselves with how end-users might mis-use the available
tools: my only concern is it becoming the *default response* to disregard the author's wishes.)
Basically: continuing to use⁶ (and more importantly, distribute) some software that the original
author doesn't wish to be used anymore, should be the *exception*, not the rule. I think we should
collectively *very rarely* resort to continuing to use / distribute / depend-on a package that the
author wants to disappear, without a human actively taking upon the effort of forking, sanitizing,
and maintaining the parent project. It should be an *exceptional circumstance*, and npm's technical
decisions should reflect / encourage / even *enforce* that.
----
If I've completely failed to convince anybody with all of the above, and it's still the consensus
that it's best that `unpublish` be removed entirely, here's what I think is the absolutely minimum
necessary concessions to the needs of authors who wish, for whatever reason, to disappear or have
their efforts removed:
- A *giant* fucking disclaimer. Put it on first `publish` of a new package, or perhaps just a
user's first `publish` overall; or even on their first invocation of `npm` overall (not to
mention documentation / website / whatever.) If users are going to be coming from the other
services that *do* allow them to ‘undo’ their mistakes, or to reserve a right-to-be-forgotten;
then they need to be informed *up front* that things work differently around here.
- A *strict* outline for how the human-intervention currently dictated will proceed: what are
acceptable reasons? More importantly, tell us, *before implementing this*, what are
*unacceptable* reasons? It's anxiety-inducing that, however nice they may be, this is apparently
left totally up to the judgement of npm Humans™. `)=`
- Even if the package sources are retained and may continue to be depended upon, they should be
sanitized and hidden: remove `author` / `description` fields and similar from the package.json in
an automated fashion; remove any versions not being depended upon at the time of the abandonment;
and remove such packages from any public npm system (search features, the web-pages, the
author-list, perhaps even remove them from the point of view of any API features; perhaps
`access-disowned` should be a special-circumstances-granted API access-right, or smth?)
- Finally, if possible, prevent *new* packages/versions from being published that depend upon them,
even if you're going to allow already-dependant packages to continue to install.
----
#### Footnotes:
> 1. guys. read the TOS. *Legally*, ignoring ethics, npm has *just gained* the license to do what
> they're saying they're going to do. Like, that's what this entire discussion is about. All
> this discussion of whether FOSS licenses “allow” this or not is … completely irrelevant,
> because by typing `npm publish`, you're effectively *extending* your FOSS license with a
> clause of “oh, by the way, any npm user can download this package, in perpetuity, as long as
> npm, Inc. chooses to host it for them to do so.” Of course, those users can't necessarily
> *use*, modify, *re*distribute, etc, that software … but all of that is irrelevant to the
> current discussion: the point is, you don't get to say ‘my license has a clause that it
> expires in 2018!’, because you've basically voided that clause as it relates to npm, Inc. by
> `npm publish`'ing. Not-a-lawyer-not-legal-advice-etc.)
> 2. I want to make it clear, again, that I'm talking about that very particular, specific action:
> ‘unpublishing’; and I would posit that this action has nothing to do with the licensing: as
> with the blog-post, yes, we know that once this content is out there, we've *legally* allowed
> this code to float around the Internet for years. I'm not saying the publisher should be able
> to press a button and remove their presumably-open-licensed-code from the Entire Internet …
> I'm saying they should be able to press a button and remove it from *npm*. I think the
> distinction is important, and we should stop arguing about the former; it's a misleading
> straw-man. And for the latter, unlike the former, I think licensing has no relation
> whatsoever.
> 3. Note, I'm not saying we should actively make npm horrible for the dependants, or anything! I'm
> only saying that in *cases like this*, where the needs of the dependants, and the needs of the
> content-creators, are directly in opposition, npm might have an obligation to the
> content-creators first.
> 4. I want to expand on this possibility: note, again, as I've mentioned in above footnotes, that
> I really don't think licensing has a bearing on this issue ... but, if we'll opt to pay
> attention to it for a moment, all of the far-above commentary by other posters *is accurate*,
> here. If they published that code under a permissive license, Mx. Dependant Librarian *can*
> hunt down a copy of that code, and temporarily host it for *their* dependants until such a
> time as a better solution can be produced. (And, if it *wasn't* ... why were you using it in
> the first place? :) If it's irreplacable, or if it's simply just Actually Useful to Them (aand
> possibly other people), then, as mentioned above, they can even re-publish/claim/fork/support
> that dependency themselves.
> 5. “There are more [pains] in heaven and earth // Than are dreamt of in your philosophy.” Be
> wary of assuming that just because you may not be able to imagine a situation in which this is
> true for *you*, doesn't mean those situations won't come to pass for others. They have,
> repeatedly, and will continue to, in our current developer culture. /=
> 6. Again: regardless of the license. We have a legal system to protect us from exceptional
> circumstances, but we *very rarely* resort to it, if ever.
[RTBF]: <https://en.wikipedia.org/wiki/Right_to_be_forgotten>
"The European ‘Right to be Forgotten.’"
[Google]: <https://support.google.com/legal/contact/lr_eudpa?product=websearch>
"Google's RTBF forms"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment