212: Canon TDD - by Kent Beck
The late 1990s , Extreme Programming brought us a concept called "Test First Programming". In 2002, Kent Beck released a book called "Test Driven Development by Example". In December of 2023, Kent wrote an article called "Canon TDD". With Kent's permission, I am going to read that article in this episode. I'm gonna save my commentary for a follow-up episode.
Brian:Now here's Canon TDD by Kent Beck.
Brian:Number 1. Write a list of test scenarios you wanna cover.
Brian:Number 2. Turn exactly one item on the list into an actual concrete runnable test.
Brian:Number 3. Change the code to make the test and all previous tests pass, adding items to the list as you discover them.
Brian:Number 4, optionally refactor to improve the implementation design.
Brian:Number 5, Until the list is empty, go back to number 2. In my recent round of test room development clarifications, one surprising experience is
Brian:that folks out there don't agree on the definition of TDD.
Brian:I made it as clear as possible in my book. I thought it was clear. Nope. My bad. If you're doing something different than the following workflow and it works for you, congratulations.
Brian:It's not Canon TDD, but who cares? There's no gold star for following these steps exactly. If you plan on critiquing TDD and you're not critiquing the following workflow, then you're critiquing a straw man. That's my point in spending some of the precious remaining seconds of my life writing this for stalling straw man. I'm not telling you how to program.
Brian:I'm not charging for gold stars. I try to be positive and constructive as a habit. By necessity, this post is going to be concise and negative. People get this wrong. Here's the actual thing.
Brian:I don't mean to critique someone's workflow, but sharpen their understanding of Canon TDD. Overview. Test driven development is a programming workflow. A programmer needs to change the behavior of a system, which may be empty just now. TDD is intended to help the programmer create a new state of the system where everything that used to work still works.
Brian:The new behavior works as expected. The system is ready for the next change. The programmer and their colleagues feel confident in the the above points. Interface implementation split. The first misunderstanding is that folks seem to lump all design together.
Brian:There are 2 flavors, how a particular piece of behavior is invoked, how the system implements that behavior. When I was in school, we called these logical and physical design and were told never to mix the 2, but nobody ever explained how. I had to figure that out later. The steps. People are lousy computers.
Brian:What follows looks like a computer program, but it's not. It's written this way to attempt to communicate effectively with people who are used to working with programs. I say attempt because as noted, folks seem prone to saying, TDD sucks dude. I did something else entirely and it failed. Number 1, test list.
Brian:The initial step in TDD given a system and desired change in behavior is to list all the expected variance in the new behavior. There's the basic case and then if this service times out and what if the key isn't in the database yet and etcetera? This is analysis, but behavioral analysis. You're thinking of all the different cases in which a behavior change should work. If you think of ways the behavior change shouldn't break existing behavior, throw that in there too.
Brian:Mistake. Mixing in implementation designs decisions. Chill. There will be plenty of time to decide how the internals will look later. You'll do a better job of listing tests if that's all you concentrate on.
Brian:If you need an implementation sketch in Sharpie on a napkin, go ahead, but you might not really need it. Experiment. Folks seem to have missed this step in the book. TDD just launches into coding. You never know when you're done.
Brian:Nope. Number 2, write a test. One test, a really truly automated test with setup and invocation and assertions. Pro tip. Trying working backwards from the assertions sometime.
Brian:It's in the writing of this test that you'll begin making design decisions, but they are primarily interface decisions. Some implementation decisions may leak through, but you'll get better at avoiding this over time. Mistake. Writing tests without assertions just to get code coverage. Mistake.
Brian:Convert all the items on the test list into concrete tests, then make them pass 1 at a time. What happens when making the first test pass causes you to reconsider a decision that affects all of those speculative tests? Rework. What happens when you get to test number 6 and you haven't seen anything pass yet? Depression and or boredom.
Brian:Picking the next test is an important skill and one that only comes with experience. The order of the test can significantly infect both the experience of programming and the final result. Open question, is code sensitive to initial conditions? Number 3. Make it pass.
Brian:Now that you have a failing test, change the system so the test passes. Mistake. Delete assertions so the test pretends to pass. No. Make it pass for real.
Brian:Mistake. Copying actual computed values and pasting them into the expected values of the test. That defeats double checking, which creates much of the validation value of TDD. Mistake. Mixing refactoring into making the test pass, again, with the wearing 2 hats problem, make it run, then make it right.
Brian:Your brain will eventually thank you. If in the process of going red to green, you discover you need a new test added to the test list. If the test invalidates the work you've done already, oh, no, There's no way to handle the case of an empty folder. You need to decide whether to push on or start over. Pro tip, start over but pick a different order to implement the tests.
Brian:When the test passes, mark it off the list. Number 4, optionally refactor. Now you get to make implementation design decisions. Mistake, Refactoring further than necessary for this session. It feels good to tidy stuff up.
Brian:It can feel scary to face the next test, especially if it's one you don't know how to get to pass. I'm stuck on this on a side project right now. Mistake. Abstracting too soon. Duplication is a hint, not a command.
Brian:Number 5. Until the list is empty, go to 2. Keep testing and coding until your fear for the behavior of the code has been transmuted into boredom.
Brian:A link to this article by Kent will be included in the show notes.