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.
  |