Re: Test-Driven Development
From: Phlip (phlip_cpp_at_yahoo.com)
Date: 02/29/04
- Next message: Pirate Wannabe: "Re: GetAsyncKeyState problem, Help Please."
- Previous message: MSCHAEF.COM: "Re: Sound and mixing channels question"
- In reply to: Michael Mendelsohn: "Re: Test-Driven Development"
- Next in thread: James Rogers: "Re: Test-Driven Development"
- Reply: James Rogers: "Re: Test-Driven Development"
- Reply: Michael Mendelsohn: "Re: Test-Driven Development"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 28 Feb 2004 22:04:55 EST
Michael Mendelsohn wrote:
> I think the "roman numeral" example was badly chosen, because that is a
> task that is clearly specified up front. It also doesn't take too long
> to implement.
The question "what order do we write the tests" matters.
There are good things about TDD that the "roman numeral" example illustrates
poorly. But for test order, the example is brilliant (and I wish I thought
of it).
Given a hard task, solve the simplest condition within it. To write a
language, make it print("Hello World") first. Solve for several simple
cases, then merge the solutions to solve the general case.
This is how mathematicians write advanced proofs, such as proofs on geometry
that generalize to any number of dimensions. They solve a specific proof for
2D, then a proof for 3D, then for 4D. This gives them enough experience, and
proofs, to merge duplication into a single generic proof for ND.
(Leaving only the ND proof in the textbooks, to show off, is why so many
math books make such light pleasant relaxing reading material.)
The "roman numeral" example illustrates this effect so clearly because
counting schemes are canonic examples of sequences from simple to complex
cases: I, II, III, IV, V. The number's value indicates its position in the
rank of tests, from simplest to hardest.
(To be ridiculously accurate, one could have gone I, V, II, III, IV, but the
benefit would only be slight.)
Now suppose I wrote romanToInt(), then wrote a test that iterated from 1 to
100, and wrote a super-stupid roman() that returned IIIIII for 6, etc. The
assertion would be romanToInt(roman(q)) == q.
Then suppose I added to that test a new assertion; no character may appear
more than 3 times.
This would be an example of adding the tests in the wrong order. The single
new assertion, because it challenges intermediately wrong complex test
cases, would break everything.
Putting tests in order from simple to complex allows one to aggressively
simplify the intermediately simple (and wrong) versions of the function, to
seek the best abstraction.
> If you have to code to badly specified requirements that are subject to
> change, the tests tell you (and anybody else) what requirements you've
> coded to. Also, I can take an hour to think about an algorithm; if
> you've got your boss breathing down your neck, showing progress in terms
> of running code (and tests passed) can be important (another effect of a
> bad programming environment that TDD helps alleviate, the first being
> performance measured by lines of code).
>
> Many real-life programming tasks don't require you to come up with
> sophisticated algorithms; they require you to make choices, and TDD
> documents them and keeps them consistent (one hopes).
TDD sucks. It sucks extra as an algorithm generator. If someone invented a
general-purpose algorithm generator, they could become a trillionaire. But
TDD is worse than BDUF at algorithm generation. Programming lifecycles
should not be sensitive to initial conditions. No matter how many
butterflies flap their dumb wings, we won't get no hurricane.
I had to start my example 3 times. Each time I started, I solved the "II"
case differently. The first two times (using "I"*q, or recursing on the
wrong side), the algorithm went straight down a rat hole and stayed there.
No amount of refactoring could dig it out. The very first flap of that
butterfly's wings, 2 out of 3 times, instantly triggered humongous
hurricanes.
Programs are only simple algorithms - iteration, recursion, etc. - and
programs should encapsulate all hard algorithms behind simple interfaces,
such as std::sort<>.
So because refactoring simple algorithms is so easy that refactoring
browsers can automate it, TDD is an adequate system to rapidly search a
design space for a best-fit, and to create robust code with a low defect
count as a side-effect.
--
Phlip
http://www.xpsd.org/cgi-bin/wiki?TestFirstUserInterfaces
-- impositive == negative
anegative == positive --
- Next message: Pirate Wannabe: "Re: GetAsyncKeyState problem, Help Please."
- Previous message: MSCHAEF.COM: "Re: Sound and mixing channels question"
- In reply to: Michael Mendelsohn: "Re: Test-Driven Development"
- Next in thread: James Rogers: "Re: Test-Driven Development"
- Reply: James Rogers: "Re: Test-Driven Development"
- Reply: Michael Mendelsohn: "Re: Test-Driven Development"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]