前回取り上げた、TDDが解決しようとした問題の一覧を眺めていると、それらの問題は Dave Thomas氏が言うところのアジャイルの価値とも共通する部分が多く、TDDというのはアジャイル手法全体のメタファーとなるような、言わばミニアジャイルのような存在と言っても差し支えないように思える。
間違っているかもしれないが、アジャイル以前から長くプログラムを生業としていた人ほど、テストファーストという考え方に抵抗感を抱くのではないだろうか?
TDD、あるいはアジャイルという考え方は、外部からの要件(「機能」)が、結果として、その機能を実現するために必要な「構造」を生み出す、という考え方である。これは、この命題だけに注目する限りは当たり前の事実のようにも思える。しかし、プログラマは、経験を積み重ねる内に同じような構造のパターンに何度も遭遇することになる。そうやって頭の中に有用なコンセプトが蓄積されて行く。それらがイディオムとかデザインパターンなどと呼ばれたりする訳だが、TDDの問題意識は、それらのコンセプトの適用範囲は思ったほど広くなく、そして耐用年数は思ったよりも短く、濫用すれば過剰性能を作り込む罠に落ちるというものであった。
しかし、人間はどうしても知識を貯えてしまうので、解法を先に考えてしまうというバイアスから逃げるのは至難の業である。そしてこれが、経験者ほどテストファーストに抵抗感を抱くのではないかという、推測の根拠である。
要件が構造を生み出す、というロジックはとても反論しづらい。何のためにソフトウェアを作るのかということを考えれば、それが至極当然の流れのように思える。ミニアジャイルであるTDDがプログラマの間でドグマ化してしまうのも頷ける気がする。
では、経験者のバイアスが存在しない初心者のプログラマにとって、TDDは自然な手法になり得るのだろうか?
TDD以前では、プログラムデザインのフォーカスはやはりプロダクトコード側にあって、より良いモジュール、あるいはより良いオブジェクトのデザインは何かということについて、様々なデザイン原則やパターンなどを学習し、デザインの質を高める事によって、プロダクトの保守性や信頼性を担保するという方法が一般的であった。
TDDの出現によって、プログラミングのフォーカスは、プロダクトコードからテストコードに移動する。テストをしやすいようにプロダクトコードをデザインすると、結果的に、モジュール間の疎結合を実現でき、自然によいデザインへと導かれるというわけだ。テストコードを検証すれば要件との齟齬をチェックでき、テスト自体を実行してプロダクトコードの正しさも確認出来るという、まさに一石二鳥・三鳥の方法であった。
実際に筆者も以前、初心者はTDDのやり方から学べば、自然にプログラムデザインも学べるし、管理者視点からは要件との齟齬もチェックしやすく、なかなか良いアプローチではないかと考えていた時期もあった。
しかし、実際には様々な障害があることが分かった。例えば、テスト駆動で小さなステップを踏むことの難しさである。
think of a test that will force you to add the next few lines of production code. This is the hardest part of TDD because the concept of tests driving your code seems backwards, and because it can be difficult to think in small increments. (James Shore: The Art of Agile Development: Test-Driven Development)
TDDでは、API視点からプログラムをデザインすると言っても、実際はインクリメンタルに開発するために、どういうテストを書けばプロダクトコードの変更を最小限に出来るかというアクロバティックなことを考えなければならない。これは、TDDに限らず、vertical slice単位で開発するアジャイルの難しさの中心的な課題といってもよく、とても初心者が太刀打ち出来る問題とは思えない。
もう一つ例を挙げると、James O Coplien氏の指摘にも通じるが、自動テストが(現実的に)カバー出来る範囲というのは思ったより広くない、ということである。
これはつい最近、たまチームで遭遇したばかりの出来事だが、テスト(外部)からは期待通り動作しているように見えるのだが、実はプラスアルファの余計なことをやっていて、関係ないデータを壮大に破壊していたという事例があった。原因は、ライブラリのAPIについての理解が足りなかったという、ごく初歩的な問題である。こういった問題を考えると、テストプログラムで担保出来る信頼性など、特に初心者を対象とした場合、取るに足らないことが分かる。まさに、Coplien氏が言うところの「テストがコードのクオリティを上げる訳ではない、上げるのは開発者自身である」。