Update (2011-03-21)

Changed table layout.

An interesting question I rarely see discussed is: how many build should I plan for in my project and how do they relate each other.

This latter point is of paramount importance as it drives us to two other questions:

  • why should I need such build? or, in other words, which are the motivations and objectives for a having particular build?
  • how do we distinguish the outputs?

Let’s sketch some answers.

I assume knowledge of merge and branching; if you need to be up at speed take a look at Visual Studio TFS Branching Guide 2010.

Build Objectives

A primitive kind of build is compiling the project’s deliverables for some user to consume. Different users may require different flavors of the same outputs. A case is signing: for development or test, you use fake keys or certificates, while an official build will use the official encryption keys. Another case is multiple teams: the output of a team is consumed by the team itself, or is on “official” version release to the other teams. Some projects require different builds for binaries and documentation, as the latter has different timing.

This is an important point: as your whole product/project is partitioned in various team (see How Microsoft/DevDiv uses TFS - Chapter 2 (Feature Crews)), you have a natural source of different builds, a group of builds for each team.

As a projects grows bigger, you’ll need to split some of your builds in pieces, to reduce the time they requires.

A very special build is a build created for testing the build itself (see my Testing the Build post).

A very common pattern is to have a continuous integration (CI) and a daily build. Typically the first is aimed at a quick verification of a check-in, while the second is a thorough exercise of automation. For example, the CI simply compiles and run a portion of unit tests, while the Daily exercises as much as possible the code with integration test and packages the output in MSI. I will not spend more words on this subject as there is plenty of material about.

Another common theme is the have a different flavor of the same build for the developers branches, so they may run that flavor on their branch and be reasonably sure of the outcome after merging on the trunk(so called, reverse integration). In this case we have private builds, for private consumption of a single developer or teams, and public builds, shared among various teams or the end-users.

Build Outputs

As we have different builds and different flavors of the same builds, it’s extremely important to clearly distinguish the outputs. In my opinion the difference has to be something easy to recognize in the binaries and the artifacts.

For .NET you may use attributes like AssemblyConfiguration or AssemblyInformationalVersion; the latter is easily checked from Windows Explorer as “Product version”.

A second element that differentiates the builds is the version assigned to the output: I refer to the four part number major.minor.build.revision (see Version Information). A well know schema, widely used in Microsoft, is to:

  • fix major and minor for the whole product release;
  • build is incremented by official builds;
  • revision may refer to a patch build that spins off an official build.

In this schema there may be:

  • private builds, where build and revision are fixed (0.0);
  • public builds, where build number is increasingly incremented and the revision stays zero;
  • public patches, where the build number stays fixed and the revision number is increasingly incremented.

All artifacts (DLL, EXE, MSI) that carry a version number shows their origin based on the last two numbers.

Update (2010-04-30)

I have found this interesting post Best Practices for .NET Assembly Versioning that gives you a good explanation on the version numbering topic.

A basic schema

After this long introduction, I’ll show the schema apt to a small-medium project.

Build

Description

Version

Retention

Trigger

Tools

Compile (and check-in) tools and libraries used
by other builds or tools for dev/test/deploy

(default)

Some (5) latest

Manual

CI

Continuous Integration, just compile
and run some unit test

(default)

Some (5) latest

Batch

Daily

Official build, good for deploy on test

1.0.*.0

50 good, 10 others

Scheduled at 14:30

Release

Official build for Acceptance / Production

1.0.*.0

All

Manual

Hotfix

Official patch for Acceptance / Production

1.0.*.*

All

Manual

Private* Private builds for developers’ branches 1.0.0.*

Some (5) latest

Manual

Some variations, should be immediately evident: you may have more build for different tools; a private build distinct by branch; release and hotfix builds by branch, when you have multiple outstanding deployments.

In a future post, I’ll show how the version number may be computed during the build so to satisfy this scheme. Also note that in TFS 2010, Daily / Release build are candidate for the new Gated check-in feature.

This arrangement isn’t really complex and works well for a single team; when you account for more complex project structure, like feature teams, more complex schemes are needed, both on naming and versioning… but discussing such topic requires more than a blog post.

Hope this may spawn some comments.