The Reliable Build
If you look at my WeeWikiPaint codebase, you’ll notice something strange… and a little off-putting. All kinds of crap is checked into the repository: throwaway code experiments, npm modules, and even… IDE settings‽
Given that WeeWikiPaint is the Recorded Live channel’s ongoing example of professional & rigorous software development, what gives? Why the mess?
There’s a reason.
Real-World Software Development
In the Recorded Live series, I’m acting the same way I would if I were on a team developing a real-world software product. In that environment, coordination between team members is important, and it can be surprisingly difficult to maintain. One of the easiest mistakes that can occur is for various development machines to get out of sync. Then you have the dreaded “it worked on my machine” problem.
A variant of this problem is an inability to reproduce old builds. You’re chasing down a bug or something, so you check out an old commit, but it no longer builds, or it fails in a strange way, despite working perfectly in production. Let’s call that the “it no longer works on my machine” problem.
And then there’s the all-too-common case of getting a new development machine and having to spend days to weeks getting everything configured and set up. Also known as the “why doesn’t this #$@%! work on my machine” problem.
These are problems that you never see in a classroom setting, but if you’ve worked in a team environment for more than a few years, you’re sure to have encountered them. They’re painful, annoying, and an utter waste of time. At best! I’ve heard of projects that were irrecoverable because no one could get them to run any more.
The Reliable Reference
Of all the things in your programming environment, there’s only one thing that you can count on to give you the same answer every time: your source repository. When you put something into the repository, you can rely on being able to get exactly that thing back out at some future date. (Nitpicky exceptions aside.)
When else is that true? Your development database changes all the time. Dependencies get updated at the whims of others. Package managers change versions and storage strategies. Your network infrastructure changes and once-vital services are retired. Even your OS changes over time as patches are applied and versions upgraded.
Nothing about your programming environment is the same today as it was 10 years ago… but if you have a code repo that old, you can still get the exact code you had 10 years ago.
But will it run?
Creating a Reliable Build
How do you solve the “it worked on my machine,” “it no longer works on my machine,” and “why doesn’t this #$%! work on my machine” problems?
My way is to take advantage of the reliable repository. I consciously use it for as much coordination as possible. My ideal is to be able to buy a new computer, clone the repo, run one command, and have everything work exactly as it does on every other development machine.
Even more ideally, I’d like that build to work even when the network cable is disconnected. That way I know that all the state I need is stored in the repo, which means we can always reproduce a previous build with 100% fidelity.
I’m not able to achieve that ideal in every case. For example, in WeeWikiPaint’s current setup, you have to install Node.js manually. There’s often big-ticket items such as Node which can’t be checked in. But even when I can’t achieve the ideal, I still want the automated build to tell me when I’ve gotten out of sync with the build’s expectations.
Theory in Practice
That’s the underlying philosophy. You can see it play out in the WeeWikiPaint codebase in a variety of small ways.
Jake, and all the command-line tools the build uses, are installed locally rather than globally.
When you run the “jake” script for the first time, it automatically builds all the npm binaries, including Jake itself.
The build will fail if a different version of Node is installed than expected.
The Karma tests confirm that the expected browser and OS versions are being tested.
Cross-team IDE settings are stored in the repository (but machine-specific settings are in the
.gitignore
file).All dependencies, including
node_modules
are stored in the repository (but binaries are .gitignore’d).
The code’s not perfect, and there are some things that I still don’t know how to store reliably, but I get as close as I can. Those node_modules
and .idea
folders may look like a mess, or a waste of space, but they’re actually a vital part of a reliable build.
(Thanks to “Madara Uchiha” for asking the questions that inspired this essay.)