Hudsonを使ったアジャイルな開発入門
第3回 Hudsonによるチーム間の連携
この連載では,オープンソースの継続的インテグレーション(CI)サーバであるHudsonを利用した,ソフトウェア開発の生産性向上について解説しています。前回の記事では,Hudson上に継続的ビルドを設定して,ソースコードに加えられた変更をいち早くビルドし,結果を開発者にフィードバックする方法に付いて見てきました。今回は,視野を少し広げて,規模の大きいソフトウェアプロジェクトの開発で,Hudsonを更に有効活用する方法についてみていきます。
テストを有効活用する
実行したテストの結果をHudson上に集計する方法については前回述べました。ビルドと同時にテストもやってしまうという手法は,小さなプロジェクトやライブラリ,もしくはテストの数も少ない場合にはとても有効です。ですが,プロジェクトが大きくなりテストの数が増えるにつれ,テストの実行時間が長くなり,この方法では迅速にフィードバックを得ることが難しくなります。プログラムの変更を加える際には,開発者は暗黙の内に,変更によって得られるメリットと,バグを混入させて混乱を引き起こす可能性とを天秤にかけています。大規模なテストを短時間で実行できれば,小さなメリットしか得られない変更でも着実に拾っていくことができます(リファクタリングなどは特にこのカテゴリに属する変更です)。これが,中長期的にソフトウェアの品質の確保につながるのです。このため,大規模なソフトウェア開発においてはテストの実行時間を極力短くすることは非常に戦略的な重要性を持っています。テスト自体の書き方・実行の仕方で工夫することが第一ですが,その議論は本稿の範疇を外れるので,ここではHudsonをどのように活用するかを見てみます。
まず第一のステップは,ビルドとテストをHudson上で2つのプロジェクトに分離することです。Hudsonは異なるプロジェクトのビルドは同時並行で行ってくれますから,これによってテストとビルドを同時進行させることが可能になります。この様子はちょうどCPUが命令をパイプライン処理するのに似ています。変更が加えられてからそのテストが完了するまでの時間は同じなのですが,同時に2つを走らせる事でソースコードに変更が加えられてからビルドが開始されるまでの待ち時間を大きくカットできるわけです。
このようにセットアップするためには,ビルド側からテスト側へテストするべきバイナリを送る必要があります。これには永続リンクが大変有効です。すなわち,流れは次の様になります。
- ビルド側が完了時にバイナリを保管
これには「ビルド後の処理」>「成果物を保存」を使います。 - ビルドの完了後テストを自動的に開始
これには「ビルド後の処理」>「他のプロジェクトのビルド」を使います。 - 最新のビルド成果物をHudsonから取得
これにはwgetやAntの<get>タスクなどを使います。Hudsonの「最新成功ビルドの成果物」のリンクは永続リンクになっているので,これを利用しましょう。 - テストを実行
上流・下流ビルド
上記のように,複数のプロジェクトの間に依存関係を設定してあるプロジェクトのビルドが完了した時に他のプロジェクトをビルドさせることができます。このような関係にあるプロジェクトを上流プロジェクト・下流プロジェクト,または上流ビルド・下流ビルドと呼びます。テストだけに限らず,Hudson上により多くの作業を移すにつれ,1つの巨大ジョブで全ての作業をやろうとすると1サイクルの実行時間が長くなりすぎてCIのメリットが薄れてきます。このような場合に,作業をいくつかのジョブに分解しそれらの間に依存関係を適切に設定することで,この問題を解決できます。
一方,複雑な依存関係を設定する場合には幾つか必要な注意もあります。まず,上流ビルドが完了した時に実際に行われている事は,下流プロジェクトに対する新規ビルドのリクエストだということです(これはちょうど「ビルド実行」リンクをクリックするのと同じです)。この時,下流のプロジェクトのビルドが既に待ち行列に入っていれば新しいリクエストは単にこれに吸収されます。なので,一般的には(特に下流ビルドが上流ビルドより長い時間を要する場合には),上流ビルドと下流ビルドは一対一には対応しないことがあります。また,A→B,B→D,A→C,C→Dといったようなダイヤモンド依存関係がある時も,Bと Cの変更はDを個別にリクエストするので,従ってAのビルドが最終的には2つのDのビルドを生じる,というような事があります。
こういった問題を解決してより賢い依存関係を処理するという議論は,devリストで頻繁に行われていますが,残念ながら現時点では特に具体的な案はありません。


