Friday, July 18, 2008

Test-driven Development

Test-driven development (TDD) is commonly understood to connote the simultaneous construction of a test-suite with the system-under-test. This is "developer testing": the programmer writes unit-test classes in the same sitting as the classes being tested. Less commonly, a test is written before the class or method it's meant to test: in this case the test acts as the 'first client' of the tested code, helping the developer to explore the 'problem space'. This is test-driven design and I see such tests as analogous to the scaffolding which festoons buildings under construction, except of course they aren't thrown away when the construction is complete.

So far, so good and plenty of smart people have thought longer and harder than me on this topic. In the rest of this post I'd like to describe a unique (in my experience) application of TDD in which it worked out better than I'd imagined.

In an earlier existence I worked at an start-up which specialised (in those days) in building implementations of JSR-82, better known (if that's the mot juste, which I doubt) as the "Java APIs for Bluetooth Wireless Technology" (or JABWT possibly the Java world's first five-letter acronym and unpronounceable to boot). This was fairly exciting stuff: we were members of the expert group working on embedded Java on cool hardware... and we had a tab at the coffee shop around the corner!

In those days, Bluetooth hardware was expensive and one of the company's offerings was a simulator which allowed users to experiment with the APIs without having to buy any. Better still this simulator provided an implementation of the APIs which ran on standard Java so no messing around with on-device testing. In true TDD fashion, a spin-off from these simulated JABWT APIs was a comprehensive testsuite. This was very useful because JABWT is a deceptively complex specification: although it comprises only 21 classes and interfaces, a working implementation (i.e., one which passes the TCK) can easily run to a hundred concrete classes.

Back then, the Linux Bluetooth stack was in its infancy, there was a kernel implementation of the L2CAP protocol and a couple of user-space daemons to manage device hot-plugging (hcid) and service discovery (sdpd). The code for the latter had been donated to the community by Nokia but was no longer supported by them.

You're miles ahead of me.

What we did next was a skunk-works implementation of JSR-82 over this embryonic stack. How we did this was entirely test-driven: we would run our comprehensive testsuite over our implementation, see which tests failed and only implement enough to make the tests pass. Since this was a guerrilla activity, the latest test-reports always gave us a point at which to resume the implementation, when we found time from our 'real jobs'. Serendipitously our test-suite also indirectly tested a large part of the underlying Linux infrastructure and allowed us to feed bugfixes and missing features back into the community, and I ended up as the maintainer of the SDP subsystem for a year or so. A further benefit (this time to the company itself) was that it became much easier to build and test subsequent implementations of JABWT: since one half of the testsuite was typically run on Linux and the other on the embedded implementation, we could use Linux's low-level packet inspection (hcidump) to see what the other side was trying to do. Serendipity, financial benefit and bonus karma points all round.

No comments: