I started doing TDD in 1999. I decided to tweet twenty random thoughts on TDD, roughly one per business day starting 2019 February 14, using the hashtag #20YearsTDD. Each tweet represents a good topic for an article that I should write (and might already have written).

Here are the tweets from #20YearsTDD. They appear in the order posted:

  1. 70% coverage (a typical claim by test-after folks) sounds good until you realize that means almost a 3rd of your system is at risk and thus more rigid.
  2. TDD is a simple and dumb cycle, in that it doesn’t bring the magic, you do: TDD allows you to continually think about and address design.
  3. The hardest part of TDD: It’s a habit you must ingrain; harder still if you have a different habit you must break.
  4. Doing test-after dev (TAD) should, in theory, be able to provide the same improved design results as TDD. In reality, I’ve never seen it happen. People don’t generally clean up their design because they wrote some tests after.
  5. That ~70% coverage suggested as a good goal by test-after (TAD) proponents isn’t uniform. It’s more like 26% here, 63% there, 84% there. That means you’re always wasting time figuring out just what protections you truly have.
  6. Were a manager to have long ago told me “you have to do TDD,” (like they tell people to write unit tests), I probably would’ve told ’em to get lost, then found ways to not do it. Mandates get you nowhere.
  7. TDD forces the issue of breaking things down into small, incremental chunks–probably one of the most useful things you can learn as a developer. And you’ll get better at it quickly.
  8. Devs always want to learn “how do I fix my legacy mess” first. But there’s not much point teaching how until they know what a good system looks like, and how TDD might help get them there.
  9. TDD accommodates–and requires–continual thinking about design, at every step of red-green-refactor, every time. It’s all design.
  10. “In a clean, well-designed system, I probably spend roughly the same amount of time reading code as I do writing it. In a poorly-designed system, I spend far more time reading code than writing it.” (“How much time do you spend writing code vs. reading code,” via Quora)
  11. TDD won’t magically take you to Great DesignWorld; you have to know the route. In contrast, not doing TDD basically clamps you to railroad tracks to eventual Design Dismaland.
  12. TDD is a great tool in your toolbox that helps shape code & eliminate logic defects (among other things). TDD alone is is insufficient enough to support all your developer testing needs.
  13. TDD will help you document the thousands of little choices you made in your system… info that otherwise can take hours to learn when you later need to know the choices you made.
  14. TDD does takes more time initially–when you first start learning; also when you first start a new effort. You can save time by not doing TDD for the first day or so. After that, you’re chewing up far more time than you think you saved.
  15. Hypothesis: (In a test-after system) Code and complexity grow more rapidly in the uncovered areas of a system, making those areas increasingly more brittle and rigid.
  16. There is no dichotomy: Doing TDD does not come at the expense of other forms of testing.
  17. The TDD stumbling block for seasoned developers: “I know what the implementation needs to be in 30 minutes, why can’t I just code it now?”
  18. A small secret: Almost everyone thinks writing unit tests after code (TAD) is tedious, not fun, and only moderately useful. Infected folks usually find TDD to be a lot of fun and extremely useful.
  19. I continue to do TDD because it’s a lot of fun. Even though it’s also gratifying to be able to ship clean, working code, I wouldn’t do TDD if I hated it.
  20. The habits & things I continue to embrace are those that either bring me “geek joy” or ensure security. TDD provides both. “Geek joy” is what it’s mostly about.

New article at Ranorex, “The Value of Failing Tests”

failing testsThe Value of Failing Tests (30-Oct-2018)

“A test that passes with no change to your classes is always cause for humility and pause.”

We learn red-green-refactor for a reason–it’s not just “green-refactor.” In this blog post for Ranorex, I talk about the various reasons why you might see tests pass (green) when expecting them to fail. You’ll learn why it’s important to stick to that TDD rhythm.

New article at Ranorex, “Insights from the TDD Community”

insights from the TDD communityInsights from the TDD Community (21-Aug-2018)

Check out We Do TDD for numerous great stories about test-driven development from people, teams, and companies that test-drive their software.

In this blog post for Ranorex, I talk about Dave Schinkel’s site that features interview questions and answers from a good number of TDD practitioners. I highlight some answers to questions about interesting TDD topics:

  • How did you adopt TDD?
  • Why would you want to be “test infected?”
  • How does TDD relate to design?

New article at Ranorex, “Find the Right TDD Approach for Your Testing Situation”

TDD approachesFind the Right TDD Approach for Your Testing Situation (16-Aug-2018)

No, there’s no one “right” way to practice TDD, though there are plenty of ways that technically are not TDD.

In this blog post for Ranorex, I talk about some of the variant ways of approaching test-driven development (TDD). I first introduce two distinct ways of describing TDD. I then discuss “assert-first,” “one assert per test,” and how tests are best named (or not).

Interview, “How Unit Testing Improves Code Quality in TDD”

Hardik Shah presents an article, “How Unit Testing Improves Code Quality in TDD.” The first part of the post, hosted at Simform’s site, describes test-driven development (TDD) and unit testing, and also demonstrates a brief example of creating code using TDD.

After presenting some recommendations for practicing TDD, Shah provides three “case studies,” which seem closer to interviews about industry experts’ perceptions of TDD. The three folks involved include J.B. Rainsberger, Frederico Goncalves, and myself.

