How to setup projects for builds

In a typical .Net development environment, you will have many projects. These may be class libraries, console apps, windows apps, web programes, etc... A natural question arises, which is how does one organize all these projects?

The most obvious answer, is that you add all the projects to one giant solution. Why? This has several advantages:

  1. It is a place where you can literally define what your entire solution is.
  2. It allows you to easily setup dependencies and references.
  3. It allows you to simply build the entire solution (for an automated build).
  4. It allows you to easily setup a deployment project for the entire solution.

This obvious answer has one obvious drawback - performance. If you have a single solution with many projects, that solution may become unwieldy. Forcing developers to open up that single project may take a very long time, and eat a lot of memory. Developers will also have to checkout all of the source for the entire solution, even if they are only working on a small portion of the source. Plus, the overhead associated with seeing every project in the solution can be very confusing. Because of this, the single solution is not the correct way to manage things when the number of projects gets large.

Instead of a single solution, there should be many different solutions, that are broken down in some logical way (perhaps a solution for all libraries, or libraries of a certain nature for example), and there should only be a few projects in these solutions. Thus, developers will only have to open up solutions with a small number of projects in them, thereby avoiding the problems above. NOTE: It is always far more desirable to use project references. Therefore, these finer grain sub solutions must include the transitive closure of (non-GAC) projects they reference.

However, for automated builds, you will still want an all-encompassing solution as mentioned above. That solution will encapsulate all of the build dependency infomation for the automated build, and make the automated build script very simple. In fact, suppose that the uber-solution is called omega.sln, then your autobuild script (for debug) can be as simple as: devenv /build Debug /out build_errors.log "Omega.sln"

This structure is the preferred way of managing solutions with many projects. However, you can try a system where every project has its own solution. This disadvatage of this is that you cannot have dependencies or references across soutions - therefore you must manage these dependencies and references manually, which can be tedious.

The following table summarizes these different structures

Technique Advantages Disadvantages
Single Master Solution
  1. Simple.
  2. Allows ease of building, dependencies and references, setup, autobuild.
  3. Defines the entire solution.
  1. May have performance and overhead problems if many projects included.
  2. Developers need all of the source to build things.
Single Solution for every project
  1. No need to keep a master solution updated when changes happen
  1. Have to manage dependecies and references manually when building, which can be tedious for both developers and the autobuild.
Master solution and other finer grain solutions
  1. Has all the avantages of the Single Master Solution for autobuilds.
  2. Finer grain solutions allow developers much more control over what source they need.
  3. Performance issues associated with opening smaller solutions is negligable.
  4. If finder solutions are logical, project dependencies can be used.
  1. May have to change more solutions when things change.
  2. Need to make finer solutions logical to enable project dependencies.