Massimo Arnoldi and I were
working on booking payments for a life insurance policy. The requirements and the code were difficult to grasp
because of all the special cases- what if they pay too much, what if they pay late, what if they pay for two months
at once, etc.
We spent half a day trying
to come up with the tests and code for this situation, without success. Every time we got one test working, we
discovered the need for three others.
Cheese and oregano pizza
and a couple of espressos later, we decided to solve a simpler problem. Could we just test and code the part that
decided whether booking a payment was possible at all? Sure- if the amount matched, we could book. Otherwise we
had to ask for human intervention. We made a couple of tests and an object that passed them. Elapsed time, 15 minutes.
Next, could we correctly
book a payment? Given that the first test passed correctly, we could assume that the source account had the correct
balance. Testing and coding was trivial- one test, one object, one method, done. Elapsed time, 5 minutes. |

We wouldn't have created
two objects if we hadn't been coding test first. The second object would have been god awful complicated if we
couldn't rely on the first test passing. Net result of test-first (once we pulled our heads out)- cleaner design,
correct behavior, simple tests, and simple code.
I now try to apply this
strategy to all of the difficult problems I encounter. "What are the pieces, the combination of which I will
have confidence in assuming that the pieces all work?" I don't always find the pieces right away. Sometimes
it's months or years. In the meantime I have lots of tests for my less-than-optimal design. When insight rears
its ugly head, I have all the resources I need to retrofit it.
 
First Class Software |