SaaS開発ほど面白いものはない - TDD(テストドリブン開発)
わたしは現在、業務ソフト系のソフトウェアエンジニアをやっている。大学を卒業したときの専門は、ある日系企業が開発する汎用コンピュータを出荷した後の技術支援だった。その汎用コンピュータは、IBMの汎用機と同じ機能を提供するという、いわゆるプラグコンパチブルマシンだった。現代でいうと、AMDのプロセッサや(どうも結局つぶれてしまったらしいが)トランスメタなどが、インテルのプロセッサと同等の機能を提供することなどと同じである。わたしはヨーロッパや米国に駐在して、技術支援を担当していた。
具体的な仕事内容は、海外の顧客で発生したファームウェアのバグ、推定される障害を日本の開発技術者に報告して、トラブルシュートを海外の顧客や海外の保守エンジニア、海外の担当SE、日本の開発エンジニアたちと協力して行う、というものだった。もちろん、製品について高度な技術が必要になる。その技術は、海外に駐在する前に2~3年、日本の開発部署で開発に従事して取得していた。そのため、わたしは基本的にはテクニカルサポートエンジニアであるが、開発エンジニアでもあった。
顧客へ製品を出荷した後、発生する問題はさまざまある。ハードウェアの問題である可能性はあるにはあるが、まずない。ほとんどはファームウェアの問題だ。原因解明後にはパッチを顧客のマシンに投入し、他の顧客への反映はファームウェアのバージョンアップで一斉に行う、といったことをしていた。
さて、この汎用コンピュータ。新しいテクノロジを使った新製品のリリース、つまりテクノロジの世代交代はだいたい5年に1回ぐらいの頻度で行っていた。大まかだが、1980年にはIC中心のコンピュータ、1985年にはカスタムLSI、1990年にはもっと集積度の進んだカスタムLSI。ここまでは、1つのCPUが複数のパッケージで作られるような物理実装だ。1995年には1チップで1CPUの時代になり、2000年には1チップに複数のCPU、という流れでテクノロジーは進化した。
一連の製品は、基本的にすべて同じOS、つまりIBMのOSを使っている。MVSやVMなどが上に乗って走るため、わたしがサポートすべきソフトウェアとのインターフェイス(API)はテクノロジーが進化しても大きくは変わらない。ここで、製品開発の際に作っていたテストプログラムの蓄積が大きく貢献することになる。一番最初にIBMコンパチ機を開発するとき、一連のテスト用プログラムを同時に開発。その後の世代の開発には、前の世代で開発済みのテストプログラムに、新世代で新たに必要となるAPIをテストするプログラムを追加して開発に使った。
つまりテストファーストのプラクティス、開発段階でテストプログラムが存在する体制・開発方式を採用していたわけである。5年ごとに性能は上がっていくが、基本的に同じものを開発していく製品開発では、このテストファーストがまさにピッタリな開発方法なのである。インテルやAMDなども、同じAPIをサポートし性能がアップするx86チップを今も開発し続けている。当然のことだが、前の世代で開発したテストプログラムを次の世代で使うような手法をとっていると思う。
さて、同じものを繰り返し開発する製品開発では、テストファーストのプラクティスはうまくいく。ところが、同じ手法を業務ソフト開発に使うには、かなりの工夫と開発者のパラダイムシフトが必要になる。しかし、開発方法論としてうまく取り入れることができれば、開発が長期にわたり、Versionアップを繰り返すような開発の時、 圧倒的な開発生産性を達成できるのも確かだ。
SaaS開発はまさに、長期に渡ってVersionアップを繰り返す製品だ。競争力を持つSaaSを開発するには、このテストファーストのプラクティスは必須といって過言ではない。
業務ソフトの開発にテストファーストを採用するとなると、メリットをもっとも受けやすくするためには、テストドリブンになるのが自然である。両者の違いは、テストのしやすさを設計の中に考慮するか否かである。
JavaやC#、そしてC++などでは、実装して実際に動かす前にコンパイルが必要だが、それと同じ頻度でテストが実行できるぐらい、テストプログラムは軽いものでなくてはならない。何万行のコードについているテストコードは遅くとも、1分以内で終らなければ、誰もテストを実行しなくなってしまう。
そのためには、テストコードがDBにアクセスするものであってはいけない。テストドリブンの考えを設計に取り込み、まずDBアクセス層とビジネス層は完全に切り離す必要がある。その後、DBアクセスの部分をスタブ化する。テストコードでは、スタブコード内でDBアクセスで取得するべきデータ取得を行い、ハードコードでシミュレートするコードを書いて対応することになる。
また、個々のクラスをテストするとき、そのクラスが動作するときに必要な別クラスが実際になくともテストできなければ、ユニットテストが非常に面倒にになる。テストドリブンの考えをとりこみ、SRP(Single Responsibility Principal)、つまり個々のクラスに単独の責任しか与えない設計を徹底し、さらにDependancy Injectionの仕組みを使って、クラスごとのユニットテストを行うことになる。
UIのテストは、ユーザの操作自体を自動化してテストする試みが過去に試されたが、結局うまくいかず難しい問題として残っている。最近のトレンドとしては、難しさを避けるため、UIのコード自体のテストはやらない方針にし、その代わりUIのバグが絶対出ないような作りでプログラムを作る。
プログラムのバグが絶対出ないようにする唯一の方法は、プログラムを小さくすることしかない。つまり、UIの層を極力小さくすることになる。純粋な ASP.NETの開発で、このあたりを達成するのは、非常に難しく、最近マイクロソフトの開発で出てきた技術にASP.NET MVCフレームワークや、フレームワークではないが、ASP.NET MVPアーキテクチャーパターンなどがある。
Javaの世界では、StrutsやJava Faceなどでこの辺は進んでいる。それらはMVCパターンを使っている。最近わたしはRuby on Railsを勉強し始めたが、それもMVCパターンを使っている。どうやらこのMVCパターンは、Webアプリケーション開発のスタンダードといってもいいだろう。
デスクトップのアプリケーション開発者にとって、同じパラダイムでWebアプリケーションを開発できるASP.NETは、最初は受けたが、構造的にUI 層が膨らみすぎてしまうという、大規模開発に際しては致命的といえる欠陥があることが、ようやくマイクロソフトにも分かってきたのだろう。その結果が ASP.NET MVPとして出てきたものと思う。
と、こういう風に少々のパラダイムシフトの必要があるが、それを克服できた技術者にとって、SaaSの開発は技術者冥利に尽きる開発となりえるだろう。汚いコード、分かりにくいコードがあると思えば、それをリファクタすれば良いのだ。リファクタによるデグラの心配はほとんどない。100%完璧にメンテしている自動テストプログラムを走らせ、問題なければまずデグラはない。
技術者にとって、動いているシステムに変更を入れるときほど大きなプレッシャーを受ける瞬間はない。デグラがないことを確認するための単調な手動テストもいやなものだ。それがなくなる開発。すばらしいと思わない技術者はいないだろう。