Preface

Test-driven development is a way of managing fear during programming.

Kent Beck

We are so ineffably lucky! We’ve had test-driven development for years.

Several decades have passed since the developers who wrote the code for the Mercury Space Program practiced Punch Card TDD (test-driven development). XUnit libraries that facilitate the adoption of test-driven development date back to the turn of the century. In fact, Kent Beck, who wrote Test-Driven Development: By Example (Addison-Wesley Professional, 2002) and developed the JUnit framework, refers to himself as having “rediscovered” (and not invented) the practice of TDD. That statement is evidence of his humility, yet it is also the truth. TDD is as old as software development itself.

Then why is it that test-driven development is still far from the standard way to write code? Why is it often the first practice that gets sacrificed when there is schedule pressure, or when IT budgets need to be trimmed, or (my personal favorite) when there is a desire to “increase the velocity of the software-delivery team”? All these reasons are proffered despite the ready availability of empirical and experimental evidence that TDD reduces defect count, creates simpler design, and improves developers’ confidence in their own code.

Why is TDD adopted grudgingly and abandoned readily? The following arguments, heard often from those who are reluctant to practice it, may explain why:

I don’t know where and how to start.

Perhaps the most common reason is lack of awareness and exposure. Like any other skill, writing code in a test-driven style is something that needs to be learned. Many developers either haven’t had the external inducement (time, resources, guidance, encouragement) or internal motivation (overcoming one’s own reluctance and fear) to learn this skill.

TDD works in toy programs or during coding interviews, but not when writing “real-world” code.

This is untrue yet understandable. Most test-driven development tutorials and books—including this one—are constrained to pick relatively simple examples from an obvious domain. It’s difficult to write a TDD article or book with actual code from a piece of software plucked from a commercially deployed application (say, from a financial institution, a healthcare management system, or a self-driving automobile). For one thing, much of such real-world code is proprietary and is not open source. For another, it’s the job of the author to show code from a domain that has the widest appeal to the largest audience. It would be illogical, bordering on obscurantism, to show TDD in the context of a highly specialized domain. Doing so would require, before anything else, a lengthy explanation of the arcane jargon and cant of that domain. That would defeat the very purpose of the author: making TDD understandable, approachable, even lovable.

These obstacles to using real-world code in TDD literature notwithstanding, developers regularly write production software using test-driven development. Perhaps the best and most convincing example is the suite of unit tests for the JUnit framework itself. The Linux Kernel—possibly the most strenuously used piece of software in the world—is being improved with unit tests.

Writing tests after the fact is sufficient; TDD is too restrictive and/or pedantic.

This is more refreshing to hear than the occasional rant that “unit testing is overrated”! Writing tests after writing production code is an improvement over writing no tests at all. Anything that raises the developers’ confidence in their code, reduces accidental complexity, and provides authentic documentation is a good thing. However, writing unit tests before writing the production code provides a forcing function against creating arbitrary complexity.

TDD guides us to simpler design because it provides these two practical rules as guardrails:

  1. Only write production code to fix a failing test.

  2. Refactor energetically when, and only when, tests are green.

Does test-driven development guarantee that all the code we ever write will automatically and inevitably be the simplest code that works? No, it does not. No practice, rule, book, or manifesto can do that. It’s up to the people who bring these practices to life to ensure that simplicity is achieved and retained.

This book’s content explains and instructs how test-driven development works in three different programming languages. Its purpose is to instill in developers the habit and self-belief to use TDD as a regular practice. That purpose may be ambitious, but I’m hopeful it isn’t elusive.

What Is Test-Driven Development?

Test-driven development is a technique for designing and structuring code that encourages simplicity and increases one’s confidence in code, even as its size increases.

Let’s take a look at the various parts of this definition.

A Technique

Test-driven development is a technique. It’s true that this technique is borne of a set of beliefs about code, namely:

  • That simplicity—the art of maximizing the amount of work not done, is essential1

  • That obviousness and clarity are more virtuous than cleverness

  • That writing uncluttered code is a key component of being successful

Despite being rooted in these beliefs, as a practical matter, TDD is a technique. Like riding a bike, kneading dough, or solving differential equations, it’s a skill that no one is born with and that everyone has to learn.

Other than this section, this book does not dwell on the belief system behind test-driven development. It’s assumed that you either subscribe to it already or that you’re willing to give TDD a try as a new (or forgotten) skill.

The mechanics of that technique—writing a failing unit test first, then briskly writing just enough code to make it pass, and then taking the time to clean up—occupy the bulk of this book. There will be ample opportunity to try this technique for yourself.

