NuGet what is wrong with you?
Lets be honest no matter how much I might enjoy developing Csharp back in 2009, when I first started at my job, csharp was on the downard spiral to oblivion. There really wasn’t a community and no was really talking about it besides Microsoft. Things didn’t really improve in 2010 either but somethings did begin to change as NuGet was first introduced and was beginning to be popularized. Before then it was common to search the “interwebs” looking for dlls, downloading them and then hard referencing them to your project in order to do various things. This worked but it came with some major downsides and wasn’t really ideal. On top of that there was no real community no single place to go and marvel at all the different projects and libraries that existed out there.
NuGet and specifically the NuGet Gallery its website really changed things up and in my opinion saved Csharp from an early grave. For that I am forever grateful it replaced hard linking dlls and then commiting those dlls in source control with real package management. It provided a service to version those packages easily and a way to search and find new ways to do things. It got the many communities of open source Csharp together and talking, which lead to more ethusiam. Eventually it brought around Microsoft which seemed to be maybe leaving Csharp for C++. It brought them back into the fold and showed them the advantages of open source.
So again for all those things I am thankful to NuGet. If you fast forward to today 2017, 7 years after NuGet first came out you would see that NuGet is the most integral part of Csharp. Nothing from visual studio to the dot net cli tools would work without NuGet. If I imagine NuGet disappearing tomorrow I would see chaos and rioting in the streets as people lay confused on how to even work. Now maybe thats a little dramatic but really NuGet is so important and the folks that work on NuGet have so much good will and influence on the Csharp world that they could do so much. That is why its so confusing that they are screwing it up so badly.
Before I talk about how they are screwing it up lets talk quickly about what NuGet actually does. What are the basic feature sets and what do people really want out of NuGet. I am going to separate the NuGet gallary/website from the NuGet commandline/vs tool/dotnet cli because I honestly don’t have any major issues with the website.
Now the basic feature set of any package management system could be broken down as such:
- Storage of Packages (Network or Local)
- Installation/Pulling of packages from the storage
- Versioning of packages
- Pushing new packages
- Searching for packages
Thats about its if we break down these features into technical terms and think about the storage as a file server on the network, then you basically have to be able to do the following:
- Download Files
- Copy files to bin/deploy folder of project
- Alter csproj to reference dll
- Store files on file server by version number
- File upload rest api
- Search rest api
This is actually pretty easy when you break it down like this in fact I think most could probably code this up in a week or so. NuGet adds a couple of additional features on top of these that are also pretty useful:
- Zip/Compression of packages
- Extraction of compressed packages
- Content files that are not referenced
- More package metadata to be searched
- Dependency chaining
The key items here are compression which allows you to move packages with multiple files around much easily and Dependency chaining which allows you to reference other packages. There are a couple of smaller items like config files, multiple sources, api keys, etc but those are not critical to how NuGet works. This is also some version dependency confliction going on as well which is pretty complex but for now lets focus on the above items.
You would think that will this list of features that NuGet could implement a base feature set deliver the tool and then refine it until it was perfect. In fact thats what they did from version 1.0 - 2.X. It was not until we got into NuGet’s v3 API and 3.X versions that NuGet started to break some fundamental software rules.
I believe strongly in the KISS software principle, KISS stands for Keep it simple stupid. The idea is to basically write your software in a simple and easy to understand way such that it can be expanded upon and quickly understood by others. Looking at the features above there are probably many ways that NuGet could be written following KISS. Yet it appears that the NuGet team have forsaken that and gone for the most complicated methodology possible. A quick look through the NuGet.Client repository is enough to understand that they have way overengineered the problem they are trying to solve. This is something that probably happened over time with multiple requests and edge cases coming NuGet felt the need to be something for everyone. As such it slowly overtime added more and more until it just became to large. When they noticed that happening they should of taken a step back followed another design princple called SOLID.
SOLID stands for 5 different principles listed here:
- Single responsibility princple
- Open/Closed principle
- Liskov substitution principle
- Interface segregation principle
- Dependency inversion principle
Each of them mean different things but the basic idea behind them is to create maintainable software by not coupling your software. Each principle are either ways to identify when coupling should and should not happen as well as ways to mitigate and reduce coupling. Coupling is of course when separate software components work together so tightly that changing anything in one of them will cause the others to have to change.
The way that NuGet is currently broken down in its repository is no-sensical and the Team’s apathy to documenting anything past the old NuGet.Core package from version 2.0 and previous is disheartening. I have always believed in having a strong foundation for software, to designing and documenting that foundation in order to build on it in the future. Instead of taking a layered approach and building a strong Single responsibility base and building upon that is separate/segregated sections for the more outlier type features, NuGet has opted for a more flat approach where everything feature is just mushed together in one layer. Nothing is documented and so in order to do something simple you have to go through a million steps just to search or download a package.
This lack of documentation has lead to more than a number of confusing design decisions. With the most recently dot net cli tool changes project.json -> csproj I actually ran into some of these. For instance project.json and csproj no longer use the configuration variable respositoryPath. This was a variable that was used to change the default package installation path which used to be $(SolutionDir)\packages. When you install packages for net core the end up in a global package location. Which some may not like and the only solution is to change a different variable named globalPackagesFolder. Why I ask is this different what design decision thought this was a good idea to just change what people had been using for years and to provide no backwards support. Lets just abandon the repositoryPath variable but not quite because if you use the old packages.config format suddenly it starts working again. So now the code base has to have flags to track which is being used, and to do the appropiate thing. If your gonna make a change then make a clean cut supporting both at the same time doesn’t make any sense.
Then there are the numerous issues with NuGet like the failure to install and uninstall packages. If you go to the issues page on NuGet/Home you will see over 1500 issues all with various problems and most of them based around things that should be simple features. If the NuGet team had started with a simple and well documented base then they could of had people test their issues in phases starting with the base and then working up until they found and isolated a feature that was causing the problem. Their design though makes everything very coupled and hard to determine where the error is occuring.
No one is gonna abandon NuGet any time soon for the reasons I stated at the beginning of this post but given time I guarantee that alternatives using the NuGet api will emerge that will dethrone it. Just take a look at things like Paket which appears to be doing some very interesting things. It might be something to look at though I am unsure about the separate file. It was ok when that was the only option ala “packages.config”, but I do really like the new csproj format. We will see how things go from here but with all the good will and control that NuGet has you would think they would be able to get their act together and deliver a great solution not just a so so one.