Ditching strong naming for Lucene.NET
Or: Let's make the world a better place
Strong naming, or assembly signing, has been the source for a lot of pain to many developers in the past few years.
Recently more and more developers are starting to raise their voice against strong-naming, and I think we as a community have the power to change things within the CLR by simply re-defining reality. I wish there was a better way to do this, for example Microsoft taking leadership and realizing SN is bad years ago. This is what I'm now pushing hard to do with Lucene.NET, with the hopes that more projects (OSS and closed source) will follow and eventually not-signing will be the default.
For reference, there is a long-going discussion on this on Octokit's issue tracker and several others long living discussions I can't find at the moment.
Obviously, this doesn't come without a cost to an OSS project like ours. We risk at bringing more barriers to entry, and for a popular project it is a problem. So I'm also proposing ways for making this easier to swallow. But, and this is important - while it may require some work in the process, this is going to be a better place for all of us when this is done.
What is strong naming?
Strong naming is basically a way to ensure the referenced assembly is indeed the one you are expecting it to be. You sign the DLL you compiled using your private key, and then distribute it.
Projects which are compiled against your DLL will expect that specific signature to appear in the DLL, and also the specific version which they referenced. This version check is made after the signature check, and only for signed assemblies.
On paper, strong naming is a great way to make sure software can't be broken by using assemblies that are different than the ones intended. By hackers for example.
How is it broken?
Because strong naming performs exact version matching, a minor release such as 3.0.1 released after 3.0.0 will not be considered the same version, and your project will refuse to compile. This means whenever you do a bugfix release, you essentially release a completely different version as far as your users are concerned, and they will have to add a reference all over again for the change to stick.
If you release often, this is eventually going to lead to a problem. If your project is popular, you'll start seeing collisions between projects - one referencing 4.5.0 and the other referencing 4.5.1 but both refuse to work together because the versions are completely different as far as they're concerned.
Most notable is the JSON.NET case - a popular OSS project in the .NET realm which was releasing very often. The project was causing so many conflicts that most projects using it in conjunction with other projects who depend on it just ended up compiling it in. And that's the worst solution of all.
But that's just a practical reason. Apparently the implementation of strong naming is also broken. The protection that SN is supposed to provide doesn't really hold (last link - see "What Strong Names Can’t Do").
This means projects that rely on SN for making sure the DLLs weren't swapped by malicious users are pretty much exposed still. And OSS projects who release their keys to the public are pretty much are pretty much useless for signing themselves.
If all (major) projects were non-signed, or the CLR would have respected SemVer when comparing versions, then we would all be fine. The latter isn't going to happen probably, the only thing that we still have some control over is the first.
The Lucene.NET case
In Lucene.NET we take external dependencies of various projects, and we wish to have dependencies as streamlined as possible. That is, not having a "SharedLibs" folder with binaries, but using NuGet as everybody is using today. But in order to do that, we have to have all dependencies signed. At least as long as we are signed.
One of our dependencies, namely NTS, seemed to have dropped signing accidentally recently. This broke another dependency (spatial4n) which is signed, but still under our control, and then in turned broke our build process just as we were about to release a bugfix for version 3.0.3. This is real pain. Modern day DLL Hell.
This gets even worse. Since users can, and are encouraged to, roll their own Lucene extensions (namely: analyzers, query parsers and so on), this eventually may lead to users trying to write something nice that can't compile because of a dependency being not-signed.
We want to avoid this pain, both for our process and for our users.
What do I suggest for Lucene.NET
Lucene.NET should stop signing its assemblies. The main release channels (main download, nuget) should have a non-signed version. This will make Lucene.NET a non-signed library, that can be used with non-signed dependencies both by us and by users.
This ideally will help us push through a change in the .NET realm, this can't really continue. And no, ILMerge or various SemVer hacks are not really a solution and they do have costs associated with them.
For projects which are signed and can't remove signing any time soon, we will offer signed assemblies which can be used for your projects. They aren't going to be on our main channels, but they will be available enough for you to use. The whole idea is to make them a bit less accessible, with the hopes that the community will stop signing their assemblies as much as possible.
While this can be a major pain for some, this eventually lead to a better place for everyone. If more major projects will join, a change will eventually come.
TL;DR
Assembly signing is broken, both in terms of how it works and in not providing what it is supposed to be providing. In the process it makes our life miserable and the pain isn't going away any time soon.
By releasing .NET as non-signed we hope to achieve a change in the community. To help people who have their project signed we will release signed assemblies as well, but on side channels.
Let's make the world a better place.