In the final analysis, it is more satisfying to learn a skill and imbue oneself with the beliefs that support it—just like riding a bike is more enjoyable if you remind yourself that it’s good for your health and the environment!

Designing and Structuring Code

Notice that TDD is not fundamentally about testing code. It is true that we use unit tests to drive the code, but the purpose of TDD is to improve the design and structure of the code.

This focus is vital. If TDD were only about testing, we couldn’t really mount an effective case for writing tests before rather than after the business code is written. It’s the goal of designing better software that spurs us on; the tests are simply a vehicle for this progress. The unit tests that we end up with via TDD are an added bonus; the primary benefit is the simplicity of design we get.

How do we achieve this simplicity? It is through the mechanism of red-green-refactor, which is described in detail at the beginning of Chapter 1.

A Bias Toward Simplicity

Simplicity isn’t a mere esoteric notion. In software, we can measure it. Fewer lines of code per feature, lower cyclomatic complexity, fewer side effects, smaller runtime or memory requirements—any subset of these (or other) requirements can be taken as an objective measure of simplicity.

Test-driven development, by forcing us to craft “the simplest thing that works” (i.e., that which gets all tests to pass), constantly nudges us toward these metrics of simplicity. We aren’t allowed to add superfluous code “in case we need it” or because “we can see it coming.” We must first write a failing test to justify writing such code. The act of writing the test first acts as a forcing function—compelling us to deal with arbitrary complexity early. If the feature we’re about to develop is ill-defined, or our understanding of it flawed, we’ll find it hard to write a good test up front. This will force us to address these issues before we write a line of production code. This is the virtue of TDD: by exercising the discipline of driving our code through tests, we weed out arbitrary complexity at every juncture.

This virtue isn’t mystical: using test-driven development won’t cut your development time, the lines of code, or defect count by half. What it will allow you to do is to arrest the temptation to introduce artificial and contrived complexity. The resultant code—driven by the discipline of writing failing tests first—will emerge as the most straightforward way to gets the job done, i.e., the simplest code that meets the needs of the tests.

Increased Confidence

Code should inspire confidence, especially code we have authored ourselves. This confidence, while itself a nebulous feeling, is grounded in an expectation of predictability. We are confident in things whose behavior we can presage. If the corner coffee shop undercharges me one day and overcharges me by the same amount the next day, I’m likely to lose confidence in the staff even though I break even over the two days. It’s human nature that we value regularity and predictability even more than net value. The world’s luckiest gambler, who may have just won 10 times in a row at a roulette table, wouldn’t say that they “trust” or have “confidence” in the wheel. Our affinity for predictability survives even dumb luck.

Test-driven development increases our confidence in our code because each new test flexes the system in new and previously untested ways—literally! Over time, the suite of tests we create guards us against regression failures.

This steadily increasing battery of tests is the reason that as the size of the code grows, so does its quality and our confidence in it.

Who Is This Book For?

This is a book for developers—people who write software.

There are many professional titles that go with this vocation: “software engineer,” “application architect,” “devops engineer,” “test automation engineer,” “programmer,” “hacker,” “code whisperer,” and countless others. Titles may be impressive or humble, trendy or solemn, traditional or modern. However, the one thing that’s held in common by the people professing these titles is this: they spend at least a part of their week—if not each day—in front of a computer, reading and/or writing source code.

I have chosen the term developers to represent this community of which I’m both a humble and grateful member.

Writing code is one of the most liberating and egalitarian activities one may imagine. In theory, all one needs by way of physical prowess is the possession of a brain. Age, gender, sex, nationality, national origin—none of these should be a barrier. Having physical disabilities shouldn’t be a barrier.

However, it would be naive to assume that reality is as neat or fair as that. Access to computing resources isn’t equitable. A certain level of wealth, freedom from want, and security are necessary. Access is thwarted even further by badly written software, badly designed hardware, and myriad other usability limitations that prevent all people from learning to program based solely on their interest and effort.

I have tried to make this book accessible to as many people as possible. In particular, I’ve tried to make it approachable to people with physical disabilities. The images have alt-text to facilitate e-reading. The code is available via GitHub. And the prose is straightforward.

In terms of experience, this book is intended both for people who are still learning how to program and for those who already know how to program. If you are ramping up on one (or more) of the three languages in this book, you are well within the target audience.

However, this book does not teach the basics of programming in any language, including Go, JavaScript, or Python. The ability to read and write code in at least one of the programming languages is a requirement. If you are absolutely new to programming, it’d be wise to solidify the foundations of writing code in one of the three languages before you proceed with this book.

