TDD再考 (2) – 何故、ほとんどのユニットテストは無駄なのか?

TDD is dead」の最後で紹介されている、TDD否定派として有名な James O Coplien氏の論文。なかなか読み応えがある。

ユニットテストには基本的に価値がないので、よりビジネス価値を反映する粒度の大きなテスト(functional tests, integration tests, system testsなど)に軸足を移すべきである、というのがこの論文の論旨。

何故ユニットテストに価値が無いのかという部分の説明についてはなかなか説得力がある。論点を挙げてみると、

  • TDDの実践者が言及するテストカバレッジ100%には意味が無い
  • バグを取り除く最大の機会はテスト以外のところにある
  • ユニットテストにビジネス価値はほとんどない
  • TDDはプログラムデザインに害を及ぼす
  • ユニットテストの維持コストは馬鹿にならない
  • テストがコードのクオリティを上げる訳ではない、上げるのは開発者自身である

一つ一つの論点を追いかけてみよう。

テストカバレッジ100%には意味が無い

Coplien氏によれば、一般に言われるカバレッジ100%というのは、計算理論の見地から言えばまったくのナンセンスであり、本当の意味で100%を目指すのならば、到達可能なパスの全パターンと、その時にアクセス可能なデータの全パターン、それら全部の組み合わせを検証しなければならないとのこと。そうでなければ、正式にそのプログラムが「正しい」とは言えないのだそうだ。

TDDのメリットとしては、もちろんプログラムの信頼性向上も謳われる事が多いが、いわゆる品質保証としてのテストとは区別される事がほとんどで、TDDとしてのフォーカスはプログラムデザインに当てられる事が多いように思う。なので、この批判はTDDに対する攻撃としてはそれほど有効ではないように思える。

一方、ユニットテストを品質保証の根拠として捉える向きには、計算理論的にコードの正しさを証明する事は非現実的であり、ほとんどのケースでは恣意的な基準によって判定されていることを明らかにした、ということになるだろうか。しかし、果たして未だにそのような勢力(ユニットテストを品質保証の根拠として捉える向き)が存在するんだろうか…?

それとは別にして、プログラマの仕事をメトリクスで計ろうとする事の落とし穴については注意深く考えた方がよいだろう。筆者自身も過去のプロジェクトで、テストプログラムを書いた経験のないプログラマが、カバレッジを基準値まで上げるために、ただプログラムを実行するだけで Assertion が全くないようなテストプログラムを書いているのを目撃した事がある。

バグを取り除く最大の機会はテスト以外のところにある

これはウォーターフォール時代から言われていた事だが、プログラムの品質にもっとも重大な影響を及ぼすのは、要求・ドメインの分析結果を設計に落とし込むタイミングである。

その前提の上で、ユニットテストという高コストな手法でバグを潰すのは、果たして費用対効果的にどうなんだろうかという話である。

TDDも設計手法ではあるが、Coplien氏は他の論点でも述べているように、TDDはプログラムデザインに害を及ぼすと主張している。なので、プログラムの信頼性を向上させる手法として、TDDに従来の設計手法以上の価値があるとは認めていない。「コードのクオリティ向上に寄与するのはテストではなく、結局のところそれは開発者自身である」というのが、彼の基本的な立場である。

ユニットテストにビジネス価値はほとんどない

おそらくこれが一番重要な論点だと思われる。Coplien氏によれば、ビジネス要件から導出されたテストだけがビジネス価値を持つ。ほとんどのユニットテストは、ビジネス価値とはあまり関係のない開発者の独断によって設計されている。

もちろんユニットテストにビジネス価値と直結する部分が全くないとは言い切れない。例えば、キーとなるアルゴリズムを実装している部分などだ。しかし、基本的にビジネス価値はより粒度の高いテストで表現すべきである、というのがCoplien氏の主張である。

ユニットテストの価値を計る方法として、もしそのテストが失敗したら、どのようなビジネス価値を毀損することになるかを考える。もし、よく分からない、あるいは明確でない場合、そのテストのビジネス価値はほとんどゼロだということになる。価値が無いのにも関わらず、そのテストを維持管理するのにはコストがかかる。であれば、そのようなテストは捨てた方が得策である。

TDDはプログラムデザインに害を及ぼす

これはDHH氏も指摘していたが、TDDがプログラムデザインを改善するという客観的な根拠や事例はなく、それを調査した研究によればむしろ逆の結果が出ているようだ。

TDDが及ぼす悪影響として、プログラムを過剰に細分化してしまうため、ドメインとプログラムで表現の粒度が釣り合わなくなり、プログラムが理解しづらくなる事、ユニットレベルでのビジネス価値が小さくなってしまうこと、などが挙げられている。

しかし、仮にCoplien氏が言うように「テストがコードのクオリティを上げる訳ではない、上げるのは開発者自身である」のであれば、TDDがデザインに与える影響を客観的に計る事自体が無理筋であるように感じられるのだが、どうだろうか。

ユニットテストの維持コストは馬鹿にならない

この問題はTDD支持者の中でも多くの人が認識するところだと思う。

テストコードもプロダクトコードと同様(あるいはそれ以上に)、デザインとメンテナンスにコストがかかる。

特にテストコードの設計においては、プロダクトコードとは異なる方法論を採用する必要があり、これが想像以上に難しい。ただテストコードがあるというだけで良しとしているプロジェクトも多いが、テストの品質がプロジェクトに与える影響は想像以上に大きい。

プロダクトコードの設計を改善するためには、より良いテストの設計手法を学習しなければならないが、そのためには前提としてプロダクトコードの設計手法に精通する必要がある。プロダクトコードの設計手法に精通しているのなら、何故設計手法としてのTDDにわざわざ手を出さなければならないのかという矛盾がある。

プロダクトコードの coupling(結合度)とcohesion(凝集度)を改善するために、テストを書くというのがTDDであるが、テストコードがプロダクトコードに強く依存してしまう(高結合度)という問題がある。プロダクトコードに大きな修正が入った場合の、テストコードに及ぼす影響は甚大であり、粒度が小さく数の多いユニットテストのメンテナンスコストは想像以上に大きくなる。

テストがコードのクオリティを上げる訳ではない、上げるのは開発者自身である

ユニットテスト・TDD批判のベースにある考え方であり、これはある種の正論として多くの人が賛成出来る部分では無いだろうか。

Dave Thomas氏の「Agile Is Dead」宣言にも見られるように、いわゆる銀の弾丸的な存在としてアジャイルやTDDがあるように喧伝されるために、このような違和感を表明しておきたいというのは多分にあるのではないかと思う。

Coplien氏は、件の記事の締めくくりに、コンピュータ資源が豊富になって何でも簡単に試したりやり直したり出来るようになると、自分の頭で考えなくなってしまう(ツールのアウトプットを盲信してしまう)とう話をしている。

参考資料

James O Coplien氏のTDD批判については、氏に直接話を聞いたという安井力氏のブログとFacebook上のやり取りが大変に興味深かった:

TDD再考 (3) – TDDが解決しようとした問題は何か?

“TDD再考 (2) – 何故、ほとんどのユニットテストは無駄なのか?” への2件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中