No matter what your software delivery pipeline looks like, if you are using a compiled language, your software delivery process probably contains these common steps:
- Getting the code from source control
- Compiling it (assuming you are using a compiled language)
- Configuring the software and deploying it to the machines in a specific environment
For any non-trivial application, you're going to be deploying the software to multiple environments. This means you need to choose: do you build your binaries once, or do you build them before each deployment?
The first strategy is to build prior to each deployment. The process looks like the diagram below, where the code is fetched, compiled and (hopefully!) tested before each deployment. To ensure that the same features/fixes make it in to each deployment, you'll probably build off a specific revision or tag each time.
Alternatively, you might decide to follow an approach more like the diagram below, where the build happens once, and the same set of binaries (the deployable artifacts) are reused when deploying to each environment.
While there can be an efficiency saving in building binaries once, the main reason for doing so, in my opinion, comes down to risk reduction. If you compile before each deployment, you run the risk of a new service pack or library update sneaking in, leading to small differences between what is eventually deployed to each environment (drift). The more consistency that you can keep between pre-production and production deployments, the more likely the production deployment is to go smoothly.
It's important to recognise that a build process isn't just a deterministic function of "code in", "binaries out". The binaries produced don't just depend on the code going in, but also the libraries, compiler, operating system updates, and a host of other environmental aspects that can change over time.
A real world example of the kinds of changes that might cause problems were some of the changes between the .NET framework 4.0 and 4.5. If you deployed to Test after compiling against .NET 4.0 on a machine without 4.5 installed, and then installed .NET 4.5 on the build server (because you plan to use it for an upcoming release) and then attempt to build before promoting to production, unless you are very specific about the version you're compiling against, there will be slight differences between the output that could lead to code running perfectly in Test and failing in Production.
Building binaries once can be somewhat more complicated, because it introduces the need to store the artifacts somewhere between deployments. However, this isn't necessarily a bad thing; at any point in time it makes it easy to locate old versions of an application without having to build them. This is very handy if you need to roll back, especially if you've made changes to your build server in the mean time.
The purpose of deployment automation is to increase our ability to put working software into production more reliably and frequently. Building binaries once is a simple practice that can help in achieving this.