Patrick Cauldwell said something very wise today at work. Here's the gist:
Sure, there's no more DLL Hell for the end user. It's that they've made it hell for the developer.
It was immediately funny, but a few hours later, it was profoundly true.
He and I are working on a really cool subsystem for our developers that offers a them clean SOA.
As an aside, it also uses NAnt 0.8.4 for its builds. I know I said I was doing command-line builds with DevEnv, but both Patrick and Chris Kinsman insisted I give it another look. I was HUGE into NAnt a year ago, but got lazy and floated away. I'm back with a vengance. The mess of -contribs and bugs is gone and it's fantastic. It includes a whole series of great new Tasks. My favorites are foreach, nunit2 and the invaluable solution task. I'm also using nunit2report which is great, but needs to support multiple input files.
Anyway, so this build of NAnt uses and includes assemblies for log4net and NUnit 2.1.3. I also use log4net and have referenced NUnit 2.1.4 in our project. We automated the entire build: codegen>build>test>report>email results. We have a bootstrapper that gets the project into an empty dir and forks to the build file that just came out of CVS. It's gloriously command-line and marginally Rube Goldbergian. ;)
However, a few weird things happened. First, these NAnt binaries were compiled on the 1.0 framework, but the NAnt.exe.config was set to allow it to run on Framework 1.1. However, the lib directory for NAnt had MULTIPLE directories (clever) with different versions of log4net, NUnit, etc, in each directory (frustrating). I didn't notice this until NAnt tried to run the tests. NAnt loaded a non-strongly-named NUnit 2.1.3, and by the time my tests tried to request my strongly named 2.1.4 I was getting all kinds of binding errors and stuff. Same thing happened when my non-strongly-named build of log4net (compiled on 1.1 as version 1.0.13704 something) tried to load into the process space of NAnt's version of log4net (compiled on 1.0 as version 1.0.13704 ALSO).
Needless to say, this all sounds obvious after the fact, but I needed to sync up my versions. Certainly I could strongly name things and GAC them, but that kind of is orthogonal to the goal of a build-anywhere-relative-paths-xcopy kind of project. So, the easiest and safest thing to do in order to maintain my goal of minimal dependancies was to rebuild NAnt on 1.1 with my preferred minor versions of log4net and NUnit via a shared lib.
So, back to Patrick's point. The CLR offers some amazing improvements over COM-style and LoadLibrary/GetProcAddress DLL Hells. Truly. We have side-by-side assemblies, the GAC, and strong naming. However, it does put increasing logistical pressure on the developer to define appropriate policies and procedures to balance ease of development with ease of deployment.
It takes some serious thought to plan this stuff, and arguably it's not possible to get it right the first time. Or the third. While the underlying support is there in the CLR, certainly the complex issues around dependancy management, both at compile-time and run-time are not going to be solved anytime soon with a nice Visual Studio.NET Add-In. "File|New|Enterprise-Wide Dependancy, Version Control, and Deployment Management Project", anyone?