Test Driven Damage?

Understanding the technical practices of software development is not easy for everyone and a lot of otherwise smart people are failing when they try to apply them. Some people even claim that the practices I cover in my book, Beyond Legacy Code: Nine Practices to Extend the Life and Value of Your Software, don’t work.

For example, David Heinemeier Hanson, the author of Ruby on Rails, says that Test Driven Development (TDD) is dead. He refers to what he calls “test-driven damage” where developers write too many tests, and write implementation dependent tests, and go about changing their production code to accommodate their tests.

Justin Searl wrote a blogpost about how TDD doesn’t really work very well. He says it may work well initially but as soon as we need to start to refactor our code, adding classes and methods, it requires us to write new tests and it breaks old tests.

Justin Searl and David Heinemeier Hanson are really smart people and bring a great deal of wisdom to our industry, but they’re missing some key points. I have seen “test-driven damage” before, where developers make compromises in code due to their tests, but this is not a fault of test driven development. It’s the fault of the way we’re using it.

Kent Beck said we should “write tests until bored,” because by the time a developer gets bored they probably have pretty decent test coverage for their code. But TDD is not about testing—at least not exclusively—and we shouldn’t put our tester’s hat on when doing TDD. It’s a different mindset. It’s like putting your editor’s hat on as you’re writing, and any writer will tell you that trying to edit yourself while you’re writing is a recipe for writer’s block. When writing it’s far better to just let the words flow then go back later to do the editing. A similar thing is true when we’re doing software development. The goal of writing code is to create behavior. Focusing on every little thing that could go wrong can block us, and we don’t want to do that—at least not initially.

No one ever said that if you have test coverage for a behavior and then you refactor the implementation to use more classes and methods that you have to add more tests. No one said you have to but the term “unit test” implies that you do. If you see a unit as a piece of code but that was not the intention of the phrase “unit test.” The word “unit” is referring to a unit of behavior. If the behavior that you’re testing does not change, your test doesn’t need to change either.

The purpose of doing TDD is to support us in refactoring our code but if we make up the rule that every unit of code has to have a test associated with it, then refactoring becomes nearly impossible. Suddenly, tests become a major burden instead of a support system. I sometimes refer to our unit test as a safety net that’s there to catch us if we make a mistake. It’s important that a safety net be attached to the ground so it’s stable but that doesn’t mean we want to entomb our safety net in concrete. Indeed, it would be very stable but the whole purpose of having a safety net would be defeated. The same thing is true with TDD.

Many developers buy into the notion of code quality and so they pay particular attention to the software they write to make sure it’s maintainable and easy to work with. But often they fail to see their tests as code as well. While their code is nice and clean, their tests can get awfully messy. If we’re going to do TDD correctly, we can’t treat our tests as second class citizens. Tests are code every bit as valuable as production code and should be treated with the same respect and with the same focus on quality.

If we reject TDD in particular, like some people are claiming we should, then we will be setting the software industry back at least twenty years. Nothing that we build in the world gives us so little feedback as the software development processes that most developers employ. We are dealing with something that we cannot touch or taste or smell and yet we are perfectly comfortable writing it out of our hands and then throwing it into production without any real verification. Because of the complex nature of software, where code is coupled and intertwined together, changing one line of code can affect an entire system’s behavior so the whole system often times needs to be retested even after minor changes are made.

Physical systems do not behave this way, I can knock out a support beam at my house and while the cieling may sag a little, the whole structure won’t come toppling down. Even bookkeepers use something called “double book entry accounting” where every credit has a corresponding debit to make the accounts balance. If the bookkeeper made an error entering a credit then that error will be picked up when they enter the corresponding debit. But there is no double book accounting for software development. Code comes from our heads, through our hands, and right into the computer.

This is not a very reliable approach, so having a way to triangulate or verify code as we write it is incredibly important, and that’s exactly what TDD does for us. In the future, if we aren’t using TDD as an industry then we’ll needsomething else that gives us the same benefit. We simply cannot progress as an industry without it.

要查看或添加评论,请登录

David Scott Bernstein的更多文章

  • Green Tests and Red Tests

    Green Tests and Red Tests

    In practice, I found that there are times that I want a bit more test coverage than I get from just doing test-first…

  • Radiators and Silos

    Radiators and Silos

    In the old days of corporate America, the way you got ahead was through hard work and perseverance. You strove to…

    1 条评论
  • Makers and Menders

    Makers and Menders

    I’ve been getting back into some research interests of mine that require data acquisition from a variety of sensors so…

  • Core Developer Practices

    Core Developer Practices

    Every field of engineering has a core set of practices that they follow and software engineering is no different. But…

    1 条评论
  • Still XP After All These Years

    Still XP After All These Years

    Are you humming in your head Paul Simon’s “Still Crazy After All These Years”? I am. And it does seem crazy.

  • The Importance of Continuous Integration

    The Importance of Continuous Integration

    Perhaps the most important yet easiest to implement of all the software development practices in Agile is continuous…

  • The Importance of Technical Practices (Again)

    The Importance of Technical Practices (Again)

    Software development has undergone many revolutions over the last few decades. The way we build software today is…

  • Summary of Seven Strategies Series

    Summary of Seven Strategies Series

    I finished my “Seven Strategies” series of 72 blog posts with seven strategies for implementing each of the nine…

    1 条评论
  • Refactor to Learn What Not to Do

    Refactor to Learn What Not to Do

    One of the things that I was not expecting when I started refactoring other people’s code was that I started to see…

    4 条评论
  • Refactor to Clean Up Before Moving On

    Refactor to Clean Up Before Moving On

    Of course, the best time to refactor code is while it’s fresh in your mind, right after having worked with it. Once I…

社区洞察

其他会员也浏览了