¿ªÔÆÌåÓý

ctrl + shift + ? for shortcuts
© 2025 Groups.io

A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..


 

So I have being doing TDD for years now.

But I started noting I tend not to do it exactly "By The Book".

So as an exercise I tried going back to doing it...

* Very fine grained steps.
* Small change so Test fails - commit.
* Small change so Test passes - commit.
* Refactor so test passes - Commit.

As small as I could.

Oh, and just for the fun of it, I'm learning the D language, so I did it in D.

So here is the result, complete with a blow-by-blow Mercurial Repository of every step.



?Conclusions from the exercise.

  1. Very fine grained steps resulted in fewer bugs and fewer backtracks.
  2. Very fine grained steps resulted in better factored code.
  3. Watching others do the same exercise led me to the attitude "adding more test cases is Bad". (Slower, hard to maintain tests, more lines of code)
  4. Very fine grained steps slowed me down compared to my more usual somewhat loose style.
  5. Thoughtfully adding Provocative test cases in the order of "What I need to Handle Next" is Very Very Good.
  6. Replacing "Fine Grained Steps" with, whenever stuck, pull out a smaller? chunk and TDD that first (with Provocative test cases) works Very Very? Well.

Bottom Line?

In future I will be doing...
  1. Thoughtfully choosing a minimal number of provocative test cases in the order that challenges a single new behaviour, ie. A test case that requires a single additional behaviour in the code.
  2. I will take the largest steps I can where I can go from test fail to test pass in a single change.
  3. Whenever I misjudged and take too large a step, I will factor out a? smaller function and test and develop that first via the same process.
  4. Factoring out works best like this...
    1. Revert to last passing state, leaving failing test commented out.
    2. Copy pasta the code you wish to factor / enhance into a small function leaving original function untouched.
    3. Get tests for new function to pass.
    4. Wire new function into parent cleaning out original copy.
    5. Get tests to pass.
    6. Reenable commented out test... hopefully it passes now.


What do I mean by provocative test cases?

For example, when converting Roman numerals.


"I" is provocative.

"II" is provocative.

"III" is NOT provocative, it merely is extra Lines of Code (and hence a liability).

"IV" is provocative, but a bad choice for next test case as it adds two new behaviours at once.

"V" is provocative and adds a single new behaviour.

"IV" is now provocative and adds only a single new behaviour.

?

Conclusions about D.

?I love it.

?It is C / C++ with the worst stuff removed, and the best stuff stolen from it's competitors.

?If you are serious about industrial grade, high quality, defect free, efficient programming, you urgently need to be looking at D as your next language.

?Sigh! Unicode.

?That's not D's fault.

?D handles Unicode remarkably smoothly, but ye ancient 7bit ASCII is always going to be faster and conceptually easier than variable length code point UTF8.

?It took a bit of time and effort to get my head around D's template system (richer, safer, better than C++)

?It took even more time to get my head around Ranges, (again, richer, more flexible, safer than C++ iterators, more efficient than generators, coroutines or enumerators.)

?The choices D has made are rich in very powerful, very efficient implications.

Possibly the most striking is Compile Time Function Evaluation.

If it can be evaluated at compile time.... in D it will be.

And that is startling powerful.



--
John Carter
Phone : (64)(3) 358 6639
Tait Electronics? ? ? ? ? ? ? ? ?? ? ???
PO Box 1645 Christchurch
New Zealand



This email, including any attachments, is only for the intended recipient. It is subject to copyright, is confidential and may be the subject of legal or other privilege, none of which is waived or lost by reason of this transmission.
If you are not an intended recipient, you may not use, disseminate, distribute or reproduce such email, any attachments, or any part thereof. If you have received a message in error, please notify the sender immediately and erase all copies of the message and any attachments.
Unfortunately, we cannot warrant that the email has not been altered or corrupted during transmission nor can we guarantee that any email or any attachments are free from computer viruses or other conditions which may damage or interfere with recipient data, hardware or software. The recipient relies upon its own procedures and assumes all risk of use and of opening any attachments.


 

Pity I didn't see this blog post first....
??

Because then I would have defined "Provocative Test that adds one new Behaviour" as one that provoked one new behaviour in the precedence order suggested by Uncle Bob.


