On Test-Driven Development

Within Agile circles, TDD is thought to be one of the techniques promoted by XP that is only for developers

This is something I have been practicing for years now, and I still have to master

It occured to me recently, during a session on fractal TDD I gave at Agile Tour Beirut with Craig Morrisson, that there is actually more to it than simpy a technique for developers

This is also tied to what Freeman and Pryce says in their GOOS book

And I think this was what Kent Beck had in mind when he invented it, explicitly or implicitly, except that using the word Test was unfortunate as it lead other people to think it was somehow connected to the actual activity of testing

TDD is the heart of Agile and from it you can derive all other practices that, along the years have become part of the norm of what can be considered agile software development

When infected by this desire to be able to express in an executable form the purpose of what I shall be developing, other practices become obvious. Given TDD and the need for feedback:

Fractal TDD is just a compact and efficient way to say that TDD has most value when practiced at all level and all stages of your development process: Each and every artifact produced and designed must be backed with some "test" which expresses the purpose of this artifact and provides the ability to consistently, continuously, rigorously and reliably validate the produced artifact is actually the right one

On another perspective, just as Curry-Howard expresses the isomorphism that exists between types and programs on one side, and predicates and proofs on the other side ; TDD expresses this same relationship logic has w.r.t. tests and software.

A test is a predicate that should be asserted by the software

And the fact that not all proofs (actually the vast majority of proofs) cannot be machine-checked does not invalidate the whole proving process behind mathematics ; just like the fact that not all tests can be automated does not impact their general usefulness

Relationship between code and test then goes on 3 levels:

There are probably more levels on the road to enlightment but those are known unknowns

At an even higher-level, TDD is simply a rephrasing of classical scientific method: Make an hypothesis, Design an experiment, Validate or invalidate the hypothesis with the experiment, repeat until exhausted (till you die...) ; but in the context not of producing knowledge but to change the world

This is the same mechanism that's at the heart of Lean: The pull system[^1] makes all parts of the system dependents on initial pull by customers/end-users

Feature Injection is another high-level form of TDD: The whole development process is driven by the requested outputs of the system which trigger examples that are turned into tests then code.

Impact Mapping, story mapping, goal tables are other instances of the same class. Starting from a high-level measurable business goal, derives intermediate goals, prioritize them, then use this to drive development building use cases

Lean Startup is yet another form of scientific process, where one design experiments to find a business model.

What are the consequences? For me, it is the acknowledgment that never should I start working on some code without a clear understanding of the goal in the form of an assertable statement of purpose, a procedure which can tell whether or not the goal has been reached, that is a test.

Of course this test can takes many forms:

It must have the standard expected characteristics:

Reframing this in a more mathematical setting, a test (both the statement and the procedure to verify it) must be:

A single test is usually not enough, it is just the start of a process so we usually end up with more tests. These tests can be viewed as an executable specification of the built system in so far as we accept the fact they are a mere sampling of the possible input/output space of this system, so we expect our set of tests to exhibit another property: Accurate Sampling.

This sampling is expected to provide an accurate image of the specification, so accurate actually that it should be possible to read the tests as if they were the actual specification of the system

A genuine executable specification would be a thing used in formal methods to prove properties of the system, or even derive the system from a formal definition (eg. as in B or Z)

TDD allows developers (and testers) to build such test suites while designing the system when there does not exist a specification of the system.

TDD at level 2 is one programming technique, not the programming technique. When a specification already exists, eg. when no learning is expected to take place, it is not useful.

TDD at level 2 can be mixed with other techniques for different parts of the software. For example, one could start writing code following a given specification, provide a skeletal system providing minimal service and writing tests after code to expose this specification, then test-drive the design and development of some components to be included in the system.

If we say Level 2 TDD is one programming technique among others, what are these other techniques? In particular, what other techniques provide the same kind of guarantees than TDD provide?

[^1]: Saying that pull system is at the heart of Lean is somewhat controversial, I guess. Some would say that kaizen, the continuous quest for perfection is actually at the heart of Lean.

[^2]: Beyond some basic level of understanding of the context. If we are stating some property of a piece of software then some assumptions can be omitted in the test, like the fact the software must be run...