ナベアツを書いているときに14でアホになってしまうという現象が起きて、ちょっと悩みました。原因は
ret = IIf(((i mod 3) = 0) Or (Instr(CStr(i),”3″) > 0),ToAho(CStr(i)),CStr(i))
と書くべきところを
ret = IIf(((i mod 3) = 0) Or (Instr(ret,”3″) > 0),ToAho(CStr(i)),CStr(i))
と書いていたからです。これだと14がアホになる他、30番台のいくつかではアホにならないという障害になります。テストで気づいたからよかったのですが、仮に10までしかテストしていなかったら気付かなかった可能性があります。ヒヤリハットみたいなものなので、仮に10までしかテストしなくて障害を起こしてしまったとして(あるいはテストしたけど気づかなかったとして)、二度とこのような問題を起こさないように根本原因を解消しておきたいと思います。

根本原因を探る際に、なぜなぜ5回というのがありますが、なぜなぜを「なぜ発生させてしまったか(なぜそのような記述をしてしまったか)」と「なぜ流出してしまったのか(なぜテストで防げなかったのか)」という観点があるというのが面白かったので、そんな感じでやってみます。
一つの参考として:「なぜなぜ分析」手法 実践セミナー 「なぜなぜ分析」手法 実践セミナー(PDF)

なぜ発生させてしまったか
(1)Dimで初期化されると思い込んでいた
(2)思い込みのため初期化しなかった(現状もしていない!危険!)
(3)最初は「3の倍数のとき」という条件のみで記述して、後から「3のつく数字のとき」という条件を追加したが、その際当初のToAhoメソッドで使っていたInstr(ret,…という記述をコピペした
(4)CStr(i)は変数に入れてから使おうかと一瞬思ったが、まあこの程度はいいかと思った(現状もそうだ!)

なぜ流出してしまったか
(1)10までテストすれば十分だと思った
(2)14は3の倍数だと勘違いした
(3)OKボタンを連打して確認したので、期待値と異なる値になっていることを見逃した

発生させないための対策
(1)宣言の直後に必ず初期化する
(2)宣言と同時に初期化できないVB Scriptは使用しない
(3)宣言に対応する初期化があるかを機械的にチェックする
(4)関数の入れ子が複雑になるような場合は戻り値をいったん変数に入れてから引数として渡す
(5)前後関係等に依存する値は裸で使わずいったん変数に入れてから引数として渡す
(6)各ステップ毎に期待する動作になっていることを確認しながら記述する
(7)誤りの再利用を避けるためすぐに対策を取っておく

流出させないための対策
(1)どこまでテストすれば品質が保証されるかを、テスト仕様を決める際に論理的に導き出す
(2)原則として考えられる全パターンをテストする。例外的にリソース上の問題等で全パターンテストができないときは、論理的に絞り込みを行う
(3)テスト仕様を作成する際にはInとOutをデータとして準備する

こんなことを考えてみると、いろいろ感じることがあります。
・発生させないための対策の方がコストが小さそう
・もっとも、発生させないための対策(5)は言うほど簡単ではない
・発生させないための対策の方が適用範囲が広そう
・流出させないための対策の方が「ちゃんと対策をとりました」と言いやすそう
・対策の中には、発生対策の(2)のように、いろいろな理由で取りえないものもある
・「必ず」のような精神論的対策は実際は無意味(今回もさらすにあたって結構気は使っているのにこの有様)
・論理的絞り込みは結構難しそう(現在のロジックは2桁までの仕様ですが、では3桁に対応しようとした際にテスト範囲を論理的に決めうるかはなかなか難しいような気がする)。それよりも、徹底的な自動化で全パターンやってしまう方が良いような気がする。