On Mon, Dec 30, 2013 at 9:40 AM, John Carter <john.carter@...> wrote:
So I have being doing TDD for years now.

But I started noting I tend not to do it exactly "By The Book".

So as an exercise I tried going back to doing it...

* Very fine grained steps.
* Small change so Test fails - commit.
* Small change so Test passes - commit.
* Refactor so test passes - Commit.

As small as I could.

Oh, and just for the fun of it, I'm learning the D language, so I did it in D.

So here is the result, complete with a blow-by-blow Mercurial Repository of every step.



?Conclusions from the exercise.

  1. Very fine grained steps resulted in fewer bugs and fewer backtracks.
  2. Very fine grained steps resulted in better factored code.
  3. Watching others do the same exercise led me to the attitude "adding more test cases is Bad". (Slower, hard to maintain tests, more lines of code)
  4. Very fine grained steps slowed me down compared to my more usual somewhat loose style.
  5. Thoughtfully adding Provocative test cases in the order of "What I need to Handle Next" is Very Very Good.
  6. Replacing "Fine Grained Steps" with, whenever stuck, pull out a smaller? chunk and TDD that first (with Provocative test cases) works Very Very? Well.

Bottom Line?

In future I will be doing...
  1. Thoughtfully choosing a minimal number of provocative test cases in the order that challenges a single new behaviour, ie. A test case that requires a single additional behaviour in the code.
  2. I will take the largest steps I can where I can go from test fail to test pass in a single change.
  3. Whenever I misjudged and take too large a step, I will factor out a? smaller function and test and develop that first via the same process.
  4. Factoring out works best like this...
    1. Revert to last passing state, leaving failing test commented out.
    2. Copy pasta the code you wish to factor / enhance into a small function leaving original function untouched.
    3. Get tests for new function to pass.
    4. Wire new function into parent cleaning out original copy.
    5. Get tests to pass.
    6. Reenable commented out test... hopefully it passes now.


What do I mean by provocative test cases?

For example, when converting Roman numerals.


"I" is provocative.

"II" is provocative.

"III" is NOT provocative, it merely is extra Lines of Code (and hence a liability).

"IV" is provocative, but a bad choice for next test case as it adds two new behaviours at once.

"V" is provocative and adds a single new behaviour.

"IV" is now provocative and adds only a single new behaviour.

?

Conclusions about D.

?I love it.

?It is C / C++ with the worst stuff removed, and the best stuff stolen from it's competitors.

?If you are serious about industrial grade, high quality, defect free, efficient programming, you urgently need to be looking at D as your next language.

?Sigh! Unicode.

?That's not D's fault.

?D handles Unicode remarkably smoothly, but ye ancient 7bit ASCII is always going to be faster and conceptually easier than variable length code point UTF8.

?It took a bit of time and effort to get my head around D's template system (richer, safer, better than C++)

?It took even more time to get my head around Ranges, (again, richer, more flexible, safer than C++ iterators, more efficient than generators, coroutines or enumerators.)

?The choices D has made are rich in very powerful, very efficient implications.

Possibly the most striking is Compile Time Function Evaluation.

If it can be evaluated at compile time.... in D it will be.

And that is startling powerful.



--
John Carter
Phone : (64)(3) 358 6639
Tait Electronics? ? ? ? ? ? ? ? ?? ? ???
PO Box 1645 Christchurch
New Zealand




--
John Carter
Phone : (64)(3) 358 6639
Tait Electronics? ? ? ? ? ? ? ? ?? ? ???
PO Box 1645 Christchurch
New Zealand



This email, including any attachments, is only for the intended recipient. It is subject to copyright, is confidential and may be the subject of legal or other privilege, none of which is waived or lost by reason of this transmission.
If you are not an intended recipient, you may not use, disseminate, distribute or reproduce such email, any attachments, or any part thereof. If you have received a message in error, please notify the sender immediately and erase all copies of the message and any attachments.
Unfortunately, we cannot warrant that the email has not been altered or corrupted during transmission nor can we guarantee that any email or any attachments are free from computer viruses or other conditions which may damage or interfere with recipient data, hardware or software. The recipient relies upon its own procedures and assumes all risk of use and of opening any attachments.