TDD changes code design from invention to discovery
I was reading the paper Mock Roles, not Objects, and there’s a description of TDD that captures an important concept I haven’t been able to put into words before:
[TDD] changes design from a process of invention, where the developer thinks hard about what a unit of code should do and then implements it, to a process of discovery, where the developer adds small increments of functionality and then extracts structure from the working code.
Though I never thought about code design as invention vs. discovery, TDD certainly makes it feel like I’m discovering rather than inventing. Typically, my process is very iterative:
-
Write a test for the simplest behavior of function A
-
Get the test to pass
-
Write a test for how function A behaves with an edge condition
-
Get the test to pass
-
Write a test for how function A behaves with invalid inputs
-
Get the test to pass
As I get each test to pass, I’m focused on writing an implementation that satisfies the behavior. But it’s usually not the end result.
Once I satisfy the full behavior of function A, as specified by the tests, I then proceed to refactor the implementation to improve it – extracting the structure from the working code.
That whole process is one of discovery. First, I discover what satisfies the behavior. Then, I discover a better shape for the code.
On the rare occasions I don’t follow TDD, I feel like I have to do a lot more work because my brain has to invent the design from the beginning. I have to think of all the conditions and possibilities ahead of time and write down a fully-finished version of the code that works and looks right.