We should be taught not to wait for inspiration to start a thing. Action always generates inspiration. Inspiration seldom generates action.
The TDD process we described in Chapter 1 assumes that we can grow the system by just slotting the tests for new features into an existing infrastructure. But what about the very first feature, before we have this infrastructure? As an acceptance test, it must run end-to-end to give us the feedback we need about the system's external interfaces, which means we must have implemented a whole automated build, deploy, and test cycle. This is a lot of work to do before we can even see our first test fail.
Deploying and testing right from the start of a project forces the team to understand how their system fits into the world. It flushes out the “unknown unknown” technical and organisational risks so they can be addressed while there's still time. Attempting to deploy also helps the team understand who they need to liaise with, such as system administrators and external vendors, and start to build those relationships.
Starting with build, deployment and test on a non-existent system sounds odd, but we think it's essential. The risks of leaving it to later are just too high. We have seen projects cancelled after months of development because they could not reliably deploy their system. We have seen systems discarded because new features required months of manual regression testing and even then the error rates were too high. As always, we view feedback as a fundamental tool, and we want to know as early as possible whether we're pointing in the right direction. Then, once we have our first test in place, the subsequent tests will be much quicker to write.
The quandary in writing and passing the first acceptance test is that it's hard to build both the tooling and the feature it's testing at the same time. Changes in one disrupt any progress made with the other, and tracking down failures is a tricky when the architecture, the tests, and the production code are all moving. One of the symptoms of an unstable development environment is that there's no obvious first place to look when something fails.
We can cut through this “first-feature paradox” by splitting it into two smaller problems. First, work out how to build, deploy, and test a Walking Skeleton, then use that infrastructure to write the acceptance tests for the first meaningful feature. After that, everything will be in place for Test-Driven Development of the rest of the system.
A Walking Skeleton is an implementation of the thinnest possible slice of real functionality that we can automatically build, deploy, and test end-to-end [Cockburn04]. It should include just enough of the automation, the major components and communication mechanisms, to allow us start work on the first feature. We keep the skeleton's application functionality so simple that it's obvious and uninteresting, leaving us free to concentrate on the infrastructure. For example, for a database-backed web application the skeleton would show a flat web page with fields from the database; for a desktop user interface, the skeleton would start the application and exercise the simplest user interaction; and, for a message processing system, the skeleton would route an empty message through the broker. You'll saw this working in practice in Chapter 6.
It's also important to realise that the “end” in “end-to-end” refers to the process, as well as the system. We want our test to start from scratch, build a deployable system, deploy it into a production-like environment, and then run the tests through the deployed system. Including the deployment step in the testing process is critical for two reasons. First, this is the sort of error-prone activity that should not be done by hand, so we want our scripts to have been thoroughly exercised by the time we have to deploy for real; the one lesson that software teaches us is that nothing forces us to understand a process like an attempt to automate it. Second, this is often the moment where the development team bumps into the rest of the organisation and has to learn how it operates. If it’s going to take six weeks and signatures up to director level to set up a database, we want to know now not two weeks before delivery.
Whilst building the Walking Skeleton, we concentrate on the structure and don't worry too much about refactoring the test to be beautifully expressive. The walking skeleton and its supporting infrastructure are there to help us work out how to start test-driving development. It's only the first step toward a complete end-to-end acceptance testing solution. When we write the test for the first feature, then we need to “Write the test that you'd want to read” to make sure that it's a clear expression of the behaviour of the system.
The development of a Walking Skeleton is the moment when we start to make choices about the high-level structure of our application. We can't automate the build, deploy, and test without some idea of the overall structure. We don't need much detail yet, just a broad-brush picture of the major system components that will be needed to support the first planned release and how they will communicate. Our rule of thumb is that we should be able to draw the design for the Walking Skeleton in a few minutes on a whiteboard.
We find that maintaining a public drawing of the structure of the system, for example on the wall of the team's work area, helps the developers stay oriented when working on the code.
picture hereTo design this initial structure, we have to have some understanding of the purpose of the system, otherwise the whole exercise risks being meaningless. We need a high-level view of the client’s requirements, both functional and non-functional, to guide our choices. This preparatory work is part of the chartering of the project, which we must leave as outside the scope of this book.
The point of the Walking Skeleton is to use the writing of the first test to draw out the context of the project, to help the team map out the landscape of their solution—the essential decisions they must take before they can write any code; Figure 13.1, “The context of the first test” shows how the TDD process we drew in Figure 1.3, “Inner and outer feedback loops in TDD.” fits into this context.
Please don't confuse this with doing “Big Design Up Front” (BDUF) which has such a bad reputation in the Agile community. We're not trying to elaborate the whole design down to classes and algorithms before we start coding. Any ideas we have now are likely to be wrong, so we prefer to discover those details as grow the system. We're making the smallest number of decisions we can to kick-start the TDD cycle, to allow us to start learning and improving from real feedback.
We have no guarantees that the decisions that we've taken about the design of our application, or the assumptions on which they're based, are right. We do the best we can, but the only thing we can rely on is to validate them as soon as possible by building feedback into our process. The tools we build to implement the Walking Skeleton are there to support this learning process. Of course, these tools too will not be perfect and we expect we will improve them incrementally as we learn how well they support the team.
Our ideal situation is where the team releases regularly to a real production system, as in Figure 13.2, “Requirements feedback”. This allows the system's stakeholders to respond to how they find the system meets their needs as much as it allows us to judge its implementation.
We use the automation of the build and test to give us feedback on qualities such as how easily we can cut a version and deploy, how well the design works, and how good the code is. The automated deployment helps us release frequently to real users, which gives us feedback on how well we have understood the domain and whether seeing the system in practice has changed our customer's priorities.
The great thing is that we will be able to make changes in response to whatever we learn because writing everything test-first means that we will have a thorough set of regression tests. No test are perfect, of course, but in practice we've found that a substantial test suite allows us to make major changes safely.
All this effort means that teams are frequently surprised by the time it takes to get a Walking Skeleton working, considering that it does hardly anything. That’s because this first step involves establishing a lot of infrastructure and asking (and answering) many awkward questions. The time to implement the first few features will be unpredictable as the team discovers more about its requirements and target environment. For a new team this will be compounded by the social stresses of learning how to work together.
Fred Tingey, a colleague, once observed that incremental development can be disconcerting for teams and management who aren't used to it because it front-loads the stress in a project. Projects with late integration start calmly but generally turn difficult towards the end as the team tries to pull the system together for the first time. Late integration is unpredictable because the team has to assemble a great many moving parts with limited time and budget to fix any failures. The result is that experienced stakeholders react badly to the instability at the start of an incremental project because they expect that end of the project will be much worse.
Our experience is that a well-run incremental development runs in the opposite direction. It starts unsettled then, after a few features have been implemented and the project automation has been built up, settles in to a routine. As a project approaches delivery, the end-game should be a steady production of functionality, perhaps with a burst of activity before the first release. All the mundane but brittle tasks, such as deployment and upgrading, will have been automated so that they “just work”. The contrast looks rather like Figure 13.3, “Visible Uncertainty in Test-First and Test-Later projects”.
This aspect of Test-Driven Development, like others, may appear counter-intuitive but we've always found it worth taking enough time to structure and automate the basics of the system. Of course, we don't want to spend the whole project setting up a perfect Walking Skeleton so we limit ourselves to whiteboard-level decisions, and reserve the right to change our mind when we have to. But the most important thing is to have a sense of direction and a concrete implementation to test our assumptions.
Copyright © 2008 Steve Freeman and Nat Pryce