But before I tell you what you really need to know let's look at a really bad example. A few months ago I was consuming a NuGet package that was a client to a service I needed to use. When you installed the package you got four things: Two assemblies, one configuration file and another NuGet package that was a dependency. That might not sound to bad, but it was.
First of all the second Nuget package that was a dependency was an emulator for the service. The motivation was that you needed the emulator to test your code. That was in my opinion a partially false statement. In my unit tests I fakes the dependency by faking the interfaces it provided. In integration testing I actually used the real service. I could have used the emulator for integration testing but it made more sense to use the real thing for me in this case. Also, it made no sense to add the emulator to my production code where I needed the client NuGet package.
Then we have the two assemblies. One was a shared assembly between the client and the service and the other was the client library itself. Turned out that the code in the client assembly was needed in one place, but the shared assembly contained a few constants I needed in a few more places. Naturally I could have created my own copies of the constants rather than installing the NuGet package in multiple places (I'll have a separate article on that), but especially for some unit tests I really wanted to reuse the shared assembly only.
And speaking about my unit test assemblies. The configuration file added by the NuGet package was added to all my unit test assemblies even though I didn't need them at all. I did need the client assembly so that i could fake the interfaces, but the configuration file was not needed.
All this meant that I had a bunch of stuff in a a lot of assemblies that was not really needed. Either I just had it there and ignored it or I had to remove it each time I updated the package. Neither option was very appealing to me.
So how should the NuGet author have done in this case? Well the recommendation is clear; in most cases there should be one NuGet package for each assembly. And this is how I would have structured the NuGet packages to accommodate everybody's needs assuming the service name was Foo and from the company Acme.
- Acme.Foo.Core - This is the shared assembly package. It only contains the shared assembly.
- Acme.Foo.Client - This package contains the client assembly only and is dependent on Acme.Foo.Core.
- Acme.Foo.Client.Config - This package contains the client configuration and is dependent on Acme.Foo.Client.
- Acme.Foo.Emulator - This package contains the emulator for the Foo service and a client config to talk to the emulator. This package depends on the Acme.Foo.Core.
With this approach you can see that depending on your needs to can bring in what you need rather than having one NuGet package containing everything. So if you are authoring NuGet packages; make no assumption on how people will use your packages but instead let people decide that themselves. But you can make it easy for them with some smart package dependency setup.