TDDって何をしたいんだっけ?

TDDの自殺 #kyon_mmAdventを読んで、TDDについて考えなおしたいと思ったので思うままに書いてみます。

正直、私はTDDについては必須ではないと考えています。
もう1年以上前に書いたエントリーですが、アジャイルにTDDしようとしてペアプロして失敗した話というのがありまして、なんとなくTDD+αをやったけれども失敗したというプロジェクトを見てきました。

ちなみにこのエントリー自体はいくつかのプロジェクトのことをまとめて書いているのでなんとなく読んでて不整合な箇所はあります。

さて、TDDって何をしたいんだっけ?という問に関しては個人的には以下の3つだと思っています。

  1. 設計-作り始める前にテストを書くことで、INとOUTを明確にする
  2. 単体テスト-不安をテストとすることでプログラマが意図したとおりに動くことを保証する
  3. 回帰テスト-テストコードが結果として回帰テストとなる

こんな感じです。

それぞれどうなんだろうってちょっと見ていきます。

設計-INとOUTを明確にするって誰でもやってるよね?

上に書いた一文が全てなのですけれども、初心者ならともかく、ある程度プログラミングに慣れた人であればINとOUTを定義するなんて誰でもやっていることだと思っています。
それこそCOBOLの時代、古い見積方法にファンクションポイント法というのがある程度に自明なお話。
TDDである必用があるのかといわれると甚だ疑問です。

単体テスト-不安に思うことってそんなにある?

初心者ならともかく、プログラミングに慣れれば慣れるほどコードが意図したとおりに動かないという不安は消えていくと思っています。それを毎回テストコードを書いてというのはあまりにも面倒くさいです。コードが動くかどうか不安に思うところって慣れれば慣れるほど少なくなっていくのかなと。例えば、

"Hello World!".startWith("H") == true;

というコードがあって、初心者であれば意図したとおりに動くかどうか不安に思うかもしれないけれども、少なくとも私は不安には思いません。プログラマーが不安に思ったところを動くように確認するという意味では、多分コードを書いた後にテストを改めて書けばいいのではないかなと。少なくとも全てに対してテストコードを書くという必要性は感じないですし、多分無駄。

回帰テスト-テストし過ぎという罠。

TDDの自殺でも語られている「モックやスタブのテストをしているのではないだろうか」「モックを書いているようでプロダクトを書いているのではないか」と感じるという罠。モック対象のコードが書き換わったのに、モックのコードを書き換えなかったため、結果としてデグレードを起こしてしまったという経験はないでしょうか。実際に疎通すれば良いだけなのに、なぜかユニットテストがたくさんあってそちらのコードを全部書きなおさないといけないとかいう場合とか無いでしょうか。
実際問題モックを使ったテストは用済みになれば削除され、結合したテストに置き換えて回帰テストとすれば良いと思うし、それであればモックを使ったテストはそれほど作らなくても良いのではないかと思います。結合した状態でも問題なくテストが出来れば良いのではないでしょうか。

TDDが限定的に生きる場面

TDD要らないのではないかという形で考えをすすめてきましたが、TDDをやるべき人たちもいます。それは初心者です。

初心者にTDDをやって欲しいと思うのは以下の3つの理由によります。

  1. 設計-INとOUTを先に考える癖をつける
  2. 単体テスト-自身の書くコードがどれくらい動かないのかを知る
  3. 回帰テスト-動いたということを上位者に確認してもらう

なんだかんだで初心者用としては非常に良いと思います。設計はともかく、自分が書くコードがどれくらい動かないものなのか、自分の実力がどれくらいのものなのかを知るということで、このコードは動かないのではないだろうかという不安を覚える原材料となりますし、単体テストでは確認しにくい場所、例えば性能問題が出た時に熟練プログラマーの人にテストコードという名前の仕様を引き継いで中身を書きなおしてもらいやすくするというのは非常に良いことだと思います。

まとめ

なんだかんだで書いてきたけれども、以下の様な感じです。

  1. 熟練者はTDDをする必要はない
  2. 初心者はTDDをしたほうが良い

TDDという素振りはするべきだけれども、プロダクトコードをきちんと書けるレベルの人はする必要はないんじゃないでしょうかね。
目的から考えれば多分別の適切な方法がありますよ。