nik codes

Archive for the month “October, 2013”

Packaging Source Code With NuGet

Pluralsight If you like my blog, you’ll love my Pluralsight courses:
Tracking Real World Web Performance
WebPageTest Deep Dive

.NET developers depend on binaries a lot. Assemblies and executables are our typical unit of deployment and consumption and NuGet itself is basically a sophisticated binary distribution system.

I don’t think there is anything necessarily wrong with that. Assemblies offer a lot of power and have plenty of benefits, but a few times over the last year or so I’ve wondered if our assembly usage follows the law of the instrument.

hammerI suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail. – Abraham Maslow

Plenty of other development communities very happily exist in a world without assemblies or binaries. The Ruby gems and npm repositories are absolutely filled to the brim with packages that contain no binary files whatsoever. What do they contain? Source code.

Recently I’ve been wanting to create a NuGet package that would contain common AutoFixture configuration for intrinsic ASP.NET types that I find myself repeatedly using. Unfortunately, every other user of the package would want to slightly tweak the configuration for their project, so I figured I’d simply ship the package with only the source code (no pre-compiled assembly) so that they could easily do that.

When I told Louis DeJardin about this idea earlier in the year at MonkeySpace, his eyes lit up and he got excited. It turns out he’s been thinking about source only packages quite a bit and has even released several OWIN packages as source only.

Louis told me about a few best practices and conventions that he has found useful when creating source only packages. I’ve noticed that only Damian Hickey has picked up on these, so with Louis’ permission, I’ve decided to publish them here for greater exposure:

NuGet Source-Only Package Conventions and Practices

  1. Package ID’s should end in .Sources, which aligns well with and builds upon the .Sample suffix recommended in the NuGet Package Conventions documentation.
  2. In the .nupkg itself, source code files should be placed in a directory with the path content/App_Packages/{package-id}.{package-version}. Similar to how the .Sources suffix builds upon the prior art of .Samples, the App_Packages directory follows the App_Start folder nomenclature used by David Ebbo’s popular WebActivator package.

    Here’s an example of a package following this convention, as seen in NuGet Package Explorer:
    path
    This convention also allows for a very convenient upgrade path which I’ll cover later on.

  3. Source-Only packages can depend on any other package, including other Source-Only packages.
  4. Source-Only packages may leverage NuGet’s Source Code Transformations (*.pp files) to inject project properties into the source. This is most often seen with the use of the $rootNamespace$ property, but any project property can be used.
  5. In some situations, it may be useful to also ship a standard “binary” package in addition to the Source-Only package.
  6. Types in Source-Only packages should be marked as internal by default in order to not pollute the target code’s public API.
  7. Consider using conditional compilation symbols or partial classes in Source-Only packages to provide flexibility and the ability to customize the source to users.

    Examples of this technique include allowing for multiple platform targeting options and changing the accessibility of types to public when desired. SimpleJson has a few good examples of this in their source code.

When to Create Source-Only Packages

There are plenty of situations where a Source-Only package does not make sense. Here’s a few things to consider:

  • DO consider creating a Source-Only package for “utility” libraries that feature heavy usage of static and/or extension methods. Examples of these types of utility libraries include unit test assertion libraries (see note below!) and the popular DataAnnotationsExtensions package.
  • DO consider creating a Source-Only package for small single purpose libraries. SimpleJson is already doing this (though not following these conventions) but you can image any code appropriate for a blog post or Gist would fit the definition well. (Aside: a Gist to Source-Only NuGet Package service would be pretty useful!)
  • DO consider creating a Source-Only package for common configuration and setup code or any code which will require tweaking by the user.
  • DO NOT consider creating a Source-Only package as a means to simply make step-debugging easier. Instead leverage a symbols package.

Source-Only Package Update Process

One of the nice things about assemblies is that the process of versioning them is well understood. How do we version and update source-only NuGet packages? Luckily, NuGet’s native handling of content works in our favor. Let’s explore with an example:

I’ve created a source-only package called Reverse.Sources that contains an extension method for reversing a string. Let’s install it:

