Re: Tyranny of NuGet
My old friend Mitch Denny (it's been a while!) wrote about the Tyranny of NuGet.
In addition to these two popular uses, NuGet is also used by the new PowerShell Package Management tools as one possible source/provider of packages, once again for installation of software. And finally, NuGet is also exploited by deployment management tools, one of the most popular being Octopus Deploy as a way of shipping files from the package source to an agent responsible for remotely installing software. ... Personally I think that using NuGet for software installation as opposed to dependency management is an abuse of the technology.
I wrote something about this in 2013 in Wanted: a universal application packaging format for .NET. Octopus currently uses NuGet heavily, because there aren't much better choices.
I actually agree quite a bit with Mitch, even the "abusing" part. What I think Mitch missed in the discussion is that there are two parts to NuGet:
- The NuGet package file format
- The NuGet repository protocol
It's actually the repository protocol that compels Octopus to use NuGet; not the package format. In an ideal deployment automation scenario:
- We'd build our binaries once
- We'd package and stamp them with metadata (a version number at least) so we know what's in the package
- We'd store them in a place where we can refer back to them at any time
Keep in mind that in deployment automation, there are often more than one "living" package at a time. 1.3 is in staging and needs to go to production. 1.4 has been tested and is ready for staging tomorrow. We don't want to rebuild from source code, and we can't just have a "latest"; we need to track versions.
With MSI's, of course, you can do #1 and #2. But how do you do #3? We could chuck MSI's on a file share, but there's just no ecosystem of tooling support around that, no standardised way to sort and query.
More importantly, how does a deployment automation tool make it easy for various build tools to contribute packages to #3? How can we query #3 to work out what versions are available?
The NuGet repository protocol defines all of that, so by using NuGet packages, packages for Octopus can be stored in a ton of places:
- Octopus itself (built-in NuGet repository)
- TeamCity (which speaks NuGet)
- VS Online (which (finally!) speaks NuGet)
- Proprietary repository managers like Artifactory, Nexus, ProGet
- Self-hosed NuGet repositories
If Octopus was based on MSI's, how would we ever integrate with any of those tools?
I'm happy to admit that we're abusing NuGet. But I'd phrase it as: NuGet would be perfectly suited to what we are doing with it, but the team are pretty focussed on just being a library packaging tools and have tightly coupled NuGet to that problem domain instead of allowing it to be general purpose, which it would otherwise be perfectly capable of becoming. While NuGet is OSS and pretty open, the community using it outside of these intended purposes can't really change that direction.
That said, we're going to open Octopus to simpler packaging formats - plain old .zips and .tar.gz's with a naming convention - because NuGet just isn't suited to the non-.NET universe. But we're still left without a common repository protocol format, so this will only work with the built-in Octopus package repository.
But this is still a very compelling idea to anyone serious about a continuous delivery pipeline:
Artifact repository: it is a key resource which stores the binaries, reports, and metadata for each of your release candidates.
And until anyone can point to an alternative repository protocol that's supported by a whole ecosystem of tools our customers are using, NuGet remains a pragmatic choice for this. Abuse or not :)
Hello, I'm Paul Stovell
I'm a Brisbane-based software developer, and founder of Octopus Deploy, a DevOps automation software company. This is my personal blog where I write about my journey with Octopus and software development.
I write new blog posts about once a month. Subscribe and I'll send you an email when I publish something new.Subscribe