というわけで、最近プライベートでの開発にテスト駆動開発を試し始めているのですが、これはよいですね。わたしはボンクラなので、テスト駆動なんていう難しそうな手法は縁がないかと思っていましたが、むしろ逆でしたw
きっかけは
まちゅさんのチケット駆動開発のエントリだったかな。
あと、実際にやってみようと思ったときに非常に助かったのがこちらの記事。
「テスト駆動開発」はプログラマのストレスを軽減するか? - @IT「テスト駆動」なんていうと
スーパープログラマがエクストリームに実践するハイパーでスペシャルな感じがするじゃないですか。テストを先に作るとか、支援ツール(xUnit)を活用するとか。あと、そもそも「最終コードに含まれないモノを作るのはめんどくさいなあ」というところもあったり。
でもまあ、やってみたらテストといっても定型記述がメインで、ちっとも難しくないものなんですね。しかも、いきあたりばったりにクラスを作る自分のようなボンクラコーディングに実に向いていました。
自分の場合、最終的にそのモジュール全体がどんな機能を持つかはある程度イメージできているものの、そのモジュールを構成する各クラスのインタラクションのところが設計にきちんと落としこめない。クラスのメソッドやメンバーがなかなか安定しない、というのがありました。で、だんだん手が動かなくなって、開発が止まっちゃう、というのの繰り返し。
たとえば、ゲームを作ろうとすると「画面上のオブジェクトを一括管理するModelクラスは、Characterクラスのインスタンスを管理して表示モジュールに引き渡せるようにする。時間を進めるメソッドを呼ぶとすべてのCharacterを1ステップ分遷移させる」というのは決めてても、「Characterクラスはどんなデータを持てばいいんだろう」とかで試行錯誤したり手が止まったりするわけです。
ここで、テスト駆動が非常に役に立つ。
Modelクラスに必要なメソッド(管理キャラクタのリストアップや、Tickの操作、初期化などなど)を作り、CharacterManagerのスケルトンを呼ぶ形でテストを通す(そう、この段階では固定で値を返すだけのスケルトンでいいのです!)。
これができたら、スケルトンの中身を一段階潜って、CharacterManagerクラスをスケルトン実装から本物の実装にリファクタリングする(このときは、Characterクラスのスケルトンを呼ぶ形でテストを通す)。
これを繰り返していけば、必要なインタラクションを実装したクラス群(モジュール)ができあがるわけです。
クラスを作る前に、クラスのテストコードを書く、という順番も効果は大きいです。
Characterクラスの中身を作り込む前に、Characterクラスのテストコード(Characterクラスを初期化したり参照したり設定したりするコード)を書くわけです。このテストコードによって、「どう呼ばれるのか」の具体的なイメージが固まってくるわけです。
それに、Characterクラスを実際にハンドリングするCharacterManagerクラスを作るときにも、テストコードで書いたように作ればいい、ということでもあります。
開発を進めていって、どこかで機能が足りない!となったら、
それが実装されたときにどう動いて欲しいかをイメージしたコードをテストとして追加して、そのテストを通るようになるまで実装を進めていけばいい。
ああ、ステキ! いつでもコンパイルが通って、ぱっと見動いてるふうで、いつでも実装が必要な部分が残されてる!!
とはいえ、動くように作っていく方法なので、できあがったクラス群がオブジェクト指向的に美しいかどうかを保証はしてくれない。でもまあ、まずはボンクラプログラマとしては、コードが動くことが重要。リファクタリングしやすいようにテストがあるわけなので、美しいのが好きなら、ガンガン書き直してテストを通せばいい。あるいは美しいアクセス方法(メンバ変数を直接触らないとかあるんだよねえ)で最初からテストを書いておけば、その辺の問題はあらかじめある程度抑えられるだろうし。
何か関数とかクラスとか作るときって、呼ぶ側のコードはもちろん作るけど、だいたいは使い捨てにしてたもんなぁ。それを一定の書式のもとでリユースするフレームワークがxUnitなどによって整えられているというわけです。
何にしても呼ぶ側と呼ばれる側をセットで作り、それを継続的に利用し続けることで「手が動くようになる」のが、テスト駆動開発という手法のいいところだと思います。今後は、初期実装が済んだところで、Tracとかでチケット管理にも挑戦しようと思ってます。
うん、もうちょっとがんばってみよう。