複数プロジェクトがある場合のビルド環境

環境依存の情報の管理やHudsonのジョブ設計など - watawata日記に触発されて。自分もちょうど考えてることがあったのですが、140字ではとても足りないのでブログにまとめてみます。

ちなみにJava開発の話です、はい。


前提

「ビルドスクリプトは、IDE/CIに依存しないこと」が大事だと考えています。(Java開発においては)IDE上で開発する方が大多数だと思いますが、コマンドプロンプトシェルスクリプト上でビルドできて、かつCI上でも同様に実行できること。これがビルド環境を考える上で大事なことですね。

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-F15B8.png

プロジェクトの分類

ここでは、2つの要素でプロジェクトを分類します。

  • 依存ライブラリ管理の仕組みが有るか?
  • IDE上で、プロジェクト間での直接参照が有るか?

依存ライブラリの管理というのは、平たく言えばMaven/Ivyを導入しているか?ということです。IvyはAntベースで、Mavenから依存ライブラリの管理機能だけを抽出したものと考えてもらえばいいでしょう。詳しく知りたい人は、ぐぐれ(ry

プロジェクト間での直接参照というのは、例えばプロジェクトBがプロジェクトAに依存している場合に、どのようにプロジェクトAを参照しているかの話です。直接参照では、IDE上の設定でプロジェクトを指定して参照する設定を行います。逆に、直接参照がないということは、依存しているプロジェクトAをJarファイルなどでパッケージ化した後にプロジェクトBにそのJarファイルをインポートしているといった場合です。

直接参照をしておくと、プロジェクトAリファクタリングした場合などでもプロジェクトBにも変更を追随してくれるので、非常に便利です。が、プロジェクトAの変更が即座にBに反映されるのは、よしとしない状況も当然あるでしょう。また、IDEの機能なので、ビルドスクリプトでは参照関係をそのまま扱うことはできません。

依存ライブラリの管理が有り、プロジェクトの直接参照が無い

一番スマートな構成ですね。Mavenだったら、依存しているプロジェクトAを先にmvn:installなどでローカルリポジトリにインストールし、その後のプロジェクトBのビルドではリポジトリ経由でプロジェクトAを参照します*1

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-97EC3.png

依存ライブラリの管理が無く、プロジェクトの直接参照が無い

基本的には、上記の構成と変わりありません。ただ、リポジトリ経由での参照はできないので、プロジェクトAをJarパッケージ化しておき、プロジェクトBではそのJarファイルをインポートして(コミットして)参照するといった手順になります。インポートするのは手動ですので手間はかかりますが、どの環境でも同じようにビルドができるので、硬い方法と言えるでしょう。

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-F8B21.png

依存ライブラリの管理が有り、プロジェクトの直接参照が有る

IDE上ではプロジェクトの直接参照をしていますが、コマンドプロンプトシェルスクリプト上ではリポジトリ経由で参照します。IDE上でのビルド環境とそれ以外のビルド環境が異なっているのが若干気になるところですが、ビルド環境の構築自体はそこまで手間はかからないでしょう。

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-4DE64.png

依存ライブラリの管理が無く、プロジェクトの直接参照が有る

このケースが一番厄介です。が、実際問題、このケースというのは多いんじゃないでしょうか。で、CI(Hudson)を導入したときの最初の壁になるのもこのあたりだと思います。

途中で触れたように、プロジェクトの直接参照はIDEの機能ですのでビルドスクリプトでは解決できません。で、まず考えるのは、(大体Ant : build.xmlでしょうが)ビルドスクリプトで依存関係を解決できるように作り込むことだと思います。

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-BF7BD.png

ただ、これ意外と面倒なんですよね。プロジェクトAとプロジェクトBが同一階層にあるかも限定できないので、BからAへの参照を汎用的に実現するのは難しい。それでいてIDE上では特に手間かけずにビルドできるので、労力かける価値もあまり見出しにくい。

そこで、最近は以下の図のような構成をベースに考えています。ローカルではIDE上でビルドすることを前提にし、Hudson上ではプラグインを用いて依存関係を解決する。Hudsonプラグインは、Copy Artifact Plugin - hudson - Hudson Wikiとか使うと結構あっさり解決することができます。

https://cacoo.com/diagrams/D48z4DqiiYMUJfkP-00F04.png


最後の考えと、前提で言った「ビルドスクリプトは、IDE/CIに依存しないこと」と実は矛盾してますw ただ、一番大事なことは「最小限のコストで最大限のリターンを得ること」だと考えています。「ビルドスクリプトは〜」もそのための一つの指針でしかないと。

なので、コストとリターンの兼ね合いから考えて、(少なくとも現時点では)最後のような割り切りも全然ありだとは思っています。色々経験していったら、将来的にはまた変わるかもしれませんけどね。

*1:ローカルリポジトリではなく、mvn:deployなどのリモートのリポジトリを参照するという話もありますが、この違いはここでの大枠から外れるので割愛します