Brian Marick writes wonderfully (as usual) about how requirements documents and tests communicate the same thing in different ways. The interesting point is that, although it’s difficult to see how tests communicate the necessary information, for various reasons they do so more effectively than a requirements document. It shouldn’t be surprising that we have a hard time convincing some people of that.
I’ve been thinking about a related issue for a couple of years now. In The Mythical Man-Month, Fred Brooks writes about “the project notebook”: the authoritative source for information about the project. And it sounds like such a good idea. It’s easy to see how that would work. It records important information precisely and directly.
It’s also—as you begin to understand when you read Brook’s ideas for how to manage the project notebook—incredibly unwieldy and inefficient. And while the notebook might (if you spend a lot of time and money on it) contain all of the important information, it’s highly unlikely that it would ever be completely understood, by the right people at the right times in the right ways.
It works much better to let the code—the system itself, plus executable tests—serve as the project notebook. This is why iterative development is so important. The code is functional, and it gives us feedback about our understanding. (More importantly, it gives us feedback about our misunderstanding.) If we think we know something about how the system works, we try to write code that depends on that knowledge, and the system will tell us if we were correct. With the project notebook, on the other hand, we might not learn about our error until weeks or months have passed, by which time the ripple effects from our mistaken assumption will be tremendous.
Another common objection to agile styles of development goes something like this: “You mean you don’t document or model design decisions that come out of a meeting? Haven’t you ever been to a meeting where everyone thought they had reached an agreement, only to find out that each person understood the decisions differently?” Sure I have. But the problem there, I believe, is largely that people have a hard time communicating about abstract things. Handwaving, and even boxes and lines, aren’t really very expressive about what software is. I’ve been in a lot of those discussions, and the problem is that there’s almost no feedback about whether you really understand what’s being said. I’ve been completely confused and at the same time absolutely convinced that I understood everything.
When people have those same discussions in the context of code—working code—communication changes. It may seem strange to say this about software, but code is concrete. It’s unambiguous. It grounds our discussions in a reality, and it’s a terrific aid to effective communication and understanding. It provides a feedback mechanism for the act of communication. If you don’t understand what’s being said, then the proposal (more often than not) won’t make any sense when held up against the code.
It’s no wonder that, in many test-first teams, design debates are frequently carried out through unit tests. The “conduit” and “program” metaphors of communication each have their strengths, and the best policy is to let them support and reinforce each other.