Building a Better NuGet

NuGet is the standard package manager for the Microsoft development platform including .NET. It has transformed the ease of getting and installing the latest version of .NET packages, tools and frameworks. It relies on NuGet package authors to get packages right but there is little documentation for them to go by, and there are a few inevitable problems. Ed Charbeneau offers advice from experience

Introduction

NuGet, the package manager for the Microsoft development platform, is an excellent resource. NuGet is open to any developer who would like to share code, tools and frameworks with the community. With this open attitude also comes the responsibility to authors to share quality packages that ensure NuGet stays a functional and convenient resource. The authors are trusted to maintain standards.

As with any “store”, the consumers will leave forever if the quality of goods and services decreases. Since there is little to no regulation as to what is published to NuGet we must hold ourselves, as NuGet package authors, to high standards and provide a quality product that is easily accessed, understandable, and solves a problem.

NuGet users are faced with some difficulties today that can easily be overcome by authors if they focus on the overall quality of their packages. Let’s look at some of these problems so we can better understand and address them.

Research and Collaboration

NuGet contains many “duplicate” packages. When searching NuGet, it’s not uncommon to find many variations of the same package, including both official and un-official versions; and to suffer poorly named, or poorly implemented packages.

Instead of adding to the confusion, you must, as a NuGet package author, do your homework before starting a new package. It only takes a few minutes to search on NuGet and elsewhere online to see if there is already a NuGet package that supports your favorite framework or tooling. If you’re sharing your favorite open source project with the community through NuGet, make sure the project’s owners don’t intend to release the NuGet package themselves.

If you find that a package already is already on NuGet and it’s incomplete, or you would like to help in some way, try contacting the author before you begin your own version of the package. The NuGet website has a simple “Contact Owners” link that will put you in touch with the package author. By contacting the author you may find they need help, or they may not intend to update the project and are willing to give you control.

Whenever possible you must try to collaborate, working together on the package: This is a much more productive use of your time than adding loosely-related packages that confuse the end user when they search. If you’re in a position that you have no choice but to make a competitive package, make sure you provide as much information to the user as possible so they can make a clear distinction of what your package provides.

Global scope pollution

When constructing a NuGet package, it is important to understand how your files are deployed to a project. For most packages, the resource you are providing will add files to the user’s project. Ideally these files should be organized in a way that makes them easily: identifiable, upgradeable, and removable.

For example, an MVC project has conventions to place code with similar functionality into folders. The content, scripts, and views folders are common locations to add code to an MVC project, and can become polluted quickly when adding packages to your project. To help alleviate this issue, consider using subfolders to identify collections of scripts, CSS and other code that apply to your project. If subfolders are not a practical option, consider adding a prefix to your file names. eg: myproject.search.js, myproject.crud.js

If you add files directly to common folders, you may introduce duplicate file names. If the user needs to make a decision to keep or discard files when installing your package, they may break other packages or the package may install incorrectly. In addition, the extra organization will help users when they need to work directly with the files from your project. If a user needs to troubleshoot an issue coming from your code, they can easily identify the components if they are carefully and logically stored.

Delivering Documentation

Some documentation should be included with your package, even if it’s just the basics such as the version number, basic instructions and links to relevant online resources. Much like the code that your package installs, you should also deliver your documentation in a way that is organized and doesn’t interfere with other packages or products. By following a discoverable naming convention you can easily avoid conflict, and make things easy for the end user.

You can tell users where the document for your package will can be found by using a convention such as a folder named App_Readme/packagename/readme.md. Multiple packages can deposit their documentation to this folder, thereby keeping all package documentation in one place. In addition, other authors and users can take advantage of this folder and its conventions for their own use.

Go modular

Sometimes the package that you create can have multiple levels of functionality or optional plugins / components. By splitting up your package into modules, you give users the option to use only what is important to their project rather than delivering it as a whole.

You can easily promote modularity and discoverability by using dot notation in your package name. When naming your packages, start with the common or core files required for your package to work properly.

  • MyPackage.Core

Using this core package as a starting point, add modular packages by naming them according to their functionality and declare a dependency on the Core package.

  • MyPackge.Widget

MyPackage.Widget.nuspec

By adding the Core package as a dependency, the user will download both packages when installing the package named MyPackage.Widget.

This style of packaging can be extend to include sets of functionality or even full package installs simply by creating a package with many dependencies.

MyPackage.All depends on thereby installing MyPackage.Core, MyPackage.WidgetA, MyPackage.WidgetB

MyPackage.All.nuspec

Testing, Deployment and Versioning

When you’re ready to deploy your NuGet package, make sure your package is thoroughly tested. NuGet does not allow modifications to your package to fix errors or even typos in documentation. You will need to increment your packages version number and upload the new version to fix any problems that occur.

To test your package’s installation process create a local NuGet source. Copy your NuGet packages to a folder and add this folder as a NuGet package source in Visual Studio.

2065-local-packages-82fc9a26-d255-48c5-b

Now you can install your package locally before uploading to NuGet.

Handling version numbers

It can cause problems if you use the version number of the code deployed by your package as the packages version. Since you are required to create a new version number each time you upload a package to NuGet, your version numbers could get out of sync between the package and the code. To avoid this problem, create a version scheme that allows you to make package changes in addition to code changes.

<package major>.<package minor>.<code major>.<code minor>

This example allows flexibility because we can change the functionality of the package itself independently of the code that the package deploys. If we would like to make a change to the installation process or update the documentation, we can increment the package version without causing our code version to be out of sync. To help users understand what version they are installing, make sure to document the version numbering scheme and include a change log in the package’s documentation.

Conclusion

By increasing the quality of the packages that you author, you increase the value of NuGet. There are no strict guidelines on how packages are created or on their content, so is important for the growth of the community of users to create packages of high value. High value packages will help the platform by giving users easy choices, clear options and positive experience.