Monday, July 31, 2023

TDDbE: Preface

Opening paragraph: the goal of Test Driven Development is "clean code that works" - which is a bit of sloganeering describing the stop condition.  TDD is a way to apply our effort to achieve the stop condition.

First promise: the long bug trail after "done" goes away.  Certainly a lot of the faults in complicated logic should have been identified and eliminated, because we will be making sure to design our systems so that testing the complicated logic is cost effective (i.e. relentlessly reducing the coupling between complicated logic and modules that are difficult or expensive to test).  Depending on how much of your system is complex logic, that could be the bulk of your problem right there.

It gives you a chance to learn all of the lessons that the code has to teach you.
This one, I'll need to chew on.  You've got structured time to focus attention, but there's an opportunity cost associated with each of these lessons.

  • Write new code only if an automated test has failed
  • Eliminate duplication

These are two simple rules....

Eliminate duplication being a rule is kind of important, in so far as it pulls one of the pillars of the four rules of simple design into a definition of TDD.  Sandro Mancuso has suggested that the four rules of simple design are separate from TDD, and while I'm receptive to the idea that they should be, the rule listed here means it isn't quite so easy.

A lot of lip service was paid to the "only if" rule early on.  Michael Feathers introduced Humble Dialog before TDDbE was published, and we already had people using test doubles as an isolation mechanism.  I think you can interpret that a lot of different ways - either the rule isn't so absolute, or the rule is absolute but the TDD process isn't sensible for all coding problems.

Running code providing feedback between decisions

This is a riddle I've been thinking on lately: the obvious feedback we get between decisions is red/green bar, announcing whether the values measured in our experiments match the described specifications.  But the feedback for the design decisions - running the code doesn't give us very much there.  Feedback for design decisions must come from somewhere else.

Refactor - Eliminate all of the duplication created in merely getting the test to work.

This is a big one: in my experience, most to nearly all practitioners move on from the refactor phase while duplication is still present.  Back in the day, Beck had a reputation for being something of a wizard in spotting duplication that wasn't obvious and immediately taking steps to eliminate it.

Next, lots of emphasis on implications of reduced defect density.  Just something to notice, possibly in contrast to his earlier writings about test first being primarily an analysis and design technique.

I'm noticing in passing that he isn't making any attempt here to clarify whether he is talking about reduced defect density because defects are being discovered and removed, or reduced defect density because fewer defects are being introduced.

TDD is an awareness of the gap between decision and feedback during programming, and techniques to control that gap.

 One of my two favorite quotations from the book.

Some software engineers learn TDD and then revert to their earlier practices, reserving TDD for special occasions when ordinary programming isn't making progress.

Huh.  If this sentence is written in 2009 - fine, there's been lots of time for people to try it, learn it, and decide it's a sometimes useful tool in the kit.  On the other hand, if that sentence goes back to the earliest drafts, then it becomes a very interesting statement about some of the early adopters.

There certainly are programming tasks that can't be driven solely by tests.  Security software and concurrency, for example, are two topics where TDD is insufficient to mechanically demonstrate that the goals of the software have been met.

 Horses for courses.

Before teeing off on the examples as being too simple

Well, I certainly do do that often enough - mostly because the starting position (money as model code) already elides a bunch of interesting decisions about module boundaries.  And weren't we promising that the tests would "drive" those decisions?


No comments:

Post a Comment