WeDoTDD: Companies & Teams Practicing Test-Driven Development

Take a moment and head on over to WeDoTDD.com: a site that posts detailed information about companies, people, and teams who practice and teach TDD. You’ll pick up some great ideas about what works with TDD in real teams.

You’ll find an in-depth interview with me talking about my TDD experiences as an individual and also with respect to working with my customers. I enjoyed answering the questions, and some of them forced me to think hard about why I do things the way I do.

New article at Gurock, “Test-Driven Development: A Love Story?”

TDD: A Love StoryTest-Driven Development: A Love Story? (22-May-2018)
In this blog post for Gurock, I wax rhapsodic about TDD… well, maybe not. I don’t love TDD itself; I love the things that TDD enables me to do. I talk about what those things are, along with a bit of my personal history about how I got here.

New article at Ranorex, “Convincing Your Team to Adopt TDD”

adopting TDDConvincing Your Team to Adopt TDD (15-May-2018)
In this blog post for Ranorex, you’ll pick up a number of ideas about how to approach introducing TDD into your team. While TDD is a simple practice to learn (though a challenge to master), getting developers to think they might want to even consider it is not an easy task. I’ll also talk about why resistance is to be expected.

New article at Ranorex, “Why I Practice TDD: Speed and Need”

TDD: speed and needWhy I Practice TDD: Speed and Need (2-Mar-2018)

Why do TDD at all?

In this blog post for Ranorex, I explain that my primary reason to do TDD is because it allows me to go faster, particularly as a system grows. I talk about some of the reasons why, and iterate some of the high cost of defects along the way.

Clean Tests: Common Concerns, Part 2: “I’ll Have Twice As Much Code to Maintain”

The unit tests you produce in TDD represent an investment. You’ll want to ensure they continue to return on value and not turn into a liability.

Breaking Dawn - Loch Rusky
“Breaking Dawn – Loch Rusky,” courtesy John McSporran.License.

The concerns:

  • The tests will have their own defects.
  • I’ll have twice as much code to maintain.
  • The tests are handcuffs.
  • Testing everything (via TDD) results in diminishing returns.

I’ll have twice as much code to maintain

It’s true, do TDD and you’ll likely have as much test code as production code, if not more. However, most sizable non-test-driven systems contain over twice the code needed. In other words: if C represents the ideal amount of production code for a system’s implementation, and TC represents test code, then 2C ≈ C + TC. That’s a wash, to me. I’ll take the version that comes with the tests, thank you.

2C? Twice the code needed? How’s that? The short answer: In non-test-driven systems, there’s no high-confidence way to keep code cruft from building up.

The TDD Bet

I worked with a customer in the Great Lakes area some years ago. They’d deployed a production application prior to my arrival; I was told its initial non-test-driven release was around 180,000 lines of Java code. The team, dedicated to TDD, had slowly but surely added unit tests as they test-drove new features, meanwhile cleaning up what they could in the legacy code. By my arrival, they’d shrunk the codebase to around 70,000 lines; by the time I’d left, they’d shrunk it perhaps another 10,000 lines.

Granted, much of the bloat was a large swath of dead and generated code they’d spotted. But a significant amount was purely unnecessary code.

I’d take the TDD Bet on almost any sizable legacy codebase: Given enough time to add tests and clean things up, it could be reduced to under half its size. A codebase with 100,000 lines of bloated code can transform into a codebase with 50,000 lines of production code and 50,000 more of tests.

Where Does This Bloat Come From?

I’m guilty of producing bloated code on my first pass of implementing some small solution. It’s much like writing (for example, these blog entries): I’ll slam out a few sentences in an attempt to spew what’s in my head onto the computer screen. Then I’ll read what I wrote, trying to put myself into the shoes of another reader: Does it make sense? Is it as punchy as it could be? I usually find numerous opportunities for cleanup!

There’s nothing wrong with slapping out a sloppy paragraph as long as you clean it up later. The same approach works for coding, with the caveat that you don’t want to wait too long–“later” might never come because something new demands your attention. When doing TDD, we ensure we clean up the code every few minutes, using the confidence that a passing test suite gives us.

Without TDD, we don’t do nearly enough of these little bits of clean-up. It’s far too unsafe: The chance of breaking other stuff is way too high. By definition, our non-test-driven code stinks a little bit more every few minutes.

Duplicate code rears its ugly head all the time. Duplication can happen in many forms–small bits of logic appearing dozens of times throughout the codebase, different algorithms to accomplish the same purpose, rote mechanisms where more abstract concepts would suffice.

I watched a developer copy-and-paste an entire 100+ line function in order to introduce a small, 5-line-long code variance. The right thing, of course, would be to use delegation, polymorphism, whatever, as long as it didn’t mean duplicating logic. And the developer knew that, as we might hope. “But I don’t want to change that function. I don’t want to be the one who crashes production because I changed some working code in order to make the system ‘cleaner.'”

Rather than introduce design concepts that minimize redundancy when they must deal with behavior variances, developers make what they think is the least impactful change out of fear. For these programmers, the notion of cleaner provides no immediate, obvious value. We know clean will make their job easier over time, but fear now intimidates more.

So, yes, with TDD, you’ll have as much test code as production code to maintain, but overall the amount of code will not be significantly different.

More importantly, you won’t fear your own code.