XDD — what drives your development? Part I: TDD

Intractables
3 min readMar 2, 2019

This is the beginning of a series of posts along the theme of X-driven-development.

Have you heard of Pain-Driven Development or Destruction-Driven Development or Outage-Driven Development?

Keep on reading these series, and you will! :)

But first, as a prelude, we start with TDD, the now largely non-controversial, accepted concept of Test-Driven Development, and why it’s not nearly enough.

The notion of systematic testing of software predates the term “Test-Driven Development”, but TDD makes testing a primary driver of the development process, hence the name.

In short, test-driven development requires the developer to first write a test before implementing a new feature; run the test and see it fail, since the feature is not implemented yet; implement the feature and see the test pass;

Letting the test fail at first is a crucial step, as it gives some assurance that the test’s failure will correctly signal feature’s failure. Another crucial aspect is to keep refactoring the code as developer’s understanding of requirements emerges in the process of testing and coding. This supposedly allows good design to be interactively discovered in response to requirements, reducing the need for upfront design effort, increasing both the responsiveness and the velocity of the development process.

Test-driven Development:

  • A radical departure from the (now quaint) notion that someone other than the developer (e.g., a tester, a QA engineer, etc) is responsible for testing developer’s code.
  • A staple of the Agile Development methodologies, re-discovered and popularized by Kent Beck, Martin Fowler, Robert C. Martin.
  • A key enabler of high-velocity development with tight, short delivery cycles.
  • Taken sometimes way too far, but more often, not nearly far enough, especially in legacy enterprise environments.
  • At scale, a non-trivial practice, requiring acquisition of skill, adjustment of process/tooling and, a cultural shift in engineering.

Using the technical debt metaphor, adopting a practical TDD approach can be compared to paying off your high-interest revolving debt as the first step to financial health: the codebase will be drowning in technical debt until a robust code testing practice is adopted by every developer, who assumes the responsibility of writing high-coverage tests for all the code they write.

The good consequences of TDD:

  • Coding for testability shapes design and implementation in (mostly) beneficial ways.
  • Tests serve as a safety net going forward.
  • Enables (relatively) worry-free refactoring.

The pitfalls and anti-patterns to look out for:

  • Premature overgeneralization: when taken too far, unnecessary complexity may result from superfluous or trivial testing.
  • Self-delusion and false sense of security — due to lack of coverage or false coverage, e.g. tests testing mocks and fixtures rather than actual implementations.
  • Brittleness in the testing codebase, that itself becomes a burden.
  • Unbalanced test pyramid.

Finally, let’s note that TDD originated in the era dominated by shrink-wrapped software: where a project, once “shipped” (usually physically shipped on hard media like CD-ROMs), would be operated by the customer and not touched by the original developers, remaining unchanged (in fact, unchangeable) and mostly running on a single machine.

But the dominant kind of software these days is operated and usually continuously developed and deployed to huge clusters of machines — think GMail, Uber, Amazon, etc. As a result, software merely passing tests in testing environments doesn’t tell us whether the production environment is healthy. And the production environment, with all its complexities, is what truly matters.

Ultimately, while some form of TDD is absolutely indispensable to create and maintain any large modern codebase, it is not nearly enough to ensure that “prod” (the production environment) stays continuously healthy.

Tending to “prod” health was my obsession for the past seven years, and a key ingredient that emerged early on was the Monitoring-Driven Development.

Stay tuned!

--

--