TDD、TDDと言うけれども。TDDのダークサイドについてそろそろ一言語ってみる。

id:t-wadaさんの話の中で、TDDが品質を保証するわけではない、という話があったんですが、それについて私見をつらつらと。ちなみに自分は2年くらい仕事でTDDをやってきました。
やってきた中で下記のTDDの利点を感じることができました。

その時に気づいた最もシンプルなコード、クリーンなコードができる

テストコードからコードを書く、と言うのはプロダクトコードの利用方法が考えられるのでとても有効に作用します。id:t-wadaさんもリファクタリングが一番重要と話されていましたが、テストコードがあれば安心してリファクタリングができます。

より高い品質のコードが書けるようになる

これはt-wadaさんの話の中でもありましたね。なぜかと言うと、プロダクトコードが実行される時の前提条件を知ろうとすると、結構いろいろなコードに目を通すことになります。コードに目を通すことで優れた先人の知恵を見つけることができます。また最近はテストコードを書くためのクラスを標準で用意しているフレームワークも多いですが、それでもセットアップは必要です。

実装の振る舞いのやり残しがなくなる

ペアプロも一緒にやると、4つの目でコードとテストケースを見るので、かなりやり残しが発生しません。(それでもやり残しが発生してしまうのが人間ってもんなんですが。)

と、いいことずくめに見えるTDDですが、

今日は暗黒面について少し触れたいと思います。

TDDで書いたプロダクトコードは、部分最適なコードになりやすい。

TDDでコードを書くときは、あえて全体の設計を行わないように語られますが、実はそれは過ちを招く事になります。どういうことかと言うと、一つずつ振る舞いを実装していくので、全体の構造がとても脆い実装になってしまうことが多いのです。そうです。アーキテクチャの骨格を疎かになってしまい、パフォーマンスがとても悪くなってしまう事が往々にして起こってしまうのです。
えぇ、そのテストケースに対応するプロダクトコード単体であれば全然問題ないでしょう。しかし、一つのソフトウェアの中で構成されるクラスは一つだけ、と言うわけではありません。いくつかのクラスが関連して、初めてソフトウェアになるはずです。
KentBeck氏は、もしそうなってしまった場合、TDDで組み上げていったアーキテクチャで問題となる部分をごそっと作り直すことで対応できると語っていらっしゃいます。しかしよっぽど勇気のあるプログラマでないと、「既存の実装があるのだから」と流れてしまうのではないでしょうか。僕等にはテストコードがある!とも言えますが、テストコードはあくまで対応するプロダクトコードの振る舞いを示します。プロダクトコードのクラス構造がガラリと変わったとき、テストコードをうまく追従させることは至難の技と言えます。それもTDDで行えますが、何もない所から積み上げていったものよりも、気にしなければならない点が多いです。一つ一つを相手に潰す、と言うことができなくなってしまいます。
プロダクトコードを書くときに、最初から最適化されたコードを書くのは悪である、と語られる事が多いです。これはTDDの話ではないですが、あらかじめコードを書く時点で分かりそうな事は、最初に入れておくことは悪ではないはずです。何事もバランスが肝心です。
不要になったテストケースは捨てる。予想外なREDになったときは、実はそのテストケースの仕様も変えるべきだったとか。TDDで書かれたテストケースは、クリーンなコードを残すためのリファクタリングのための外殻というだけなのかもしれません。