npm (and the CommonJS module system) is the #1 reason I use Node.js. I don't care if Javascript is ugly, npm totally makes up for it. I don't get why most module systems implicitly import symbols in the scope (Python, Ruby) or worse, those that pollute the global scope (PHP).
Brew (Ruby) is not that bad but Python's package ecosystem is a complete mess (distutils, setuptools, pip, etc.). Cabal (Haskell) is pretty good too in comparison to C/C++ (installing dependencies usually involves following instructions in a README file, that is, if there are available instructions for your OS). I haven't tried Go.
I believe the language of the future will be built around, and win mainly because of, its package system/ecosystem.
</rant>
npm is easily the worst. Python is a lot better. I hold the C library model as the golden standard, so we're not going to see eye-to-eye.
The worst part of npm is the sub-dependencies. Having enabled them, they proliferate endlessly. Each time I improve the efficiency of deploying a strictly controlled tree of modules, the front-end devs manage to double the number in use. 200, 350, 650, over 1000... oh and these improvements come from realizing that npm-shrinkwrap isn't 100% reliable, and ending up with scripts comparing npm-ls output and doing full wipe and replace with a tarball for even the slightest change to the dependency tree.
If some serious bug is discovered in one of these things, there's no way the 20 copies of it at various levels of this tree of 1000 modules are going to get patched. No one really has a handle on what's in these hundreds of megs of various versions of modules. This is the true fast code movement - serious problems can't be fixed in there, they'll just be ignored and replaced with other bugs in the twice-yearly full rewrite. Don't get me wrong, our frontend devs are among the best I've seen, but the pressures and environment they're in make them focus on churning out the latest fad in web design and skimping on engineering quality everywhere possible.
Python doesn't do implicit import of symbols into a scope if you don't use "from blah import (star)". Don't use the (star).
Managing, and using, a list of python modules, each at a particular version, is way simpler, more reliable, and more efficient (than npm style). Pip can reliably list installed module state (freeze) and install from source tarballs or git tag checkout.
You need to fully control and understand the versions of all libraries installed and used on a system in order to have a fully reproducible deployment state, and be able to reliably roll back to a previous state. Given that, the Python or C model is much easier to work with.
</rant>
So basically, I think your point is that a project should have as few dependencies as possible whereas I think the opposite is good. Both philosophies have their pros and cons. If you are writing mission critical software that handles financial data, it's probably a good idea to know about every line of code that gets executed. However, if your goal is to release something as fast as possible, have a more manageable code base and security is not as critical, using lots of dependencies makes sense.
Sure, it's space-efficient, but disk is cheap, and developer hours are expensive. I certainly wouldn't want two employees burning man-hours trying to figure out why some app is behaving differently on their respective machines, only to fix the problem and unwittingly break another project in the most expensively subtle of ways.
I'd really like to think I'm missing something though, I certainly don't presume to be more insightful than the collective Go team.
So, for example, github.com/natefinch/lumberjack is an import path. When I wanted to change the API, I have to put my project at a different import path so I don't break projects that use this version. I could just make a new github repo called lumberjack-v2 and that would work fine.
Of course, reality and theory don't always see eye to eye, and the Go community realizes this. That's why there are several community-made tools to help out.
The most well-respected one is godep, which has the ability to pin revisions on your dependencies. That is, it'll look at the git commit hash (or equiv for hg/bzr/svn) for every repo that you depend on, and record it in a file in your repo. It can then reset those dependencies to those specific hashes. Then all members of your team just need to use godep to make sure they're all using the exact same git commits for all dependencies. Bam - now you're insulated from someone updating a dependency with breaking changes, and your team can test new revisions and decide when they want to start using them.
Godep has a second function that lets you copy all your dependencies into your repo and renames all import statements to reference the copied paths. This is an even more extreme version of the above, which not only insulates you from changes in dependencies, but also insulates you from those dependencies disappearing entirely.
I don't think that was ever said; I claimed that trading disk space for developer hours is a good trade-off in this case.
> The npm-style dependency tree enables and encourages much more complexity, which developers then have to deal with when debugging or deploying.
I don't believe this is the case. When developing an app (as opposed to a library) it's considered a best practice to check your node modules into source control, ensuring that there's never a mismatch between installed dependencies on developer machines. If you don't want to do that, you take what comes - but even before I picked up on that, I never ran into issues even when collaborating with 5+ developers. You just need to make sure your package.json locks your versions appropriately.
The thing I love about Go's packaging is that your VCS and package manager are the same thing. There's no need to wonder where the code from package foo comes from... because you know you imported it from github.com/jimbob/foo It also means there's no fighting over namespaces, since it's just done by domain name (i.e. I can have the package npf.io/foo because I control that domain, and I don't have to to fight over who gets to use that name).
npm is without a doubt the best module system I've come across in my years of development. RubyGems is kind of a pain, .NET dependency management is a joke, Python is super fragmented, and Go doesn't have one. Godeps is an okay tool, and `go get` is cute, but I have yet to use a package manager that couldn't stand to borrow a thing or two from npm.
That's the nice thing about using tools written in Go. There is no npm install. There's a file copy. Bam, done. You don't even need to know it was written in Go unless you're using the code for your own development.
The magic folders in the filesystem exist in every package manager, it's just more obvious in Go. So, for example, npm puts code it downloads into /usr/local/lib/node. I'm very far from a Node expert, but this doesn't sound terribly different from GOPATH.
There's just the one go tool to install, which can be installed just by unzipping a zip file. From there on in, you don't need any other tools. It just uses VCS for package management. You don't need an IDE... the single go tool has support for pretty much every part of the development cycle - compiling, testing, code formatting, profiling... there are no other tools you need to create real deliverable software. I've been writing Go for over two years and still haven't added any other tools to my standard workflow - git and go are the only two commands I type while writing go code. (At work we use a revision pinning tool, but I haven't needed that on my side projects.)