One of the things that comes up often in build management is the management of external libraries or dependencies. There are a lot of ways to deal with this, and they are usually language dependent (Java rocks in this regard via Maven, whilst there doesn’t appear to be anything equivalent in the Microsoft world).

As I work predominantly with Microsoft technology, there are usually a few problems specific to external library management that are typical to a standard development team:

  1. Developer workstation setup. How long does it take a new developer, or a developer with a new workstation, to get up and running and build the project? This is usually a good measure of how refined your build and external management process is.
  2. Buildable from source control. Again, a measure of refinement. This is particularly ‘do-able’ in the C# world, where the compiler is sitting on almost every workstation (although with the number and variety of .Net service packs and revisions, this is not always the case!).
  3. Global access to externals. This is not something that every team will deal with, as it is particular to geographically dispersed development teams, but it does crop up often.
  4. Identical build environment for all. Build server and developers have to have the exact same build and external dependencies. A mismatch in the way developers and the “official” build are produced are a pox on the face of software.

There are a few steps that I would generally look to take in a team using .Net technologies to address many of these issues, and at the moment (but not for ever, if I can get some spare time!) the methods used are usually bespoke.

  1. Centralised externals, replicated if necessary for global access. This can be anything from an SMB file share, a database with scripted access, RSYNC (one of my favourites) or any other centralised tool that provides storage and retrieval of binary artifacts. One of the simplest ways you can do this is to provide a single file share, with a tree structure based on Product\Version.  This storage mechanism should capture any externals required for your build, even if you can install it in the GAC (unless there is a specific licensing reason that prevents this).
  2. Standard dependency access script. Once you have centralised your dependencies, how do you get them to your developers? Generally developers will have a few random directories that they use to store assemblies they reference, or they install the assemblies in the GAC and reference from there. A script to standardise the download, installation and location of these assemblies and binary externals simplifies the processes, and changes it from being a manual task the developer undertakes to an automated process that can be centrally managed. This also ensures that any reference to a binary external will work on any workstation running the same script.The one trick with this type of script is how to embed it into the developers workflow. Is it something that the developer needs to run manually? Is it an MSBuild script embedded in the solution file itself that runs automatically? There are a lot of ways this can be solved, and it does come down to the culture of the team to a certain extent.  One thing to look at though is to ensure that the file that drives the dependencies sits inside source control with the project itself.  This way you get a history of when (and what) changed in the dependencies.
  3. Standardised developer workstation (here starts the religious war).  Ideally a standard workstation build provides the developers with a common toolset, best of breed integration, faster startup for new developers (or when a workstation dies) and developer mobility.  A lot of developers REALLY don’t like the idea of having their work environment dictated to them, so getting a standard desktop environment up and running requires a lot of consensus building.
  4. Standardised build script.  This is probably one of the most important things that you can get working.  The goal here is to make the continuous integration build as close to the release build as close to the developer build as possible.  If they can all run off the same script, good.  With most scripting approaches to this you can have the script detect whether it is being run under continuous integration or not, and act appropriately if there are any non-developer specific build actions required (like outputting the files to a release area, tagging, signing etc), although it is usually best if these actions are carried out by the continuous integration server itself.  This will keep the build script as common as possible.  You really dont want to be in a situation where your integration builds are subtly (and buggily!) different from your developers builds.

With all these tools, there are some standard approaches and scripting that can help.  When I get a chance I will post on a few of the ways you can implement these simply within a C# environment.