Test-driven development (described on Wikipedia) is now widely accepted as the preferred way to develop software, especially Java software. I'm an enthusiastic supporter of this predilection - but there is a problem people seem often to overlook. I call it The Four Horsemen (also on Wikipedia) because there are four potentially major dynamic problems unreachable by testing alone.
The problems are:
- Race Conditions - instability due to concurrent threads changing shared data without sufficient protective locking
- Deadlock - freezing-up of concurrent threads that have a mutual dependency that cannot ever be satisfied
- Livelock - similar to deadlock, livelock is a condition in which concurrent threads waste time trying to acquire resources that cannot ever be satisfied due to the mutual dependency between the threads. Unlike deadlock, the CPU wastes endless effort trying to fulfil the unfulfilable.
- Starvation - because of unfair contention between concurrent threads, one (or more) particular threads can be put into a state where they are always being pre-empted by their peer threads. The starved threads never get to do anything useful.
All four problems are actually design mistakes, although it is really common for Java code that experiences this never to have had these issues considered. They are therefore quite likely to be unconscious design mistakes.
Some developers make the mistake of trying to prove that their code does not have these problems by means of unit and functional testing. This is an important misunderstanding - you cannot prove the absence of deadlock by testing alone, nor absence of the other three horsemen.
Quite simply, good testing is necessary but not enough. I shall discuss possible solutions in later postings.