The sweet spot for this book spans developers who are beyond their early forays into programming, all the way to seasoned architects, as shown in Figure P-1. (Kent Beck is an outlier.)

This book is for developers who are early in their careers, are in mid-career, or are seasoned developers. Even industry experts can find valuable insights in this book. However, people who are learning how to program may find the examples difficult to follow. And Kent Beck is an outlier!
Figure P-1. This is a book for software developers

Writing code can be, by turns, exhilarating and exasperating. However, even at its most frustrating, there should always be more than a glimmer of optimism and a bushel of confidence that we can make code do our bidding. With perseverance, you’ll find that your journey through this book is fruitful and that the joy of writing code in a test-driven manner is one you want to savor long after you’re done reading Chapter 14.

What Are the Prerequisites for Reading This Book?

By way of equipment and technical prowess, you should:

  • Have access to a computer with internet connectivity.

  • Be able to install and delete software on that computer. That is, your access on that computer should not be restricted; in most cases this would require having “Administrator” or “Superuser” access on that computer.

  • Be able to launch and use a shell program, a web browser, a text editor, and optionally an integrated development environment (IDE) on that computer.

  • Have installed (or be able to install) the runtime tools for one of the languages used in this book.

  • Be able to write and run a simple program—“Hello World”—in one of the languages used in this book.

“Setting Up Your Development Environment” in Chapter 0 has more installation details.

How to Read This Book

The subject matter of this book is “how to do test-driven development in Go, JavaScript, and Python.” While the concepts discussed are applicable to all three languages, the treatment of each language necessitates some separation of the material in each chapter. The best way to learn test-driven development (like any other acquired skill) is through practice. I encourage you to both read the text and write the code on your own. I call this style “following the book”—because it includes active reading and active coding.

Tip

To get the most out of this book, write the code for the Money example in all three languages.

Most of the chapters have general-purpose sections that are applicable to all three languages. These are followed by language-specific sections, where the code for one of the three languages is described and developed. These language-specific sections are always clearly marked by their headings: Go, JavaScript, or Python. At the end of each chapter is one or two sections that summarize what we have accomplished thus far and what comes next.

Chapters 5 through 7 are unique insofar as they each deal exclusively with one of the three languages: Go, JavaScript, and Python, respectively.

Figure P-2 shows a flowchart describing the layout of this book and the different ways to follow it.

This book can be read sequentially from chapter 0 to chapter 14. Be aware that chapter 5 is exclusively about Go, chapter 6 is about JavaScript, and chapter 7 is about Python. If you're following this book one or two languages at a time, you may need to read these chapters out of order.
Figure P-2. Flowchart on how to read this book

Here are some “reading pathways” for how to best follow this book.

Follow the Book One Language at a Time

I recommend this pathway if one or more of these conditions apply to you:

  1. I am aching to dive into one of these languages before tackling the other two.

  2. I’m particularly curious (or skeptical!) about how TDD works in one of the three languages.

  3. I learn best by working in one language at a time, rather than multiple languages simultaneously.

Follow the flowchart shown in Figure P-2 one line at a time. For example, if you are eager to learn TDD in Go first, skip the sections marked JavaScript and Python in the first reading. Then do a second pass through the book for JavaScript, and a third to finish things off in Python. Or you may do the languages in a different order. The second and third pass should be quicker than the first; however, be prepared for the unique quirks of each language!

If you follow the book this way, you will find that writing the code successively in each language gives you greater insight into TDD as a principle—beyond the details of testing as a language feature. Getting into the habit of writing tests is necessary; however, understanding the reasons for why test-driven development works across languages is even more important.

Follow the Book in Two Languages First and Then in the Third Language

I recommend this pathway if you identify with any of the following statements:

  1. I want to build and compare the solutions to the same problem in two languages.

  2. I am less comfortable with one of the languages and want to tackle it after the other two.

  3. I can code in two languages at a time but would find it difficult to juggle all three at once.

Follow the flowchart shown in Figure P-2 two lines at a time. After you’re done with following the Money problem for two languages, do a second pass through the book to follow the third language.

It can happen that you want to follow two languages in the first pass, yet cannot decide which language to defer to a second reading. Here are some suggestions on how to pick two out of the three languages:

  1. Do you want to contrast a dynamically typed language with a statically typed one and keep the language tech stack simple? Follow Go and Python first, and JavaScript next.

  2. Are you ready to learn contrasting ways to build code in two different languages and ready to tackle tech stack variations? Follow Go and JavaScript first, and Python later.

  3. Do you want to compare and contrast two dynamically typed languages? Follow JavaScript and Python first, and Go next.

