5 Excuses for Not Doing TDD, Debunked

by Hit Subscribe 13. October 2018 03:21

When you hear test-driven development (TDD), you might think of something cute—but not something for real developers. You might be afraid to try it out, thinking it'll cause you to fail at your job.

I, too, have sat at my desk and thought, "Do I really need to test drive this?" So I empathize.

Developers are using TDD in business after business and may soon elevate it to an industry standard. We can either embrace it or continue to shy away in fear...and get left in the dust.

In this post, I will refute some of the more common excuses for avoiding TDD. But first, a quick primer to get you up to speed.

TDD excuses

TDD: A Quick Primer

TDD helps developers guide themselves through coding solutions by following three steps—red, green, and refactor:

1. Red: Write a failing test first. This ensures the test actually verifies something that needs to change

2. Green: Make the test pass in the production code as quick and dirty as necessary. This ensures you implement the correct functionality for the test.

3. Refactor. Clean up the code. Make it better than you wrote in the green step and better than you found it. This is a huge step. It ensures the code drives towards stability instead of entropy.

Now, onto the excuses.

1. "TDD Slows Me Down"

This is one of the most commons excuses I hear. It is also one of the most short-sighted.

The general complaint is, "All this extra code I must write slows down my ability to deliver the feature." But this assumes that the only part of feature delivery that matters is the actual writing of the code.

Think of it like driving. Say you're cruising at a steady 40 mph. You look over and see some Mustang shooting past you at 55 mph. Five minutes later, you approach a red light—but it turns green before you get there. You don't even need to slow down. You cruise on through while that same Mustang from earlier is still sitting at that stoplight, now needing to accelerate to catch up to you. In this scenario, you are the TDD practitioner; the Mustang is your anti-test cowboy coder.

In this example, the Mustang assumes they're going faster because, for a short period of time, they are. But the goal is not to get to the next stop light, but to your destination. As developers, our destination is getting features in the hand of our customers. The actual codification of this is just a slice of the overall pipeline. It is only a stop light. We need to understand the business problem and propose one or more solutions. Then we have to understand how these solutions could be implemented in the code and what their costs are. Then we have to ensure the feature is without defects and meets our customers' expectations. In most of the situations I've seen, the actual coding hasn't been the bottleneck.

In fact, test driving your code will make these other parts of pipeline faster and easier. Thinking about the output of the test will shape how you can get a proposed solution into the code. Wrapping your system in automated tests will reduce your defects. Test driving will let you cruise through the QA intersections while your cowboy coders will be stopped, trying to sort out their bugs.

2. "TDD Makes My Code Brittle"

If you're new to test driving, you might end up with brittle code. David Heinemeier Hansson calls this test-induced damage. As this great video discussion about TDD describes, this sort of damage comes as someone new to testing starts writing a test for each class. The new practitioner believes they need a test for every class, or the logic being tested is not a "unit." They then stub out any other classes the object under the test uses. This creates a web of tests and classes that are hard to change.

The impact of this style hits really hard when someone wants to apply the refactoring step. Whenever they change any public method on any of their classes, multiple tests break. This is what I mean by brittleness. The developer then starts believing test driving makes systems that are hard to change and thus will get messier as time goes on.

Let's go back to the car analogy. Say every time you go on the road, you drive 90 mph. Inevitably, you get in a bunch of accidents. But instead of going slower, using your turn signals, or any number of safety protocols, you give up on ever using a car again. You decide to just walk everywhere. Seems silly, doesn't it?

As the videos describe, there are ways of doing TDD that avoid this brittleness. A detailed how-to would be a whole post of its own, but the basic idea is simple. Test your public interface. I don't mean "public" in a code sense, but "public" in a "customer or consumer may see this" sense. Modularize your app using healthy patterns. If you need to go beneath the public interface to figure out some complex logic, that's fine, but delete the tests when you are done to avoid that brittleness.

3. "My Code Is Too Simple to Test"

Sometimes you may think, "This logic is simple. I don't really need to test it, much less test drive it." And if you're a senior developer, having many years of healthy test driving, you may be able to make that call. For the rest of us, that's a path of hubris. Usually, it's a way for people to avoid test driving when they don't feel like it.

Thinking this way ignores the whole equation. Every piece of code you write has both complexity and impact to your customers. These two dimensions can help you understand when you should test drive and when it's not worth it. See below:

Graph with Impact and Complexity

You can see that if you say, "I don't need to test because my code is simple," you're ignoring the impact of the code. It is still worth testing high-impact simple code. If you are new to TDD, you should test all four quadrants, if only for the practice.

I sometimes fall into this trap of simplicity, and it bites me almost every time. Remember: it's often the customers that pay for the developer's arrogance.

4. "My Code Is Too Hard to Test"

This is a tricky one. There are many codebases that were not designed with testability in mind and, as such, are hard to test. It's easy to throw up your hands and walk away. Perhaps you want to fall into the rewrite trap. But if you do this, you are giving in to fear. Plus we need to test these codebases because they are not going away. Developers will continue to have to use them. If we let them sit and decay, the cost to build features in them will continue to increase.

You have many patterns and guidance these days to help deal with this challenge. Don't give up. Learn these patterns; put them in your code. Then test drive your way out of the mess.

5. "My Boss Won't Let Me"

You might have a boss who's skeptical. But remember: devs are the new kingmakers. You are professionals. You don't hear someone telling a doctor, "Hey, don't waste time washing your hands; we have a lot of patients for your see today." A healthy boss trusts you to do your job as professionally and effectively as possible.

If you find yourself with a boss that says, "Don't TDD," I believe you are obligated to advocate for it and explain your intentions. Often just explaining your reasoning can be enough to let them see the light.

Ultimately, if your boss continues to resist despite your reasoned explanations, you may want to reconsider your place at that institution. Like they say: change your organization or change your organization.

Let's Change Some Minds

Someday TDD will be standard practice, just like surgeons washing their hands before surgery. But this is an industry full of mysticism and fear, where showing logic and reason en masse can get you booed out of a room.

You have in this post logical explanations for why arguments against TDD don't hold water. We will have to win the world over one person—one reasonable argument—at a time. So don't give up. Show the people who give excuses for avoiding TDD exactly what they're missing.

This post was written by Mark Henke. Mark has spent over 10 years architecting systems that talk to other systems, doing DevOps before it was cool, and matching software to its business function. Every developer is a leader of something on their team, and he wants to help them see that.

Tags:

Blog