The Hillbilly asks: How do you compile your application in your NAnt script for releases?
There are many options, you see, even though the <solution> task is no longer one of them. You could use the <msbuild> task to build the solution as it is built in VS (I think; the documentation is a little sketchy on this task if you don’t know the inner workings of msbuild). Or you could use the <csc> or <vbc> tasks to compile a group of code files into an assembly (similar to a .csproj or .vbproj file). Or, for the ultimate control, you could use the <exec> task to call out to msbuild.exe, csc.exe, or vbc.exe directly though I couldn’t tell you personally what that offers you that the corresponding tasks don’t. Future-proofing maybe.
Usually, for testing purposes at least, this entails using <csc> (or <exec> with csc.exe) to compile all the application code into a single assembly that I can run tests against. It’s a practice I learned from JP Boodhoo and I’ve been happy with the results in the absence of anything better.
But I don’t care much about the unit tests. I’m more interested in your releases. Assuming you’ve automated them in a NAnt script, how do you build the application in preparation for them?
Historically, I’ve usually used the <msbuild>/msbuild.exe scenario mostly because I couldn’t wrap my head around writing a bunch of <csc> tasks to compile the code into the same structure I see in Visual Studio. For example, if your solution has a Domain project, a DataAccess project, and a UI project, I would need three <csc> tasks to create the individual assemblies. Or one <msbuild> task running against the solution. My reasoning was that it was the easiest way to build the application the same way I did in Visual Studio, which I assumed was how I wanted to deploy it.
Then I talked to Donald Belcham.
Conversations with Donald Belcham are always eye-opening (and I won’t expand on that comment this time; happy belated birthday, dude). And during our chat, he admitted to using <csc> to create his releases. I expressed my surprise: "But Iggy, what if your solution has a dozen projects in it? I don’t want to deal with the pain of a dozen <csc> tasks in the right order". To which he replied: "Dude, you don’t need to deploy the same way you build. The Visual Studio solution is a file management mechanism, not a deployment mechanism." And my mind awakened like it did during my last visit to Brian Head.
The basic idea Donald described was thus: Just because you build your application one way in Visual Studio during development, doesn’t mean you need to build your releases the same way. Especially if you are using NAnt to create your releases because then you can do it however you like.
And as if my mind wasn’t expanded enough, he typically shoots for one assembly per physical location. Not one assembly for the domain, one for the data layer, one for the common utilities, and so on and so forth. One. Total. If I were building a WinForms application with no other physical layers, I’d have one file: MyApp.exe. If it were a WinForms app calling a web service, there would be two assemblies. One for the client and one for the web service (plus corresponding .asmx files).
This is the extreme position of course and there are caveats. If the application depends on third-party libraries, naturally we won’t bundle those up into the assembly. And if you’re using an internal client library that is common to more than one project, you’d treat that as you would any other third-party library and keep them separate. But if your application-specific domain code and data access code sits on the same server, that all gets munged into one assembly regardless of how it is organized in the .sln file. NAnt gives us that flexibility.
I’m kind of putting Donald out there for potential ridicule so I’ll expose myself ever so slightly and admit that I really like this idea. Why *do* we feel we have to ship a dozen assemblies for our application? If something changes in our domain, what difference does it make if we re-deploy MyCompany.MyApp.Domain.dll or MyCompand.MyApp.exe? And in speaking with Donald, he points out that even though we have the flexibility to deploy only parts of an application, rarely do we exercise it. In a typical scenario, new versions and hot fixes are deployed as an "all or nothing" in each physical layer anyway. This matches my experience. Even if nothing changed in certain assemblies, I typically re-deploy everything during an upgrade just to be safe.
Now, we still need to be practical about it. If the resulting executable is 300Mb, then ISDN line or not, you’ll want to break that into something more manageable. But for the average application, one assembly should function just as easily as five, yesno?
Looking forward to hearing the counter-arguments because I haven’t quite thought this through too much except from a maintenance point of view. In particular, are there performance differences with loading several smaller assemblies vs. one "larger" (but still manageable) one? What about issues with unloading an assembly from an application pool in IIS?
Enquiring minds want to know!
Kyle the Inquisitive