If you read the book this way, you’ll quickly discover the similarities and differences of doing TDD in multiple languages. While the syntactical and design variations in the languages create obvious differences, you may be surprised by how deeply the discipline of TDD permeates into how you write code, regardless of the language in which you write code.

Follow the Book in All Three Languages Simultaneously

I recommend this pathway if any of these statements apply to you:

  1. You want to gain the best value by learning the contrasts and similarities of the three languages.

  2. You find it easier to read a book from start to finish instead of doing multiple passes through it.

  3. You have some experience in all three languages but haven’t practiced TDD in any of them.

If you can write code in three languages simultaneously without getting overwhelmed, I recommend this pathway.

Regardless of the pathway you choose, be mindful that when you’re writing code, you will likely face challenges that have to do with your specific development environment. While the code in this book has been tested for correctness (and its continuous integration build is green), that does not mean it will work on your computer at first go. (On the contrary, I can almost guarantee that you will find interestingly steep portions on the learning curve.) One of the key benefits of TDD is that you control the speed at which you proceed. When you get stuck, slow down. If you make progress in smaller increments, it is easier to find where the code went astray. Writing software means dealing with errant dependencies, unreliable network connections, quirky tools, and the thousand natural shocks that code is heir to. Slow down when you feel overwhelmed: make your changes smaller and discrete. Remember: TDD is a way of managing the fear of writing code!

Conventions Used in This Book

There are two categories of conventions used in this book that require explanation: typographical and contextual.

Typographical Conventions

The prose in this book is in the font-type used in this sentence. It is meant to be read and not entered verbatim as code. When there are words used in prose that are also used in code—such as class, interface, or Exception—a fixed-width font is used. This alerts you that the term is or will be used—spelled exactly the same way—in code.

Longer segments of code are separated into their own blocks, as shown below.

package main

import "fmt"

...1

func main() {
    fmt.Println("hello world")
}
1

Ellipses mean irrelevant code or output has been omitted.

Everything in a code block is either something you type in verbatim or something the program produces as the literal output, with two exceptions.

  1. Within code blocks, ellipses (...) are used to indicate either omitted code or omitted output. In both cases, whatever is omitted is irrelevant to the current topic. You should not type these ellipses in code or expect to see them in the output. An example is shown in the code block above.

  2. Within code blocks that show output, there can be ephemeral values—memory addresses, timestamps, elapsed time, line numbers, autogenerated filenames, etc.—that will almost certainly be different for you. When reading such output, you may safely ignore the specific ephemeral values, such as the memory addresses in the following block:

AssertionError: <money.Money object at 0x10417b2e0> !=
                <money.Money object at 0x10417b400>
Tip

Tips are suggestions that can be helpful to you while you write code. They are separated from the main text for easy reference.

Important

Important information that is vital to the topic is identified like this. Often there are hyperlinks or footnotes to resources that provide more information on the subject.

In most chapters, there is extended development and discussion of code in each of the three languages. (The exceptions are Chapters 5, 6, and 7, which deal exclusively with Go, JavaScript, and Python respectively.) To separate the discussion of each language, a heading and an icon in the margin indicate the language that’s the exclusive purview of that section. Keep your eyes peeled for these three headings and icons:

  • Go Go

  • JavaScript JavaScript

  • Python Python

Lexical Conventions

This book discusses core software concepts and backs up those discussions with code in three different languages. The languages are sufficiently different in their individual terminology so as to present challenges when discussing common concepts.

For example, Go does not have classes or class-based inheritance. JavaScript’s type system has prototype-based objects—which means that everything is really an object, including things typically thought of as classes. Python, as used in this book, has the more “traditional” class-based objects.2 A sentence like “We will create a new class named Money" isn’t merely confusing, but is downright incorrect when interpreted in the context of Go.

To reduce the potential for confusion, I’ve adopted the general terminology shown in Table P-1 to refer to key concepts.

Table P-1. General terminology used in this book
Term Meaning Equivalent in Go Equivalent in JavaScript Equivalent in Python

Entity

A singular, independently meaningful domain concept; a key noun

Struct type

Class

Class

Object

An instance of an Entity; a reified noun

Struct instance

Object

Object

Sequence

A sequential list of Objects of dynamic length

Slice

Array

Array

Hashmap

