TDD

Copyright (c) Andrew J. Peterson

My first experience I was under a deadline to build the site map, breadcrumb system, page name and hierarchy and dynamic menues for an webapp. I wrote a basic design requirements, shopped it around, but no one cared. Then, in three days I created the XML config DTD, in-memory model, and JSP tags. I wrote the tests of all the model reading and access, and then the code. I was surprised when it came together faster than I expected, and moreso when I plugged in the tags to the pages, filled out the configuration file (from the user experience engineer), and everything worked. I usually make a few mistakes. In two years after that I never got a bug report about this code. I'm not bragging, just blown away! I was surprised how quickly things came together, and I credit the tests with allowing me to build the web-tier code (often hard to test), on top of a solid foundation. I was sold.

2

The next breakthrough was developing a new application with a small team of less experienced engineers. It is a web site about schools, and I was disciplined about defining the fundamental concepts and the tests around them -- grade levels, school types, etc. It may seem really simple, and it is, but we've all had experiences where fundamental concepts are either ill-defined or "evolve". The new engineer thinks an "ungraded" school has all the grades set where the old one thought it was an empty set. Is a school with only 5th grade students a middle or elementary school?

So not so much benefit from TDD in defining or writing these classes, but going into maintenance mode it really helps. It helps communicate to engineers the behavior of the class, more than documentation often does. They couldn't change the behavior of a core object without breaking a test, and that did seem to hamper these easy but costly changes. In a team environment having those tests in place really grounds the software. And when we did have to make changes, it was easier to see the implications of changes-- so the maintenance really is TDD and helps drive the development.

3

My next breakthrough was a data cleansing tool at the same company. I ended up writing something I never could have done any other way. We had about 120 different sources of school data, each with their own capitalization and abbreviations. "Hi" vs. "High", "Jr" vs. "Junior", "Rd" vs. "Road", and (believe it or not) 30 different variations of "kindergarten" (I counted). We wanted to have a consistent editorial style to the site, but since most of the site was data, we weren't doing very well.

My (self-appointed) task was to clean these up and do it in such a way that ongoing updates would following the same rules. One example of this is the school names themselves. As part of the requirements, I started building a list of test inputs and desired test outputs. It was a simple XML file with multiple <input> elements, and a single <output> element. As we scoured the school names with an editorial eye, I'd capture all the ways the data sources messed things up (including those 30 kindergartens). So I was just writing a simple

String fixSchoolName(String name, State s, Type t)

Not too hard. I started 20 or so cases we knew about, and a regex handled them. But when I had finished months later, there were more than 1000 different "tests". There are separate rules for private schools (to deal with the Saints consistently), handled problems like "Lagrange, IN" vs. "La Grange, AR" that our data providers didn't seem to understand, and even handled one of my favorites, "Martin Luther King Jr. Junior High", no matter how mangled the input was. And there are 100s of hard-coded rules because some data sources just have bad data we wanted to fix and there's no generic rule.

As we had to fix more names, we'd throw in the new tests, write code, and get immediate feedback about whether the change caused other problems. Without TDD, this would have been a much longer cycle, and I wouldn't have been able to accomplish what I did. As it was, this was my fifth or sixth priority, but I was able to do what I consider a high quality job. I created a complex piece of code (100s of regexs) that I had complete confidence in. I grew to be comfortable processing the whole database of 20k schools. I never would have been able to do this without TDD.

4

Oh yeah, here's a final case where TDD was helpful. In order to get a job interview at a company, they asked you to write a multiplication routine without using the * operator. I wrote test cases along with 4 answers in just a few minutes. This got me the interview (but not the job.)

Other Thoughts

I find TDD works best with simple unit tests. Those are the easiest to write, so you get the most bang for your buck. Once you have to mock or stub dependencies, or bring up a web container, the tests are harder to write and run, and therefore less return on investment.�

There's also the thought that if you don't get in the habit of writing tests first, you won't write them. From my experience, this is pretty much true.