Install-Package Reverse.Sources -Version 1.0.0

install01

Great, now our project contains that StringExtensions.cs file with an implementation to reverse strings. It compiles right along with our application and is relatively out of our way.

Unfortunately, version 1.0.0 of my package had a bug and blows up if a null string is passed into the Reverse method. I’ve added a simple guard clause to fix the problem and released it in version 1.1.0. Let’s update:

Update-Package Reverse.Sources

install02

Notice Solution Explorer looks nearly identical – Reverse.Sources.1.0.0 was simply replaced, along with all of it’s files, by Reverse.Sources.1.1.0. I’ve updated my project without any troubles and I have that nice bug fix now.

But what if we had made changes to StringExtensions.cs? NuGet would have simply left behind the files you’ve edited.

install03

We’d know that there was a problem too because the compiler would complain with a “The namespace ‘Sources_Example’ already contains a definition for ‘StringExtensions’” error.

To fix that error we can use a text diff/merge tool to move the changes over and delete the old 1.0.0 folder.

To me this is a pretty clean upgrade process. Sure we could sometimes get into a situation where we have to deal with merging, but we also get the benefits of working directly with the code.

Are Source-Only Packages A Bad Idea?

Perhaps yes, perhaps no. I don’t think they are that crazy of an idea though. Large numbers of developers outside the .NET ecosystem already work almost exclusively with source only packages. Further, I’d propose that you do as well if you’ve ever included jQuery, Modernizr or any other JavaScript NuGet package in your project.

I for one probably wouldn’t want all packages to be source-only (we certainly won’t be shipping Glimpse like this!), but there are situations where I think it could be extremely useful – particularly in scenarios involving extensibility/tweaking and reducing dependency overhead when I might have reached for ILMerge otherwise.

I’m hoping that this post can start a bit of a conversation about the idea of source only packages and increase the community’s comfort with them. I’m interested to hear the thoughts of the NuGet team and will be submitting these conventions to the NuGet documentation shortly.


Note: It looks like this is on Brad Wilson’s mind too!


Updated Oct 25th with feedback from Phil Haack, Louis DeJardin, Prabir Shrestha and Andrew Nurse. Thanks for the feedback guys!

Advertisements

Enjoy the Perks of Open Source Development

I’ve been working on Glimpse for a little over two and a half years now. Helping the community and collaborating with brilliant developers worldwide is really rewarding. It’s certainly the biggest benefit of working on open source software.

There are plenty of other smaller perks though. One of my favorites is the availability of all types of free world class tooling and services that assist in the efforts of any given project. I use several of them, for instance:

When I think about all the sponsorships I’ve received, I start to feel a bit like this guy who is completely hooked up by companies who are willing to help him do what he does best:

driver

I’m very thankful for all of the support I’ve received. Neither my projects nor I would be in the position we are in without the help. But here’s the secret: I’m not special. Licenses and freebees are available to most open source projects, you just have to know where to ask for them. Unfortunately, figuring that out can be intimidating, which is why I decided to launch ossPerks.com.

logo

OSS Perks is a crowd sourced listing of all the products and services that are made freely available to open source projects. It started in public beta a few months ago with just a listing of the perks that I knew about. Since then the list has more than tripled via contributions from several different people and a Twitter account has been created so that developers can follow along as perks are added to the list.

The site is open source in and of itself, so you can easily add a new perk that you’ve found. I’m leveraging GitHub Pages and Jekyll to maintain the list so it’s very easy to contribute to directly from your browser by just editing our YAML file. (YAML is a plain text data format popular in the Ruby community, think of it as the offspring between INI file syntax and JSON.)

If you’d like to contribute but this all sounds a bit foreign to you, I’ve got a quick little tutorial right on the repositories readme file that should be able to get you up and running.

So go take a look at the available perks and take full advantage of the support offered to you for your open source projects. Trust me, it will make you feel like a world class athlete (or race car driver Winking smile)!

PS – Fellow Microsoft MVP Xavier Decoster has forked the code for OSSPerks and created MVPPerks, a similar listing of the perks available to MVPs!

Post Navigation