Why Do Many Developers Hate TDD?

Priyal Walpita
5 min readJul 26, 2023

--

Test-Driven Development (TDD) is a powerful technique within the software development world, renowned for creating more reliable, robust, and maintainable code. Yet, it has been subject to a fair share of resistance. This resistance often stems from misunderstandings, reluctance to change traditional practices, or simply, the discomfort of venturing into unknown territory. Let’s break down these barriers and debunk some of the myths surrounding TDD.

The Heart of Test-Driven Development

TDD is a unique approach to programming that hinges on an iterative cycle: Red, Green, and Refactor. To break down this cycle, in the “Red” phase, you start by writing a test for a specific functionality and then run it to see it fail. This failing test sets a clear target for what the code should accomplish.

Once you’ve witnessed the test fail, you transition to the “Green” phase, writing just enough code to satisfy that test condition, thereby turning the test from red (failing) to green (passing). It’s about finding the shortest route to stability in the form of code with a passing test.

The last phase, “Refactor,” is about cleaning up the code without changing its behavior. You keep the code efficient, maintainable, and devoid of any redundancies. It ensures your codebase remains elegant and straightforward, simplifying future development work.

But here’s the catch — TDD is not merely about testing. It’s a design approach. Testing checks for the presence of bugs in an existing piece of code. In contrast, TDD is about writing the test first and letting it guide your code’s design, focusing on what we want the code to do. TDD allows us to sidestep most of the problems associated with testing alone, but it’s crucial to understand they aren’t the same thing at all.

Tackling the Objections to TDD

Following are a few misconceptions about TDD.

1. The Perception of Slowness

One common criticism is that TDD is slow. At face value, it might seem like TDD slows down the development process. After all, writing tests before writing functional code feels like an additional step. However, it’s essential to think of TDD not as a hurdle, but as an investment. While it might seem to slow down the development process initially, it pays off in the form of higher code quality, fewer bugs, and less time spent on debugging and maintenance down the road. It’s akin to laying a strong foundation before building a house.

2. The Misbelief That TDD Doesn’t Work

Another objection arises from the belief that TDD is ineffective or unnecessary. However, evidence suggests otherwise. Some of the most successful companies today attribute their high-quality software products to TDD. When someone asserts that TDD doesn’t work, it often reveals a lack of understanding or knowledge about how to implement it effectively, rather than a flaw in the TDD approach itself. Therefore, the remedy to this obstacle is education and hands-on training.

3. The Assumption That TDD Doesn’t Apply to Complex Systems

Some developers assume that TDD doesn’t apply to complex systems like games, infrastructure, embedded systems, and legacy systems. But the premise of TDD, which is specifying what the software should do and writing it down in code form (i.e., the test), applies across the board.

While it’s true that designing tests for complex systems can be challenging, TDD can actually simplify this process. It forces developers to break down complex tasks into manageable units and consider the software’s functionality at a granular level. Moreover, TDD can help identify problems earlier in the development process when they are typically easier (and less costly) to fix.

Clarifying the Real Purpose of Tests

In many fields and professions, tests are often seen as a tool for verification, a means to certify that something is correct or valid. For instance, in academia, a perfect score on a test might affirm a student’s mastery over a subject. However, in software development, this notion is misplaced. Tests, especially in the context of TDD, serve a different purpose.

One common misconception is that tests in software development prove the correctness of code. This misunderstanding can lead to the dangerous assumption that a codebase with passing tests is flawless and free of bugs. The reality, however, is that tests do not guarantee correctness, but instead aim to expose incorrectness. No matter how extensive, tests can’t cover every possible scenario that the software might encounter in the real world. Even with rigorous testing, there’s always a chance that an unanticipated situation could cause the software to behave unexpectedly.

Tests, therefore, are best used as a means of falsification, not validation. They don’t confirm that our code works in all scenarios; instead, they help identify when our code fails under specified conditions. This falsification approach is at the heart of TDD. If a test fails, that’s a clear signal that there’s a problem that needs addressing. It’s a red flag indicating the presence of a bug that might have otherwise gone unnoticed until much later in the development process or, worse, once the software is in the hands of users.

Automatic tests are particularly valuable for this purpose. They can be run repeatedly and reliably, ensuring that as the codebase grows and evolves, previously written code still performs as expected. These tests serve as a safety net, catching regressions and other issues early when they are typically easier and less costly to fix.

Moreover, in TDD, the tests drive the code’s design and are written before the functional code itself. This is not just about bug detection, but also about creating software that is easier to maintain, more robust, and adaptable to changes. It encourages developers to write code that is testable, modular, and clearly defined in its purpose, thus improving the overall code quality.

Conclusion

It’s clear that Test-Driven Development, despite misconceptions and initial hurdles, carries immense value for software development teams. TDD fundamentally alters our development approach, prompting us to rigorously define our expectations before diving into implementation, thereby ensuring that our code is purposeful and accurate from the outset.

The crux of TDD isn’t merely about preventing errors or ensuring that our software works as expected, although those are certainly valuable outcomes. At its heart, TDD is a philosophy of design and quality, a commitment to thoughtfulness and precision that can elevate our software to new heights of reliability, maintainability, and overall excellence.

References

Martin Fowler’s guide to Test-Driven Development

ThoughtWorks Insight on TDD

--

--

Priyal Walpita

CTO @ ZorroSign | Seasoned Software Architect | Expertise in AI/ML , Blockchain , Distributed Systems and IoT | Lecturer | Speaker | Blogger