Project anti-pattern: Many projects in a Visual Studio Solution File
I’ve been hearing from several colleagues about how their Visual Studio solution files have many (i.e. more than 10, and usually more than 30 — in one case, more than 100!). So far, none of them have been able to give me any good explanation for why this is and most of them hate it but they can’t change it because their architect/lead/whatever won’t let them.
I’m hoping that by getting the discussion going on this in the greater community, we can try to discourage everyone from having lots of projects in a solution.
Why are lots of projects in a single solution not good?
Aside from some of the more obvious arguments about performance, runtime optimization, PDB and assembly size, etc, etc, etc — actually, wait. These are obvious, right? Anyone who’s ever loaded a VS solution file with more than 20 projects should know exactly what I’m talking about. And if you’ve made the mistake of kicking off a build in Visual Studio with this solution, you know that you’re in for a 1-5 minute sit-on-your-hands party. And also — and I could be wrong about this, but it was true as of .NET 2.0 — the JIT cannot optimize code across assembly boundaries (or at least it can’t do ALL its optimizations). Then there’s the inherent overhead of each DLL file and assembly metadata being loaded for each assembly, not to mention the extra overhead of having so many PDB/symbols loaded in Debug mode, etc, etc, etc. If you need more proof of the performance problems caused by lots of assemblies, let me know and we’ll go deep. I’m hoping that these facts are well established in the wide, wide world of .NET.
Ok, so hopefully we’re past the obvious arguments, let’s get back to some of the more subtle ones. Why do you need so many assemblies? Is it namespace control? Why not put them in one big assembly and use namespaces there? Is it Strong Naming? Ok, I’ll give you that one, strong naming does throw a wrench in things sometimes, but I’d still challenge whether you need 30+ assemblies in your solution just due to strong naming. Is it licensing? Security? All of these problems have a better solution that usually doesn’t require more assemblies.
One common argument I’ve heard is ‘dependency’ management. That is, I don’t want my XYZ.Foo assembly to reference System.Web or something like that. My counter to this is: Why not? What does it matter? It’s usually an aesthetic argument that comes back and has little to do in the way of any real merit from a business value perspective. In fact, I can usually counter back with arguments that more business value is gained by having things easier to use and package and not worrying about dependencies for dependency’s sake. System.Web is in the GAC just as much as System or mscorlib are. You’re not saving yourself any problems by having an assembly that has references to all of those.
Another argument is that I don’t want my different ‘layers’ all in the same assembly. Why not, I ask? Sometimes there’s a valid argument here because you need to deploy these things separately to separate physical layers. Ok, I’ll grant you that one, but remember, we’re talking 3-4 assemblies here, TOPS. If you’re over 20, something is probably seriously wrong. It’s a smell, not a sure sign of fire, so your mileage may vary here, but 20 is definitely a line that I would try very hard not to cross. In fact, 10 is probably pushing it.
What are some exceptions when consolidating assemblies?
Utility/console application projects. Unit test projects. Integration/longer-running test projects might do well to be in their separate project. Interface assemblies for remoting/serialization/integration purposes. Plug-in/frequently changing assemblies, resource assemblies, etc.
In the case of utility/console application assemblies and things like resource or satellite assemblies, you might consider a separate solution for these since they are likely not built or used as often as the main-line code. You can have multiple SLN files reference a single project, so you can mix and max your SLN files. Be careful though, as the management of these things can get out of hand, so make sure you always have a core SLN file that you trust as the definitive source for what ‘works’ in your project.
Also, consider an automated build and test process (NAnt, Rake, Bake, etc) that can independently build and verify the fitness of the build after tests and such so that you remain honest.