うさぎ組

ソフトウェア開発、チームによる製品開発、アジャイル、ソフトウェアテスト

TDDを明確に定義する 2

はじめに

はてな
にて、id:ToMmY くんが
TDDを明確に定義する - うさぎ組
のお返事を書いてくれたのでさらにお返事!
とみぃくんがTDDにテストファーストを組み込む理由については僕も共感できますが、僕がテストファーストを組み込まなかったのには理由があるので、ここで述べていこうと思います。


ただし、今回の記事はかなり僕の感覚によるところが大きいです。(前回もそうと言えばそうなんですが。

TDDの定義にテストファーストを組み込んでいない理由

foo駆動開発というものは「No foo, No Commit」ではないと考えています。
もうちょっとゆるくて「fooの設計、実施によるフィードバックループ」であると捉えています。
そして、重要なのは「設計しない, 実装しない, 実施しない」というのも明確な手段であり、存在しないことによるフィードバックループへの影響があります。


具体的にTDDに話をうつします。

テストファーストが定義に含めなくてもTDDである具体例

RED -> GREEN -> REFACTOR が根底にあるといいながら、テストファーストが定義に含まれないのは理由があります。


具体的に言えば、REDから始まる必要はないと僕は考えています。手順で示します。

  1. (自分にとっては)簡単なコードなのでまずプロダクトコードを書く
  2. コンパイルが通る
  3. テストコードを書いて、実行する
  4. テストが予想通り合格する
  5. リファクタリングを考慮するが、コードの成長する方向が明確でないので、ここではリファクタリングをしない。
  6. 失敗するであろうテストコードを追加する
  7. テストが失敗する
  8. プロダクトコードを修正して、テストを実行して、テストが合格する


1 - 4 : GREEN
5 : REFACTOR
6 - 8 : RED
になっています。
これはテストファーストを厳守していません。ここにおいて、僕はTDDをしていないとは思っていないという事です。
これもれっきとしたTDDであると考えています。


これには2つの理由があります。

その1:テストによって支えられる側面にはいくつかある

TDDは設計手法である。という話からのみTDDを語る場合であれば、テストファーストによる「例示による設計」がまさにTDDになるのでしょう。テストファーストによって実装を支えてもらう事になります。


ただし、本当にそれだけなのであれば、REDとGREENのみでよいのです。
TDDにはREFACTORという要素があります。これを成立させているのは、GREENの結果をある範囲において保てるからです。


ここで、今更ですがTDDのテストとは検査群であると置き換えましょう。
検査群には少なくとも2つの側面があります。

  1. 検査対象群の実装前に外部設計を行う
  2. REFACTORを実施するインフラ


とみぃくんが指摘したのは、1.の検査対象群の外部設計を行うという側面です。僕は、1,2のどちらかを満たせていればそれはTDDであると思うのです。
僕はリファクタリングも「開発」だと考えていて、2のみを満たしている状況においても僕はテストによって駆動されていると感じるからです。
これを単なる回帰テストであると考える事もできますが、回帰テストはTDDの具体例の一部に出てくるに過ぎません。一部のみを切り取って「○○と同一である」と言うのはいかようにも出来ます。

その2:他人にTDDをしているというタイミング

ある開発において、「TDDしましょう」「TDDしています」と言う時に「完全なテストファーストをしているときのみ」に「TDDしています」と言うのでしょうか?


少なくとも、僕は「テストファーストしていなくてもTDDしていると言ってよい」と思っています。「検査群と共にRED -> GREEN -> REFACTORを回すことによって開発が効率的に進んでいる」と実感出来ていればよいと考えています。
それ以上の事は前回のエントリでも述べた「TDDはフレームワークなので、ひどいTDDをすることも、良いTDDをすることもできる。」という部分につきます。


まとめ

僕がTDDの定義にテストファーストを入れない理由は2つある。
検査群には少なくとも2つの側面があり、検査対象群の実装前に外部設計を行う
ことと、REFACTORを実施するインフラであることがある。それらのどちらかを満たすようにRED -> GREEN -> REFACTOR を回せればよく、その場合にはREDから始まることが必須要件にならない。
他人に「TDDをしている」「TDDをしよう」というときにテストファーストを完全に出来ていなくても「TDDしている」という実感を持てているのであれば、それはTDDであると言ってもよいと考えている。感情的な部分であるが、人が行うフレームワークという性質上、僕は許容範囲だと考えていて、それ以上は良いTDD、悪いTDDだと思う。


そして大事な事は良いTDDというのはコンテキストに大きく依存する事である。開発者や要求のレベルによって大きく場面が異なります。
個人的にはTDDという定義自体は最小限のフレームワークとしてにおさめておき、「開発者がある言語でのTDDになれている場合のTDD」「初心者として始めるためのTDD」などのようにいろんなTDDフレームワークを実装されていくのがよいと思うのです。