« ソフトウェア・リポジトリ・マイニング~Web2.0をソフトウェア工学に応用する | トップページ | ブランチのライフサイクル »

2008/08/02

Subversionコードラインのライフサイクル

Subversionを使ったブランチモデル、バージョン管理戦略がだいぶ分かってきたのでまとめてみる。
#走り書きなので後でロジカルにまとめる。

元ネタは下記の記事。

複数のアジャイルチームでのバージョン管理

【1】Subversionブランチが作られるタイミングは、2つある。

一つは、本番リリース直後に作るリリースブランチ。
他方は、突然やってきた大きな機能追加に対応するタスクブランチ。

【1-1】リリースブランチは普通で頻繁に作る。
リリースブランチのライフサイクルは、下記の通り。
これがVer1.0, 2.0とバージョンアップするたびに作られる。

Create:本番リリース直後にtrunkから切られたTagから作る。

Update:緊急のバグ修正を反映する。当然、trunkにもマージする。

Delete:次のバージョンが本番リリースされた直後に廃止される。

ここで重要なポイントは、RedmineプロジェクトとSubversionブランチのライフサイクルは一致することだ。
つまり、RedmineプロジェクトとSubversionブランチは1対1に対応し、かつCRUDのタイミングも同期する。

実際の運用では、Subversionブランチで発生したコミットには、必ずRedmineのチケットが紐づく。
これによって、Subversionブランチのソース修正の理由がチケットから必ずトレースできる。
しかも、チケットに「関係する」「先行する」リンクでチケットをツリー状に関連付けることもできる。

これによって「3年前に修正した1行のソースの修正理由もすぐに分かる」インフラが整う。
システム開発の構成管理で最も重要な点は、トレーサビリティだと思う。
ここで言うトレーサビリティとは、要件からソースコードまで論理的一貫性があるだけでなく、ソース修正の理由も要件管理IDに紐づくものであること。

つまり、プロジェクト内部で発生する作業は全て、きちんとした理由がなければならず、更に誰でもいつでも説明できるものでなければならない。

【1-2】タスクブランチの使い方もようやく分かった。
タスクブランチを使いたい状況は、下記2つがある。

一つは、SQLインジェクション対応を埋め込みたい時など、ビッグリファクタリングが必要な時。
もう一つは、大きな機能改善をtrunkのバックグラウンドで平行で行いたい場合。

成功する要求仕様、失敗する要求仕様」を読んで目に留まった点がある。

今、バージョン3.0に向けて開発中で、大きな機能追加はバージョン4.0でリリースする計画を立てたと前提する。

その時、お客から追加要求が来た。
この時、どのように対処するか?という問いに対し、本では7つの選択肢があるのだが、最良の選択は下記であると主張している。

変更を受け入れて、リリース3.1という新たなリリースポイントを作り、変更リリース3.1に組み込む計画を立てる

これは、2系統のバージョン管理戦略の発想に似ている。
つまり、今の問いの場合、下記のような作業が発生するだろう。

Create:バージョン3.1用の追加機能を実装するタスクブランチをtrunkから作る。

Update:タスクブランチ上で機能追加していく。

バージョン3.0をリリースする直前:trunkからtagを切り、バージョン3.0のリリースブランチを切る。

Delete:バージョン3.1のタスクブランチをtrunkへマージする。

上記でよくある例は、実際の開発で、本番リリースブランチは緊急バグ修正、trunkで次期バージョンにむけた新規開発が平行して動いている。
しかし、突然、大きな仕様追加がやってきて、受け入れざるを得なくなったとする。
この場合、開発中の次期バージョンに混ぜ込むのはすごく危険。

この時にタスクブランチを使って、次の次のバージョンポイントに大きな機能追加をリリースするのが安全なバージョン戦略。

このタスクブランチの開発は実際はすごく難易度が高いけれど、うまく設計して、仕様追加された機能そのものを疎結合にできれば、成功する確率は高まる。

チケット駆動開発とは、バージョン単位にチケットをグループ化して、小刻みにリリースしてシステムを育てていくスタイル。

チケット駆動開発を運用して管理者として意識することは、直近のバージョンにどのチケットを入れるか、というチケットの取捨選択だ。
突然降ってくる大きな機能改善を、いかにシステムの品質を損なうことなくバージョンアップしていくか、がプロジェクトリーダーの腕の見せ所だと最近はつくづく思う。


【2】開発者は基本的に、Subversionのtrunkだけ意識してもらう。
つまり、最新機能のソースはtrunkへ入れる。

いくらブランチ戦略が良いと言っても、たくさんのコードラインがあると混乱する。
特に開発者には、一つのコードラインに集中して開発して欲しい。
だから、プロジェクトリーダーの指示がない限り、trunkだけ意識してもらう。

Subversionのブランチはまるで生態系の系統図みたいだ。

【3】マージ作業は基本的に、Subversionリビジョン単位に行う。
タスクブランチへtrunkの最新ソースを差分反映する時、Subversionリビジョンを指定して上書きしたり、マージしたりする。

Subversionのマージ作業が意外と簡単にできる理由は、Subversionリビジョンが差分ソースをユニークに決めるものだから。
Subversionリビジョンはシーケンスみたいなもの。

最近公開されたSubversion1.5では、マージトラッキング機能が反映されたらしいと聞いたので、試してみようと思う。

【4】trunkには、環境の設定ファイル込みのプロジェクトで管理する。
丁度、Railsのproduction/development/test、Seasarのct/it/utと同じ。
更に、フレームワーク部分とアプリケーション部分を疎結合に設計しておくことも大事。

ソフトウェアプロダクトラインが提唱する製品ファミリーのソース管理は、製品単位ではなく、単一のリポジトリで管理すべきだと思う。
例えば、iPodが似たような仕様で多種類の製品をリリースする時、ビルド時に一つのリポジトリから製品ごとにビルドするやり方。

ビルドスクリプト内部で、開発サーバー向けか本番サーバー向けか切り替える、とか、顧客Aと顧客B向けに切り替える、とか、i386向けかPowerPC向けに切り替える、とかする。
そうすれば、開発者はtrunkにある単一リポジトリだけ専念すればいい。

でも、今まで僕が経験したパッケージ製品開発の現場では、ソース管理は製品単位に作られて、同じようなソースがあちこちの製品に散らばって、結局うまく管理できていなかった。
特に、フレームワークのバグ修正を後からマージする時が面倒で、しかも全て漏れなくマージできたのか、検証が面倒で難しい。
結局、せっかく直したと報告のあがったフレームワークのバグが直っていなかったりして、デスマーチに輪をかけたりした。

RedmineとSubversionを組み合わせたチケット駆動開発を運用して分かったことは、オープンソースに従事する開発者の方が大手SIerよりも、プログラミング技術だけでなくソース管理という最も重要なプロジェクト管理技術もレベルが高いこと。
実際、Rubyもver1.8系とver1.9系は厳密に管理されているし、Firefoxの開発も同様。

ソース管理という最も基本的で最重要な管理手法はもっと研究の余地がある。

|

« ソフトウェア・リポジトリ・マイニング~Web2.0をソフトウェア工学に応用する | トップページ | ブランチのライフサイクル »

プロジェクトマネジメント」カテゴリの記事

Redmine」カテゴリの記事

構成管理・Git」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック


この記事へのトラックバック一覧です: Subversionコードラインのライフサイクル:

« ソフトウェア・リポジトリ・マイニング~Web2.0をソフトウェア工学に応用する | トップページ | ブランチのライフサイクル »