There are good crutches and bad crutches in life. Being addicted to using heroin is a bad crutch but being addicted to using a working build is a good, healthy crutch. This is the kind of crutch that I want to encourage.
A healthy, well-maintained build is the heartbeat of a project. Removing friction from the build can greatly improve developers productivity. We want to make sure that the build is easy-to-use and if it breaks we want to make sure that it gives us informative error messages so we can quickly diagnose and fix the problems.
To me, a healthy build is the very essence of Agile software development. I say this because the first principle of the Agile Manifesto says, “Our highest priority is to satisfy the customer through early and continuous delivery a valuable software.”
Continuous delivery of valuable software requires continuous delivery. We have to be able to automate, not only the build but the entire verification process for the behavior we build in the system.
This is what it means to be agile in software development and to be able to respond to last-minute changes. If we have a manual process for assuring quality then it means that any minor change or addition to the system will often require a complete regression test of the entire system making it prohibitively expensive.
My preferred way of building an automated system is through test-first development. Since all the code that I write when doing TDD is to make a failing test pass, I usually have 100% code coverage. The tests that I write when doing TDD are behavioral unit tests which I find are usually the best for validating features. I often find that it’s best to think about my unit tests and testing in general as happening in two phases and for two very different purposes.
The first set of tests that I write are behavioral tests or acceptance tests and I write them at the unit level around units of behavior. These become the acceptance tests for my projects they support me when I refactor my code because they should continue to pass when I correctly change the implementation. This actually gives me the support that I need as a developer to refactor existing code and this is one of the main values of having behavioral tests, which we get naturally when we do test-first development correctly.
These tests are great but they may not be enough to validate all aspects of a feature so I often build up a set of additional tests that reach a bit further into implementation. I typically write these tests after I write my code or someone on my QA team writes them with me. These tests may give me more confidence that the system is working as it supposed to but these tests might break when I refactor the code and if they do I generally delete them or rewrite them.
A healthy build is a prerequisite for nearly every client that I have. We depend so heavily on our build that when it breaks it often means that the entire team can’t make any progress. So, keeping the build up and working is imperative.
Several years ago, my friend Thomas was showing me around his company one evening after everyone else had left. They were a true XP shop with team agreements on the walls and pairing stations everywhere. It was beautiful.
I noticed some heavy duty hardware set up in the corner and I asked my friend about this. “That’s our build server,” he said. “Want to see what happens when somebody breaks the build?” He asked me.
He walked over to a workstation, logged in, and typed a few lines. Suddenly, all the fluorescent lights in the building went out. The emergency lighting came on in a siren began to sound. I thought it was the fire alarm and I got up and ready to go but my friend stopped me.
“This is not a fire,” he said. “This is what happens when somebody breaks the build,” he said. “We don’t tolerate broken builds in our organization.”
When somebody breaks the build in his company everybody knows it and they have to fix it immediately. They can’t go to the bathroom or do anything else. They have to either fix the broken build or back out their changes so they system reverts to when it was working before. This is how dependent teams get when they have a reliable build.
A lot of crutches are bad but I find that when I have a reliable build that I depend on, it can give me such great superpowers that I find my dependency is worth it.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
Previous Post: « Keep Test Coverage Where it is Needed
Next Post: Why Practice Four: Collaborate »