“Love” is a strong word. I’m not sure I really love test-driven development (TDD). But I do love solving problems by programming and crafting simple, elegant code.
Some things detract from this love:
- Delivering defects—how embarrassing!
- Pulling my hair out because I can’t understand how your (or my) code works
- Pulling my hair out because I can’t understand what your (or my) code does
Eighteen years after learning how, I continue using test-driven development because it gives me more opportunities to do the things I love (deliver clean software solutions), and because it reduces baldness-inducing software development pains (defects and unnecessary complexity).
Test-driven development on its own is just a rote feedback loop. Red, green, refactor. That’s not terribly interesting on its own. I don’t love TDD itself; I love the things that TDD enables me to do.
I’ve been designing code using TDD since 1999, or more than half of my 35-year professional development career. I often think about what it might have been like had I known enough to practice TDD in the first half.
Get TestRail FREE for 30 days!
1982: Correctness
I enrolled in the computer science (CMSC) program at the University of Maryland in 1982. My first semester’s computer class was CMSC 110P: The Calculus of Computer Programming. In 1982, software development represented a rewarding new career for many—in fact, too many to accommodate in Maryland’s CMSC department. Maryland’s response to the surge of wannabe programmers was to weed them out; CMSC 110P was its weed whacker.
We spent the better part of the semester on formal verification of computer programs—proofs, in other words. Well, that’s not quite correct. We spent most of the semester on one proof of one function in one computer program. That’s how painstaking the proofs were. Think about things like having to prove that you can formulate a variable from a series of characters.
Demanding software correctness worked well as a weed whacker. The next time you want to edge your lawn, consider forcing the weeds to formally prove their existence. They’ll wither and disappear out of sheer terror. Maryland’s weed-out class helped shrink its CMSC enrollment to a lushly packed but weed-free yard.
Passing CMSC 110P told me that I might be ready for a career in computer science. The confidence I got from knowing I wasn’t a weed was tremendous. However, this formal verification stuff wasn’t exactly practical. I quickly found out that real-life programming had little to do with formality.
Join 34,000 subscribers and receive carefully researched and popular article on software testing and QA. Top resources on becoming a better tester, learning new tools and building a team.
1982: Stupidity
My first paid job involved building programs for the University of Maryland’s Central Administration department—all the boring stuff associated with running a large complex of schools. COBOL was the order of the day, and my first paid program involved producing a simple report. Here’s the algorithm in circa 1982 COBOL:
Procedure Division.
Open input someDataFile.
Read someDataFile.
Perform writeReportRecord until someDataFile-IsAtEnd.
Exit program.
writeReportRecord.
Move someDataElement to outputDataElement.
Move someOtherDataElement to outputOtherDataElement.
Write outputRecord.
That was easy. But astute readers will note the omission of an important statement at the end of the writeReportRecord paragraph. In September 1982, I did not notice the missing statement. And no, I did not write a formal proof for this code.
Back then, we submitted batch jobs: scripts that executed programs in the proper environment, pointing to the proper files and devices. I scraped together and submitted a job just before leaving that evening, thinking, “This programming career is going to be easy.”
When I arrived the next morning, the operator said, “I’m sorry. I didn’t know if you wanted your job to keep running, but I needed to stop it after it chewed through the first box of paper.” Uh-oh. Back then, reports were printed on wide, green bar paper, and a box was a gigantic 20 pounds of paper—more than 2,500 sheets.
I remember arguing that the source data files were only a few hundred lines long. The report should have printed in half a dozen sheets. Instead, I cringed as I saw the very first record repeated over and over and over. Today, my memory tells me the record must have said, “All work and no play makes Jack a dull boy.” The horror.
“You get to keep it,” said the operator. She added, “Don’t worry, they’re not going to charge you the $35 for the box of paper,” knowing that it represented about ten hours of labor at my hourly rate. Relief! For another upside, I inherited a box of scrap paper that lasted about 15 years.
I learned an important lesson, too, of course: Check your programs. In my case, I realized infinite loops could be the worst kind of defect. If you’re going to read a file until it’s at its end, make sure you continue to read records from it:
Procedure Division.
Open input someDataFile.
Read someDataFile.
Perform writeReportRecord until someDataFile-IsAtEnd.
Exit program.
writeReportRecord.
Move someDataElement to outputDataElement.
Move someOtherDataElement to outputOtherDataElement.
Write outputRecord.
Read someDataFile at end move ‘Y’ to someDataFile-AtEndFlag.
Oops. I’ve made beaucoup mistakes since, but I never made a mistake that blatantly stupid again. Some of the rationale behind wanting software proofs began to make sense.
1999: Enlightenment
I learned to get pretty good at manually testing my code. I eventually moved on to write little driver programs that ran the code and printed some output that I could visually check. Defects were rare, but the applications I worked on were getting longer and more complex. Things were harder to verify.
I was fortunate enough to have worked in Smalltalk for a few years. I’d read Kent Beck’s columns in the Smalltalk Report, and I finally got a chance to see him speak at a Smalltalk conference. Hey, what’s this odd thing he’s speaking about called Extreme Programming?
Moreover, what’s this odd thing called test-first design, or TFD (as TDD was called at the time)? Write tests for your code? I didn’t go quite so far as to say, “I’m a programmer, not a tester,” as many still do, but I thought that it seemed like a lot of unnecessary overhead. Tests for everything? And first? The goal, at least, made sense: Here was a way to actually make short-cycle iterative development work, unlike our abandoned attempts at a spiral process while at MCI in the early 1990s.
Using TDD means we find out about problems before we get to iteration-end, and we constantly keep the code as clean as it should be.
I had an opportunity to experiment with TDD while coding solutions in Java at a startup. Initially, it seemed very awkward. I realized the awkwardness derived from the different approach to thinking about how to solve problems: Rather than scratch away at things until they produced a whole that did hopefully what I wanted, I was breaking down larger problems into lots of smaller problems that I could test (first!) in isolation. Put another way, I was designing and verifying constantly in small increments as I went.
Even more gratifying was that I now had opportunities to always “craft simple, elegant code.” Before, I’d gotten things to work, then occasionally went back and tried to make it easier to follow, simply because I enjoyed doing that and appreciated the quality outcome. But often I didn’t have the time, or I felt it was too risky to make a change.
With TDD, I could now spend small bits of time continually throughout my development day and apply those finishing touches to code. A few weeks of playing took me past the awkwardness and into the addiction—into the realm of test-infected, as they used to say.
TDD isn’t formal verification, but in some ways it’s better. It’s easy, and it shows how things work by example, which is vastly easier than reading formal specifications and proofs. I still make stupid mistakes, but far fewer, and I can’t recall the last time I shipped a logic defect.
I love programming. For making programming easier, TDD gets to share some of that love.
Article written by Jeff Langr. Jeff has spent more than half a 35-year career successfully building and delivering software using agile methods and techniques. He’s also helped countless other development teams do the same by coaching and training through his company, Langr Software Solutions, Inc.
In addition to being a contributor to Uncle Bob’s book Clean Code, Jeff is the author of five books on software development:
- Modern C++ Programming With Test-Driven Development
- Pragmatic Unit Testing
- Agile in a Flash (with Tim Ottinger)
- Agile Java
- Essential Java Style
- He is also on the technical advisory board for the Pragmatic Bookshelf.
Jeff resides in Colorado Springs, Colorado, US.
Test Automation – Anywhere, Anytime