Do your builds have other hard dependencies?

The last couple of posts have discussed the need to eliminate the hard dependency of absolute paths from your build scripts and code. But there are other hard dependencies you really want to avoid, if possible, when building and running your code. Here are a few, along with ideas for eliminating them.

Registry, Environment, Config files

I recommended using the registry, environment variables, and configuration files as a way around the problem of absolute paths in your build scripts. Of course, now they’re dependent on these things, instead of the files and directories in the paths. If possible, use some of the other techniques for eliminating absolute paths from your build. If not, you can tackle these in a couple of different ways. You might make the registry settings, environment variables, and config files optional, with smart, commonly used defaults if they are not available. It’s not perfect, but it’s something. Also, it probably makes sense to script the dev machine setup, so that these things can be automatically setup before starting to build and hack on a new machine.

File shares

File shares can be like absolute paths, but even worse. Because they’re not on your machine, as a developer, you may not even have the access necessary to fix the problem on your own. And if the file share goes down or it’s path is changed for any reason, you’re going to start having builds break. You can start to solve this problem by putting the files in question into a version control system and treating it like one more component of source code. If these files are on a file share because they’re very large, it’s worth using a VCS that is centralized, at least until the DVCS’s solve the current drawbacks associated with large files.

Databases

I had not experienced the issue of needing a database to perform a build until coming to Fog Creek. The build process for Kiln generates a database through a series of version changes, then, from the db, generates typed classes used for accessing the database model. I suspect this is not too uncommon. A better approach would be to generate the database from the code model, or use a third “specification” for the database that could generate both the db and the code. But if you do stick with the database, you can at least make sure that each build creates and generates it’s own database, which is cleaned up with your standard build cleaning tools. This will let you still do multiple builds in parallel, and make sure you don’t break something in the process that is hidden by having a currently working database already in place.

Web services or sites

A build process may use web services or web sites to generate reports, store build statistics, or retrieve data used in the build. In one sense, a version control system falls into this category, and is an acceptable hard dependency. Other uses of websites or web services should be as optional as possible, and not part of the core build scripts. Make sure the core build scripts work, then collect any data and generate any reports you wish to. If you need data from an external source, seriously consider setting up a process for retrieving that data and placing it in a VCS repository on a regular schedule, so that you can just rely on your VCS.

Services or other running programs

Services or other running programs on your dev machine are also hard dependencies and should be avoided in much the same was as web services and sites if they are non-standard. In the example above, where the hard dependency of a database is overcome by having the build generate it’s own database, you’d still have the dependency of a database server instance running, probably on the same machine. For this reason, having the build generate the necessary SQL to create the database schema is a better approach than using an actual database during the build process.

Services/other programs not running (virus scanners, etc.)

Additionally, your build scripts may have an implicit “requirement” that certain services not be running, the most common of which is a virus scanner. Builds can modify tons of files, and if your virus scanner is immediately opening each modified file to check for viruses your builds may become unnecessarily slow. If possible, disable these as part of the build script, or find some way to have the scanner avoid your code and built files. Whatever you do, don’t leave a note on some internal wiki page that is impossible to find that tells new developers to disable the virus scanner before building to see a 200% speedup in builds.

Hardware available and connected (other than disk/memory/cpu)

Finally, it’s also possible, depending on the software you’re building, that your build scripts expect custom hardware available and use that hardware as part of the build process. The simplest, and most acceptable use of this is some cool indicator of build status that all of your office can see or hear. But don’t forget to make sure that hardware failure there doesn’t fail the build itself, or worse yet, stop new builds from being made. For other types of hardware dependencies, try to find a way to emulate them.

All of the hard dependencies listed above can make your life miserable, or possibly just more painful than it has to be. Finding ways to break those dependencies will keep your operations running more smoothly, your developers more happy, and your thrilled at how much more work you can get done between releases.