I have noticed a few debates over on StackOverflow and various blogs recently on whether components in a large .NET application should each reside in their own assembly, or whether there should be fewer assemblies and namespaces used instead to separate components (for example, see this article).
Much of the debate revolves around refuting the idea that simply by breaking every component out into its own assembly you have necessarily achieved separation of concerns (e.g. Separate Assemblies != Loose Coupling).
This may be the case, but why not have lots of assemblies? There are two main reasons to favour fewer assemblies:
- Speed - Visual Studio simply does not cope well with large numbers of projects. If you want to maintain a short cycle of code a little, compile, test a little, then you want your compile time to be as quick as possible.
- Simplified Deployment - its easier to deploy applications containing a half a dozen files than those with 100s.
Both are valid concerns (and the speed issue is causing real problems on the project I am working on), but I want to revisit the two main reasons why I think that separate assemblies can still bring benefits to a large project.
Separate assemblies enforce dependency rules. This is the controversial one. Many people have said that NDepend can do this for you, which is true, but not every company has NDepend (or at least not on every developer's PC). It is a shame there is not a simpler light-weight tool available for this task.
While I agree that separate assemblies does not automatically mean loose coupling, I have found it is a great way to help inexperienced developers to put code in the right place (or at least make it very difficult to put it in the wrong place). Yes, in an ideal world, there would be training and code reviews (and NDepend) to protect against the design being compromised. And it seems likely that genius developers such as Jeremy Miller are in a position to control these factors in their workplace. But many of us are not.
And in a large project team, separating concerns such as business logic and GUI into separate assemblies does make a very real and noticeable difference in how often coupling is inadvertently introduced between the layers, and thus how testable the application is.
Separate assemblies enable component reuse. What happens when someone creates a new application that needs to reuse a component from an existing one? Well you simply take a dependency on whatever assembly contains that component. But if that assembly contains other components, you not only bring them along for the ride, but all their dependencies too. Now you might say that you could split the assembly up at this point, but this is not a decision to be taken lightly - no one wants to be the one who breaks someone else's build. After all, there are other applications depending on this assembly - you don't want to be checking out their project files and modifying them just because you needed to take a dependency on something.
I guess I'm saying that the namespace versus assembly decision isn't quite as simple as some bloggers are making out, and the side you fall in this debate probably reveals a lot about the size and ability of the team you are working on, the working practices and tools you have at your disposal, and what sort of application you are creating (in particular, is it a single application or a whole suite of inter-related applications, and is there one customer, or many customers each with their own customised flavour of your applications).
It seems to me that much of this problem could have been solved if Visual Studio had given us a way of using netmodules. This little-known about feature of .NET allows you to compile code into pieces that can be put together into a single assembly. It would be extremely useful if you could compose a solution of many netmodules, and decide at build time whether you want to make them into one or many assemblies. That way in one application component A could share a DLL with component B, while in another application, component A could be in a DLL all by itself.