In the last couple years I’ve built a few libraries for public and internal consumption. Mostly these have been internal things, but they are not much different from OSS libraries.
So far the most popular libarary I’ve released open-sourced is Cake.SqlServer but I’m mostly proud of NSaga though it is not as used, mostly due to lack of marketing effort on my part. Both of these are still on v1.x though these are young libraries – both under 1 year of age at the moment of writing.
In a sense libraries for internal consumption are easier to build – you can break things and then fix the broken things in the downstream projects (or tell people how to fix). If your library is publicly released you need to be much more careful in how you handle breaking changes and how you define your public API surface. Semantic versioning is supposed to help you manage the breaking changes, but you still need to minimise the possibilities of breaking things for other people. If you are not careful and break a lot of stuff, people will be pissed off and eventually move away from your library.
While building OSS libraries I had to excersise a lot of care to cater for wider audience and rules I draw below are mostly coming from OSS. So here they are:
.Net Framework Versions
You need to consider what framework version you build for. Nature of .Net framework – every version is an increment on the previous, so library built for v4.5 will work in v4.6.1. But not the other way. So you need to pick the lowest version of .Net you’d like to work with and stick with it. I think it is fare to say that no currently developed project should be below v4.5. There is no reason to stay on lower version and upgrade from v3.5 is relatively painful. So my rule of thumb is to target v4.5 as a baseline, unless I need framework features that are only available in later versions.
You can build your NuGet targeting different Framework versions. However if you stick with v4.5 there is not much point in providing a separate build for 4.6.
However with the raise of .Net Core you should really consider building your library targeting Core. You can configure NuGet to build for both full-fat .Net Framework and .Net Core and this is relatively easy thing to do.
This has been iterated over and over again. Write your XML documentation for all your public methods/objects. Make your build fail on warnings and make XML generation a part of the build – so if you don’t put an annotation on a method/class your build will fail. This is a great reminder to get your documentation done from the start – otherwise it’ll never happen.
Also documentation is a great deciding factor for public OSS libraries – if they survive and grow or die. If I’m picking a library for a certain functionality, I’ll pick the one with a better documentation. Because documentation is the first thing I see before I start using their code. So be that guy with the better documentation!
Automate Your Build
If you run OSS project – you can use AppVeyor for free – this is a great Continuous Integration server, it integrates well with GitHub and can help with a lot of things – like running your tests or pushing nugets to NuGet.org.
AppVeyor knows how to build .Net projects, but for cases of more complex builds you’ll have to script what you need to happen. I’m a big fan of Cake Build system. All of my recent projects are built with this and I love it.
Internal All the Things
Define your API first – your client’s working surface, classes that client should use – these are
public classes. Everything else must be marked as
private. This is to reduce the possibility of accidently introducing breaking changes. If a class is public, even if it is not meant to be used by your clients – you don’t know how and where it is used and refactoring becomes problematic. But if this class is marked
private – you know that refactoring can be safely done without breaking everyone’s projects. There are a lot of arguments for marking everything as public and let consumers deal with this themselves. And there was a few cases when I wished third party library had a bit more public classes, so I can mold it to my liking. But I much rather prefer people contact me on GitHub and raise issues that they can’t do what they like to do because the classes are marked
private – this will lead to a discussion and project evolution. Also what is
private can always become
public, but not the other way.
And in addition – only public classes and methods need to have XML documentation on them. So you’ll have to write less documentation for your library which is always a win for any developer ;-)
Have Only One Namespace
Resharper loves to suggest different namespaces for classes, depending if your classes are in different folders. Don’t go for for it. Have only one namespace. Because later, when you decide it is time to move this file from this folder to another folder and update the namespace – this will be a breaking change (unless we are talking about
internal classes). It is much easier to do only one namespace – will save you headaches later down the line.
Exception to that are different NuGet packages. As a rule of thumb I use a single namespace within a NuGet package. My NSaga project has a few supporting projects. Main namespace is
NSaga but if you are using SimpleInjector, you will need
NSaga.SimpleInjector namespace – these are deployed via 2 NuGet packages.
These things seem basic and obvious, yet I had to research them, try different things, experiment and get burnt. So I wish I was given this advice couple years back when I was scratching my head on a design of my first internal library.