A set of (key-value) pairs, where both keys and values can be arbitrary Objects and no two keys can be the same

Map

Map

Dictionary

Function

A set of operations with a given name; Functions may (or may not) have entities with both inputs and outputs, but they’re not associated directly with any one Entity

Function

Function

Function

Method

A Function that is associated with an Entity. A method is said to be “called on” an instance of that Entity (i.e., an Object)

Method

Method

Method

Signal an error

Mechanism by which a Function or Method indicates failure

Error return value (conventionally, the last return value of a function/method)

Throw an exception

Raise an exception

The goal is to use terms that explain the concepts without favoring one programming language’s terminology over others. After all, the biggest takeaway from this book ought to be that test-driven development is a discipline that can be practiced in any programming language.

In sections of the book that deal with one of the three languages (which are clearly marked in the heading), the text uses language-specific terms. For example, in a Go section, there will be instructions to “define a new struct named Money.” The context makes it clear that this instruction is specific to a particular language.

Using Code Examples

The source code for this book is available at https://github.com/saleem/tdd-book-code.

If you have a technical question or a problem using the code examples, please send an email to .

This book is here to help you learn and practice the art of test-driven development. In general, you may use any code provided in this book in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.

We appreciate, but generally do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Learning Test-Driven Development by Saleem Siddiqui (O’Reilly). Copyright 2022 Saleem Siddiqui, 978-1-098-10647-8.”

If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at .

How to Contact Us

We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/learningTDDbook.

Email to comment or ask technical questions about this book.

For news and information about our books and courses, visit http://oreilly.com.

TDD—The Whys

Critiques of TDD—and by implication, this book—can come in various forms. Some of them are creatively humorous, such as the refreshing cartoon by Jim Kersey shown in Figure P-3.

