I saw an angel in the block of marble and I just chiseled ’til I set him free. – Michelangelo
My last post, about what my colleague Yuval Mazor coined “post-tdd-ism”, came under some criticism. It was mostly triggered, understandably, by the last sentence of this paragraph:
So we learn over time which design patterns are more testable, robust and extensible. They often evolve almost on their own. We also learn which structures produce less complexity. And we start using those patterns and structures, by default. We sometimes feel that their role is more boilerplate than logic. The most important take-away is that at this point, many programmers can “see” the tests in their mind’s eye. They can drive the development using virtual, unwritten tests.
Before I answer the criticism, let me set the record straight. I do not encourage using “unwritten tests”. I do not claim this is a TDD technique that should be taught, emulated, or encouraged. It is not the canonical way (if such exists) to do TDD. TDD is most effective, as I stated in my previous post, when the tests are explicit, written, and automated. To sum it up: don’t try this at home, kids!
So, you might ask, if I’m not promoting unwritten tests, what in blazes am I talking about? Well, I’m glad you asked that question…
In that post, I was trying to describe what I believe to be a common phenomenon: programmers do not write every possible, or even every reasonable test. More importantly, they do not write all the tests they consider writing.
Even when we drive our development using conventional TDD practices, there is never a one-to-one mapping between the decisions our code makes and the tests we write for those decisions. In fact, in anything more complicated than a trivial tutorial (and likely even then), it is highly unlikely that any two programmers will end up writing the same tests or the same code to solve any given problem. Subjective factors such as personal coding styles, favored TDD flavors, and choice of unit testing frameworks, also affect the types of tests and the resultant code.
This extreme variability, however, is hardly ever noticed; it’s simply unremarkable. Only two things really concern us when we do TDD:
- The test must be written wellin accordance with the most basic strictures.
- The test must, obviously, drive development.
The rest of it – the tools, the languages, the styles – are all insignificant by comparison and fall by the wayside.
There is a reason for this, one I alluded to in my previous post. TDD is a technique or mechanism that channels and gives structure to creativity. The term “TDD” is really a misnomer: tests don’t really drive development, just as engines don’t actually drive cars. Engines channel energy, people drive cars. In the same way, tests channel creativity, but people, programmers, creative brains, generate the ideas that drive the code.
TDD is quite simply a professional, methodical alternative to those wistful, nostalgic, pizza-ridden and beer-filled nights spent in some garage working “in the zone”. It is a part and parcel of our profession. And as professionals, we strive to learn not just the necessary but tedious mechanical practice, but the art.
This is not a new idea, or unique to our profession. It takes practice, lots of practice, to master any technique. With practice, the technique becomes second nature and the art manifests. In martial arts, we repeat katas (“forms”), ceaselessly. In sports, we exercise, endlessly. And this is true of any profession: we get better at it by doing it more.
But we can also improve the efficacy of our practice by visualizing the exercise. This is called creative visualization, an increasingly common technique in which people guide their imagination in careful, methodical way, essentially practicing “in their mind”. It is not a “new age” or “alternative” exercise. It is a mental process that works when employed in a critical manner side-by-side with real practice.
My contention is that TDD is a tool for emulating creative visualization. It is effective mainly because it emulates so well the methodical mental process that creates high-quality design.
Professional TDD-ers reach a point where they “see” the test, and the resultant code, before they put virtual pen to paper. It feels sometimes like reading from a prepared script, while writing it. Most often, they will apply their professional and self-discipline and “copy” all of what they see in their mind’s eye – both the test and the code. But occasionally, they will skip a step. They might be tired, or decide that the test is too trivial or implied. Or they might mentally refactor and edit an existing test out-of-band (instead of red-green-refactor-red-green-refactor, they might red-green-refactor-refactor to capture a new test case).
Right or wrong, it happens. Ironically, in mediocre programmers, it is cause for concern, but in master programmers, a mark of their genius. Sometimes creative visualization happens unintentionally, but at other times it is quite intentional. Just as Michelangelo freed David from the marble, so do these craftsmen free algorithms from their minds.