My Opinions on “Test Driven Development: By Example” by Kent Beck

I’m trying to get into TDD, and to this end I’m halfway through reading this book: http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530

I’m not sure I agree with *all* the principles in it though.

Beck proposes a roughly three-step method:

  1. Write a test.
  2. Write whatever it takes in the least amount of time to get the stuff to compile and run successfully (a.k.a “get to a green bar as quickly as possible”).  This apparently can include hard-coding values (gulp).
  3. Refactor to fix up your deliberately dodgy code “remove duplication”.

I understand the concept of test-first, but as a singularly scatterbrained individual, I can’t bring myself to go with “fake it ’till you make it” and “speed is more important than correct code (but only for a short while)”.  How will I remember/find those horrible bits of hard-coded code and ensure I’ve made them correct?  I think the trick to this (though it’s not said in as many words) is to write more tests that test the code from different angles until you get tests that fail with those hard-coded values, and fix them.  As a beginner of TDD, I don’t think I can be sure I’d do this effectively.  Essentially it is suggested that I write bugs into my code deliberately.  Eeeek!

What’s the point of a successfully run unit test if you know it’s testing broken code?  If you write any old code that will get the test working, you’ve totally negated the reason for the test in the first place.

Unit Test + Correct Code should equal Green Bar

Unit Test + Incorrect Code should equal Red Bar

not

Unit Test + Broken Code = Green Bar

I want tests that fail unless the code is correct.  While this isn’t always easy, I can’t bring myself to deliberately write incorrect code just to get a sucessful test.  If I have a green bar, what’s left to tell me what I need to do next?  As I said, apparently you just write more tests.

I prefer a different method:

  1. Write a test.
  2. Write the code that makes the test work.
  3. Refactor if I change my mind about that code, safe in the knowledge that as long as the test passes, the code is okay.

To his credit, Beck does suggest in his book that the whole idea is that you gradually learn how big your changes in-between running tests should be.  That it is a learning process.  When you know what you need to make a given test pass, you are allowed to write that “Obvious Implementation”.

I’m basically not sure I like the recommendation that the process be quite so iterative.  If you have to run your tests after each tiny change, you’re effectively introducing a compilation tax which will quickly get frustrating.

I’d love you hear how you’ve interpreted Beck’s advice for your own TDD process.  I’m sure I’m just missing the point, so enlightenment is always welcome :).

Advertisements

4 thoughts on “My Opinions on “Test Driven Development: By Example” by Kent Beck

  1. There is a great TDD example in the “Agile Principles, Patterns and Practices in C#” book from Uncle Bob – (http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258)

    The scenario (pair programming a bowling game) pretty much follows your concerns with writing “bad code” up front, and shows how to reduce it. The key is continually writing tests as you code, so that your tests are fractionally leading the code, rather than writing a load of tests first. Write a test (or a few, but exercise self-restraint), with the code being tested failing. Then make the test go green. As you need to add finer granularity to your code, write the tests first.

    It’s a difficult concept to get across sometimes, but I can totally recommend the above book as required reading as it does a great job of explaining the thought processes involved.

  2. I think you are indeed missing the point.

    The ultimate goal is clean code and solid regression tests. TDD like Beck proposes gives you both of these things. Writing code one small test at a time and then refactoring prevents you from overarchitecting your code. See the Go example at http://gojko.net/2009/02/27/thought-provoking-tdd-exercise-at-the-software-craftsmanship-conference/ .

    Waiting to write code until you have a test ensures that the tests will cover everything your code is doing. If you don’t want to test broken code, you have to have enough tests that it’s impossible to pass the tests and still have broken code. If you just write a test and then write the “correct” code to pass it, how will you KNOW it’s correct?

    The worst (simplest) code that you can write and still pass your test shows you exactly what your test is testing. If you can pass your test by returning a hard-coded value, then the test is useless as a regression test. Someone could replace your method with “return 4” and you would never know any better because the test would still pass. Writing the simplest code to make the test pass ensures that you get good tests out of the deal. The point is to write enough good tests that you can’t pass the tests without solving the problem. This is how the tests drive the development.

    As long as hard-coded and hacked solutions work, your test suite is incomplete, and any time you write code without tests, you may be overarchitecting your solution.

    I should note that I don’t do hardcore TDD like this all the time. For one thing, it takes a lot longer. If the program is small or relatively unimportant, the 80/20 rule applies. Doing TDD may get you from 80% to 100%, but it will take a lot of work, especially if you need to test things that are harder to test.

  3. If you’ve got a fast test framework and well factored code, then the complication & speed tax is pretty minor. Kent’s descriptions seem silly to the extreme. A practiced TDD artison doesn’t nessecarily go to such a micro-detail as described in the book. However, I suspect you might be surprised how close they are to that silly extreme. If you venture too far, it’s very easy to miss critical tests.

    Spend a day writing some greenfield code at the silly extreme. After you get into the groove, it won’t seem so silly and you’ll have a new tool to add to your inventory. Keep in mind that if writing tests is slow and awkward, your code may have some smells.

  4. I know this is old but I found it in recently – I find the major point that people trip over is _what_ code you should write to get the test to pass. The _simplest_ possible code may indeed be entirely useless but the argument for doing this is _may_ not be. Assuming it is useless is _may_ be a form of early optimisation, but it might also be a complete waste of time. It also stops you writing code ‘for the next step’ which might be dramatically different by the time you get to it.

    For me personally, yeah, I see some benefits of returning the scalar 1 for the fibonacci sequence – would I always do that as a rule in ‘real’ code – no, I don’t think so. Would I restrict myself to writing the smallest amount of _reasonable_ production code – yeah. If writing ‘1’ frees me up to move onto the next test then yes, I might do it, but its value is no longer production code, more as a ‘I can’t think of all this now, this gets helps me move further’ guide.

    This is where ‘engaging brain’ comes in.

    I also think ‘hammock driven TDD’ is where it is at :-).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s