TDDBC2.1へ参加してきました

2011/09/24に2回目の参加となるTDDBCへ参加してきました。今回も非常に得るものの多い良い会でした。感想などを含め参加して思った事をつらつらと。

TDDに対する悶々とした悩み

TDDをそれなりに大規模で複数人な開発の中で適用しようとすると、上流設計から実際にTDDを始めるまでの間の設計をどこまでするべきか、についてずっと悶々としている部分があった。

これまでのTDD

これまで自分が実務で適用してみたTDDは、詳細設計でクラス設計をしながらユースケースごとのシーケンスを導き、そこで呼ばれる各モジュール単位のI/Fやある程度の内部処理を明確にした上で、それらをインプットとしてモジュールに対するテストを書き、コーディングしていくというスタイルだった。こうした背景はコーディングに入る前に作るべきモジュール数を明確にし進捗をわかりやすくするというのと、できるだけ上流工程での設計レビューを徹底することで設計思想と異なる設計にならないよう一定品質を保ためのチェックを行うためだと思う。確かに詳細設計のレビューでクラスやメソッドの責務やI/Fの認識違いをある程度排除することはできるが、実際にコードを書き始めるとモジュールを実装するのに必要な情報不足で再設計したり責務が不適切でモジュール分割やクラス分割をしたりと詳細設計の段階で決めたことからどんどん変わって行くことが多い。

開発者の足かせ

こうなるとモジュール数での進捗管理は分母がどんどん変わるので意味を成さないし、詳細設計でガチガチに設計してしまっていることがかえってコーディング時の自由度を奪うことにもなっていた。開発者の心境としては、「もっと良い設計が思い浮かんだけど詳細設計を直すのが面倒」「DRYにするためにモジュール分割をやりたいけどモジュール一覧のメンテは面倒だし進捗に見えちゃうからやり難い」などリファクタリングを妨げる足かせとなってしまい、現状の設計を大きく崩さないように無理な責務割当てやその場凌ぎの対応を余儀なくされ、より良いアイデアや設計に軌道修正していくこと自体の妨げとなってしまう。品質が悪い時に上の連中が二言目に言うのは「上流での品質確保」だが、どんなに上流工程で詳細設計をがんばっても実際にコードを書いてみなくてはわからない部分は必ず存在するし、そこで明確になったベストな解をいかに容易に設計へフィードバックしてより良いソフトウェアとしていくかの課題について考えて行かなくちゃいけないと思う。

ユースケース駆動開発

で、上で書いたようなやり方だとTDDのスコープが狭過ぎてそのメリットを活かしきれていないと感じていた。じゃあどこまでの設計をした上で TDD に入ればいいの?について、わたなべさんの発表を聞いていて思ったのは、ユースケースシナリオからロバストネス分析でクラス抽出してソフトウェアを構成する全体クラスを把握した上でユースケースごとのざっくりシーケンス(クラス間のやりとりレベル)を書くところまでやって、あとはアーキテクチャを適用しつつ TDD でユースケースシナリオを実装していくくらいが丁度良いのかなという感触を得た。フレームワークによってはある程度実装パターンが決まっていて各ユースケースごとのシーケンスというよりは代表的なのが一本あれば十分かもしれない。とにかく詳細設計で絵に描いた餅を設計しすぎないようにして、TDDを実践する過程で湧き出る設計アイデアや課題を逐次チームメンバで議論しながら適用していけば良いのかなと。以前読んだアジャイルラクティスの「設計は指針であって、指図ではない」という言葉が心に響く。

Cucumber の衝撃

演習で Railsチームでやらせてもらった Cucumber を用いた ATDD(Acceptance TDD)はまさにそういう感じで、ユースケースシナリオから直接受け入れ試験を導き出し、Capybaraを用いて動くテストシナリオを作りながらユースケースを実装していった。ある意味今回体験した開発プロセスはテストシナリオから直接 TDD でコードに落とすという究極的な方法で、たぶんもう少し大規模でかつ複雑度の高いソフトウェアの場合は事前にある程度のクラス設計とメインフローの検討やエラー方針の設計などを行い、モデルやコントローラのロジックレベルのユニットテストも必要なんだろうけど、「動くシナリオ」という直接実行可能な受け入れ試験の実装を積み重ねて行くというユースケース駆動開発の考え方は目から鱗だった。もちろんRailsという素晴らしいライブラリが揃っているかなり進んだ開発環境の成せる技というのはあるけれど、他の組み込み系の分野などでも受け入れ試験の観点の試験を自動実行可能なレベルで開発を駆動するというこの考え方は活かせるのではないかと思った。

受け入れテストを進捗に

進捗に関してもユースケースから導きだされたテストケースの通過数とするというのも非常に腑に落ちた。「何モジュールできた」というのはそもそも変数だから進捗の本質ではないし、もし1つのユースケースを実装する内部進捗の為にモジュール数が必要と考えるのであればその時点でユースケースの粒度が大きすぎるのかもしれない。細かくユースケースを積み上げていくことで進捗を表現し、恐らく発生するであろうリファクタリングによる他のユースケースへの影響(デグレ)も jenkinsなどを用いた受け入れテストの自動化で素早く発見・フォローすることで「テストケースの通過数=進捗」として実態とかけ離れた値にはならないはずだ。

現実は

これらを現実でできるかどうかは結局メンバ次第になってしまうかもしれない。経験の浅い開発者やそもそもソフトウェアに興味の無い開発者だったりオフショア先の会ったことも無い開発者にとっては、詳細に書かれた設計書が無いとコーディングなんてできないと言って来る場合もある。TDDで創造性を発揮できるスコープの幅をどう持たせるかは、そういったチームを構成する開発メンバのスキルやバランスを加味して調整していく必要もあるのだろうし、もちろん彼らを変えて行く努力も必要だ。また、開発環境的な問題もありえる。この辺りはどちらかというとプロジェクトリーダの頑張り次第でなんとかなる事も多いけど、ソフトウェア3本柱として言われている「バージョン管理」「テスティング」「自動化」さらに「チケット管理」をどのくらい整備できるかや、チーム内のコミニュケーションや情報共有の発達度も大きく影響してくる。

今後は

まぁ、いろいろと敷居が高い要因はあるけれど、どうせやるのであればTDDのスコープの幅をできるだけ広げて攻める姿勢で開発者一人一人の創造性や創意工夫を活かしつつ楽しく成長できてやりがいのある開発にしたいなと思う。TDDBC2.1ではこれらを実現するためのいろいろなヒントやアプローチを聞けて良かったし、具体的に手を動かす事で得られるたくさんの武器を講師の方々やチームメンバからいただいた。これからの自分のソフトウェア開発との向き合い方に活かして行こう。