Comic strip with two robotic characters. Character A is wondering how TDD applies to building a bridge. Character B says that step one is to write a failing test, which in this case amounts to driving your car over the cliff! Character A doesn't want to be on the bridge-building project anymore. Character B says: we can discuss that later; take these keys!
Figure P-3. TDD humor: don’t cross a bridge you haven’t built yet! (Source: https://robotkersey.com)

Less facetiously, it’s natural to have questions about the content and structure of the book. What follows are answers to a few such questions.

Why Does This Book Use Go, JavaScript, and Python?

This book uses Go, JavaScript, and Python as the three languages with which to demonstrate the practice of test-driven development. It’s a fair question: why these three languages?

Here are some reasons.

1. Variety

The three languages in this book represent a diversity of design options, as shown in Table P-2.

Table P-2. Comparison of Go, JavaScript, and Python
Feature Go JavaScript Python

Object-oriented

“Yes and no”

Yes (as an ES.next compliant language)

Yes

Static vs. Dynamic types

Statically typed

Dynamically typed

Dynamically typed

Explicit vs. Implicit types

Mostly explicit, variable types can be implicit

Implicitly typed

Implicitly typed

Automatic type coercion

No type coercion

Partial type coercion (for Boolean, Number, String, Object). No coercion for arbitrary class types

Some implicit type coercion (e.g., 0 and "" are falsey)

Exception mechanism

By convention, second return type of methods is error, caller must explicitly check if this is nil or not

The keyword throw is used to signal an Exception and try ... catch is used to respond to it

The keyword raise is used to signal an Exception and try ... except is used to respond to it

Generics

Not yet!

Not needed due to dynamic typing

Not needed due to dynamic typing

Testing support

Part of language (i.e., the testing package and the go test command); libraries available (e.g., stretchr/testify)

Not part of language, many libraries available (e.g., Jasmine, Mocha, Jest)

Part of language (i.e., the unittest library); libraries available (e.g., PyTest)

2. Popularity

Python, JavaScript, and Go are the top three new languages that developers want to learn, as found in several annual surveys by Stack Overflow in 2017, 2018, 2019, and 2020. Figure P-4 shows the result of the 2020 survey.

In the 2020 Stack Overflow survey, 30% of developers wanted to learn Python, 18.5% wanted to learn JavaScript, and 17.9% wanted to learn Go. This applies to developers not yet programming in that specific language.
Figure P-4. Most desirable new languages to learn, as noted in a survey of developers by Stack Overflow

In the 2021 Stack Overflow survey, TypeScript climbs into second place, relegating JavaScript and Go to third and fourth places, respectively. Python retains its top spot.

Syntactically, TypeScript is a strict superset of JavaScript. Therefore, it could be argued that every developer wishing to learn TypeScript has to know JavaScript. I harbor the hope that TypeScript developers will also find this book valuable.

3. A personal reason

Over the last five years or so, I had the opportunity to work on several projects where the tech stack featured one of these three as the primary programming language. While working with other developers I found that, in general, their eagerness to learn and practice TDD was evenly matched by their inability to find resources (or muster the discipline) to do so. They wanted to practice TDD, but didn’t know how or couldn’t find the time for it. Tellingly, this was as true for seasoned developers as it was for “noobs.”

I hope this book serves as both a practical guide and a source of inspiration to those who want to learn and practice TDD in any language—not just in Go, JavaScript, or Python.

Why Not This Other Language?

For starters, there is a vast number of programming languages. One could conceivably write half a dozen books like this and still cover only a small fraction of the languages that developers over the world use on a daily basis to write code for academic, business, and recreation purposes.3

Besides, there is an excellent book already available for test-driven development in Java. Kent Beck’s seminal work is what inspired me, as it did countless other developers, to fall in love with the art and science of TDD. It also begot the “money problem” that’s a major theme in this book.

I am sure there are many other languages for which a practical TDD guide would be beneficial. How about R? Or SQL? Or even COBOL?

Let me assure you: the reference to COBOL was neither a straw man argument nor a cheap shot. In the mid 2000s, I worked on a project where I demonstrated the ability to do TDD in COBOL using COBOLUnit. It was the most fun I’ve had in a language that’s more than a decade older than I am!

I’m hoping that you will pick up the mantle. That you will learn, teach, and espouse the skills and discipline necessary to practice test-driven development in other languages. That you will write a blog, an open source project, or the next book in this series.

Why Does This Book Have a “Chapter 0”?

The vast majority of programming languages use 0-based indexing for arrays and other countable sequences.4 This is certainly true for the three programming languages that form the basis of this book. In one sense, this book honors the rich history of programming culture by numbering the chapters starting at 0.

I also want to pay homage to the number zero itself, which is a radical idea. Charles Seife has written a whole book on this lonely number. In tracing the history of zero, Seife notes the reservations that the Greeks had about a number that represents nothing:

In that [i.e., the Greek] universe there is no such thing as nothing. There is no zero. Because of this, the West could not accept zero for nearly two millennia. The consequences were dire. Zero’s absence would stunt the growth of mathematics, stifle innovation in science, and, incidentally, make a mess of the calendar. Before they could accept zero, philosophers in the West would have to destroy their universe.

Charles Seife, Zero: The Biography of a Dangerous Idea

At the risk of getting too sublime: test-driven development occupies a similar place in programming culture today as zero did in Western philosophy a few millennia ago. There is a resistance to adopting it, born of a strange combination of dismissiveness, unease, and a belief that it’s just too much fussiness about nothing. “Why should I be fastidious about writing tests first—I already know how I’m going to code the feature!” “Test-driven development is pedantic: it only works in theory and never in practice.” “Writing tests after you’re done writing production code is at least as effective as, if not more than, writing tests first.” These and other objections to TDD make it resemble the number zero in how radical it is!

The practice of a book having a Chapter 0 isn’t entirely radical, anyway. Carol Schumacher has written an entire book titled Chapter Zero: Fundamental Notions of Abstract Mathematics, which is a standard textbook for advanced mathematics in many college-level curricula. No prizes for guessing what numbered chapter that book begins with!

Dr. Schumacher, in the Instructor’s Manual for her book, says something that I have found illuminating:

Your task as a writer is to give the right cues to your readers, cues that will make it as easy as possible for them to understand what you are trying to say.

Carol Schumacher, Instructor’s Resource Manual for use with Chapter Zero

I have taken this advice to heart. Pragmatically, a title containing “0” helps to set Chapter 0 apart from the treatise that follows it. Chapter 1 of this book puts us on a TDD journey which carries on through the next dozen chapters. Chapter 0 is about describing what that journey is, what we need to know and have before we embark on it, and what to expect when we are on it.

With the clarifications out of the way, let’s move right on to Chapter 0!

1 This definition of simplicity is enshrined in one of the 12 principles of the Agile Manifesto.

2 Python is very fluid in its support for object-oriented programming (OOP). For example, see prototype.py, which implements prototype-based objects in Python.

3 Although one book about TDD on a certain language is unlikely to get approval from publishers. Its name starts with “Brain” and ends with an expletive!

4 Lua is a notable exception. My friend Kent Spillner once gave a fascinating talk on this subject, which I summarized here.

Get Learning Test-Driven Development now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.