Kyle posted about an ongoing conversation that he and I have been having for the past couple of weeks about code compilation practices. As expected, there was some disagreement with the practice that I use and, as a result, I wanted to clear up some of the points in the comments and rebuttal posts. I’m going to make a couple of posts here. One that discusses compilation practices and another on project structures. Let’s get on with the compilation practices here.
First let’s talk about why I went this route. Last year I was working at a client that had 56+ projects in the solution….and that number was growing. Part of what I needed to do on that project was to make the development effort more manageable. At the same time as I was starting to fight through the fog, I read a post by Scott Bellware (I’d link to it, but let’s not go there right now) and I attended JP‘s Nothin’ But .Net course in pretty close succession. At first, I scoffed at Scott’s suggestion that we compile assemblies differently than we organized our solution/project structures. How dare he suggest something so radical…so non-conformist…so simple.
My first physical (as much as it could be) introduction to the practice was at JP’s course. JP showed us how you could, with the <csc> task in nAnt, compile your entire application into one assembly using one relatively simple set of code. True, we were only being exposed to a scenario of compilation for testing purposes. I started to screw around with the concept on some project code (at home and at work) and it became apparent that there was one barrier. Compilation to one assembly didn’t deploy very well. Why not deploy one assembly to each physical tier then?
The only reasons I could come up with that argued against one assembly per physical tier were:
- Code reuse Fractional deploy-ability Assembly size
Code reuse is one of those things that we talk about all the time. We talk, code and deploy with the hopes and dreams that our super-special-never-causes-a-problem-when-used string manipulation method will be used by every project from this day forth. The truth is, that rarely will that method see the light of project again. It’s existence falls into the dark abyss known as our current project. Even if we do think of it when we move off to the next project, we’ve most likely deployed that method into an assembly that brings with it a bunch of other stuff we don’t want or need. Instead of dealing with the excess baggage, for good or bad, we tend to fall back onto cut-and-paste code reuse. To me, cross project code reuse is a pipe dream that rarely comes to fruition.
Like code reuse, fractional deploy-ability is something that everyone talks about, praises and designs around when we initially start architecting our projects. Maintaining the pattern I laid out for code reuse, fractional deploy-ability is lost when the project matures. Although we have the capability, thanks to our diligence designing the code architecture, we rarely deploy just one assembly. Instead we default to a deployment of the entire application no matter how small or isolated the changes were. I’m never sure it this happens because we are scared of the potential problems that can come from a partial deployment, or if our build and deployment processes are optimized to work with the full application and thus have less friction. Regardless of why, fractional deploy-ability just doesn’t seem to happen.
Assembly size was the final concern I could think of, and it was a stretch from moment one. Of course, when you compile most of your code into one or two or three assemblies, you’re going to see that those assemblies are physically larger. My one negative thought on this was that larger assemblies take more memory space when loaded. Well….most of the assemblies that I’ve build for projects tend to have a combined physical size of less than 20mb. Once that number ran through my head, I decided that it wasn’t that much memory at that size. I also decided that I should treat this like performance. Until I know that memory usage is an issue, I shouldn’t worry about it. Don’t prematurely optimize goes both for performance and memory usage.
With those thoughts in mind, and if they fit the scenario that you have at hand, why not deploy one assembly per physical layer? Now, this won’t always work. Like everything you need to look at your situation and apply the concept that makes the most sense for you. That said, don’t dismiss it out of hand like I initially did. Remember to always challenge your assumptions.