On npm and Homebrew

Homebrew is a Mac OS X package manager created by Max Howell.

It’s git-based, somewhat opinionated, and managed by a handful of volunteers that review patches sent in by community members. Its purpose is to install unix programs and shared libraries, but Homebrew is designed with OS X in mind: by limiting the scope of the problem, they manage significant gains in performance and functionality. Homebrew’s featureset and politics reflect that problem set well.

I’ve said before that writing a package manager is easy. It is. Maintaining one, and managing the community using it? Whoa, boy, that gets tricky fast. The Homebrew guys have done an admirable job of steering that ship through a tricky bit of sea that few dare to deal with.

Almost as soon as npm was unleashed on the Node community, some helpful folks helpfully decided to help us all by putting npm into the Homebrew index. I was so thankful to be helped in this way! I love Homebrew, and now my program is in it? Oh, Joy of Joys!

And thus began the great wailing and gnashing of teeth.

The Problem

npm is a package manager. It is not git-based, it is as opinionless as I could manage, and anyone can publish anything. (I do maintain autocratic powers over the registry, but I am a very lazy dictator.)

npm is designed to install NodeJS programs and module libraries. While you could in theory install anything with npm, that’d be a little dumb. It still lacks (and will likely lack forever) some features you’d really want for that purpose, and has a bunch of features that are specifically designed for node programs. It makes no assumptions about pre-existing operating systems, libraries, and so on.

I’m not sure one could say whether or not npm’s approach is better than Homebrew’s. For its use case, certainly. But Homebrew is a perfectly lovely package manager that fills an important niche very nicely.

Better or worse, the Homebrew model is not very amenable to npm’s way of doing things, and the shoehorning caused some of the worst sorts of bugs: The kind where “It works”, and then 2 months later “It doesn’t work.” What’s worse, the error was reported to the user as an npm problem, so I frequently found myself dealing with confusing debugging information, and giving users solutions that didn’t fix the issue.

The standard response quickly became, “It doesn’t work with Homebrew. Remove it, and install it using the instructions in the README.” What’s worse, the changes that caused these issues were in the Homebrew index, and not in npm. Even if I’d wanted to code around the problems, I couldn’t just do that in npm itself.

It was not easily fixable, and very frustrating. I had more than enough work to do on npm itself, so it was always pretty easy to just blame the other guy, and go back to work. But this was not the right course of action.

The Solution

One day, in a fit of frustration over the situation, having just painfully explained to two users in a row that their most beloved package managers have both been lying to them, I managed to raise the ire and disappointment of Jan Lenhardt. Luckily for us all, he had the pre-existing notion that I’m an ok chap, and decided to give me a swift kick in the ass rather than setting the bozo bit. He deserves a lot of credit for stepping in when and how he did.

I opened up an issue on the Homebrew github page, started a pull request, and Mike McQuaid and I duked it out for a while.

We all knew at the start of the discussion that just removing npm from the Homebrew index was a potential course of action that would solve a lot of problems with very little cost to everyone. But none of us wanted to do so capriciously, without at least riding the solution train to its logical end.

Mike and I eventually got to a rewrite of the npm recipe that we could both live with. It wasn’t great, but it was much better. And, really, there wasn’t any way to improve upon it further, without rewriting major chunks of one or both of our programs.

Max made the call to remove it. I agree with him. Better for a feature to be intentionally lacking rather than subtly broken.

Takeaways, and The Future

The debate was fruitful, and helped inform the development of npm and node. I’d like to think it was somewhat profitable for Mike and Max, as well.

There may one day be an npm recipe in Homebrew again. But at least not until npm 1.0, when things settle out a bit.