受託開発でTDDを導入するということ #TddAdventJp

このエントリは、TDD Advent Calendar jp: 2012の5日目の参加エントリです。 前日は、@irofさんの「思い通りに動くコードを書きたい」でした。

このエントリでは、受託開発においてTDDを導入することについて考察していきたいと思います。 自社サービスとして継続的に機能改修をしていくのに対して、明確な納期がある受託開発ではシステムの品質を求められるタイミングも、その内容も異なるため、TDDを実践するにしても気をつけないといけないことがあります。 そんな、僕が最近考えていること、気をつけてること・今後気をつけようと思っていることについて書いていこうと思います。

一般的なTDDのメリット

まずは受託開発の話に入る前に、一般的なTDDのメリットについておさらいしたいと思います。 TDDとは分析・設計手法であり、プロダクトコードを書く前にレッドになるテストコードを書こうとすることで、各モジュールを利用する側の立場になって考えるきっかけになり、モジュールのインターフェースが洗練され、モジュール間の依存関係もなくなります。仮に外部モジュールに依存する場合はそれを外部から差し込めるようにする(=Dependency Injection: 依存性の注入)のがよい設計だと言われています。 また、TDDを厳密に実践していくと、自然とコードカバレッジは100%に近づくことになり、意図しなかった変更の影響に気づくことができます(=回帰テスト)。

まとめると

がTDDを実践することによるメリットだと言っていいでしょう。

TDDを実践してみてそれが優れた手法だと感じるタイミングは人それぞれかも知れません。例えば、テストを書きながら自分がこれから実装しようとしているモジュールの設計が洗練されていく感覚を味わったとき、回帰テストによって思わぬ不具合を早期に検出できたとき、リファクタリングをしたいと思ったときなどでしょうか。

また、有効性の議論とは少し違いますが、単純にテストコードを書くのが楽しいということもあるでしょう。一般的にテストコードはプロダクトコード以上に可読性を求められるため、重要な部分を目立たせたり、本質的でない処理をヘルパーメソッドにまとめたりといった工夫が必要になり、プログラマとしてのやりがいを刺激すると思っていますし、そうやって培った可読性向上のための努力や経験はプロダクトコードを実装する場合にも当然活かせるものです。

ソフトウェアの品質

さて、ここで少し話を変えて、ソフトウェアの品質の話をしたいと思います。

TDDを実践している人にとっては当たり前かと思いますが、TDDにおける「テスト」とはあくまで実装を開始する前に要件や仕様を把握したり、分析・設計を行うためにものであり、「ソフトウェアの品質を評価するためのテスト」とは明確に異なります。一般的に、TDDを実践することによって品質は向上すると言われていますが、品質を「保証」はしてくれません。

ソフトウェアにおける品質に関する標準を定めているISO/IEC 9126によれば、ソフトウェアの品質には「外部品質」「内部品質」そして「利用時の品質」があります。 ソフトウェアの存在意義が実際に実行されユーザに対して価値を提供することである以上、もっとも優先されるべきは当然「利用時の品質」になりますが、これにはすべてのユーザの実行環境やユーザがそのソフトウェアを利用する意図までも考慮する必要があります。 その「利用時の品質」に直接影響を与えるのが「外部品質」であり、実際にそのソフトウェアを実行した際の結果が仕様通りであるかによって示される品質です。またその「外部品質」に影響を与えるのが「内部品質」であり、これはソフトウェアを実行せずに静的に測定される品質、たとえばソースコードのコードレビューであったり、ドキュメントの網羅性で示されるものです。 僕の認識では、TDDとは「内部品質を高めソフトウェアを変更に強い構成にしておくことで、外部品質を損なうことなく運用/拡張を続けていくための手法」ということができるかと思っています。

受託開発であるということ

さて、ここで本題です。 冒頭でも述べた通り、受託開発においては必ず「納期」があります。「納品しない受託開発」というコンセプトを掲げていらっしゃる企業さんもありますし、僕はそのコンセプトは非常にすばらしいと思っていますが、多くの受託開発企業には納期があり、ソフトウェアを「納品」するでしょう。

もちろん自社のサービスであっても機能をリリースするというマイルストーンはあるかと思いますが、自社サービスの場合はリリース後も同じチームが同じサービスの開発を続けるのに対して、受託開発の場合は基本的に納品を境として、その後はソースコードを触ることはできません。(場合によっては保守契約を締結させていただくこともありますが、それでも極めて限定的にしかソースコードの変更はできないことがほとんどです。)

そのため、TDDを導入する上でのメリットのひとつである「回帰テスト」としてのメリットが開発期間中にしか機能しないのです。また、求められる品質も「内部品質を高めて中長期的にサービスを改善・拡張していけるような変更への強さ」ではなく「決められた日までに要件(=外部品質)を満たすこと」になるため、TDDは選択肢のひとつにはなりえますが、唯一の選択肢にはなりにくいです。

TDDと工数

TDDやペアプロ等のアジャイルプラクティスを実践した結果、その開発工数がどうなるかという研究は数多くされています。ここでは特定の論文を引用することは控えますが、僕が知っている限りでは「開発工数は微増するが、バグ発生率は減り、テスト・デバッグを含めたトータルの工数は削減される」という結果が多かったかと思います。 「変更に強い」ということが価値として見なされにくい*1以上、僕が今後考えていかないことはこういった部分なのかと考えています。

外部品質の測定を自動化するという選択肢

最近、僕が関わるプロジェクトではディレクターさんにSeleniumを使ってテストケースを作ってもらっています。 TDDと呼ぶにはRed/Green/Refactorのサイクルが長過ぎますが「テストケースを考えることによって設計が洗練される」という快感は何もプログラマの特権ではありません。Seleniumを使うことによって、HTMLさえわかれば自動テストケースを作成することができるようになりますし、それをプロジェクトの初期に行うことによって考慮不足だった点が洗い出され、仕様が洗練されていくと僕は信じています。 「先にテストケースを作る」ことによって仕様や設計が洗練され、最終的なソフトウェアの品質が高まっていく実感をプログラマだけでなくいろいろな人に味わってもらい、それを少しずつ浸透させていきたいというのが最近僕が考えていることです。

もちろん、内部品質が低い状態でSeleniumのテストケースだけ作っても全部Redになるだけなので、TDDの推進は引き続きがんばります。

と、決意を表明したところで、翌日は@nnasakiさんです。よろしくお願いします。

*1:これがいいとか悪いとか言うつもりはなく、ビジネスモデルとして仕方のないことだと思っています。