TDDへの不満とその対応について考えてみた。

「Code Retreat in Sendai」に参加してきたのですが、その時に、TDDに対して感じた問題点とそれへの対応策について考えてみました。

2014/12/13(土)「Code Retreat in Sendai」に参加しました。 - toshimana's diary

※今回はGUIを持たないものを想定してます。GUIテスト自動化は、難しい。

TDDへの不満

「テストを同時に書くために処理が書きあがるまでの時間は増えるが、バグが少なくなるために総開発時間は短くなる」ことがTDDの主張と理解しています。
そのために、どうもアジャイル的ではないのではないか、と思うところがあります。

末端側からの実装を優先するため、変更に弱い

上記TDDの主張は、設計が適切に行われていることや、開発の途中で変更が起こらない場合に成り立つ、と感じています。
TDDはレッド・グリーン・リファクタリングのサイクルを回すため、小さいところ(末端側)から開発を始めがちです。
TDDで時間をかけたことにより末端側のソースコードが充実していることで、上流側の変更が、既に実装済みの末端側のコードを活用する方向に引っ張られること、また、それにより、不適切な設計になるのでは、と危険を感じます。
そのため、TDDはウォーターフォール開発に向いていて、アジャイル的ではない、と感じています。

TDDのテストは品質保証を目的としていない

TDDのテストは開発者のテストのためであり、品質保証のテストとは別物、というのがよく言われる話です。
開発者のテストが、そのまま品質保証のテストになりえないのは同意です。
しかし、品質保証のテストを使ってTDDをすればいいのではないか、と思っています。
(品質保証のテストと開発者のテストの違いを明確に理解できていないからの発言かもですけど。)

LazyTDD(仮)

TDDよりも上流側からシステムを作れるような工夫を検討してみました。
ここでは仮にLazyTDDとしたいと思います。
TDDが先行評価っぽいイメージを受けたので、Haskellの遅延評価っぽいTDDができないか、と考えてみました。
できる限り、品質保証に使えるテスト、壊れにくいテストの作成を作ることを優先し、品質保証に使えない、壊れやすいテストの作成を可能な限り抑制することを目的としています。

1.最も上流側のテスト(受け入れテストやシステムテストレベルのテスト)を書く。

実現したい機能の動作が確認できるレベルのテストを真っ先に用意します。

2.コードを書く。

必要な処理は可能な限り関数化する。関数はインターフェースのみの実装とする。
この時点では設計としてのコード実装の意味合いが強い。

3.作成した関数のコードを書く。

この際、必要であれば、その関数のためのテストを書く。
必要な場合として、例えば、

  • その関数をテストする際に、同じレベルに存在する関数との問題の切り分けが困難と感じたとき
  • 上流のテストでは、実行に時間がかかり過ぎるとき

テストを実装するときは、末端側のテストは上流のテストでカバーされる範囲でなければならない。
上流側に影響が表れないのなら、その機能(テスト)は不要だと考えている。

4.3で作成したテストをテストするときは、1のテストを一時的に無効化する。

3で書いたテストがグリーンになった時に、再度1のテストを有効化する。

5.1~4を繰り返す。

まとめ

TDDはプログラマが意図したものを作れる素晴らしい技術だと思います。
しかし、その分、プログラマが必要なもの、顧客が欲しいものに、プログラマが目を向け続けないと、異なる方向に進んでしまう技術とも思いました。
LazyTDD(仮)は私が適当に考えたものなので、同じような技術とかご存じの方がいらしたら教えてください。