パッケージの作成、リリース、日々の開発 この章では、フリーソフトウェアのプロジェクトが、 ソフトウェアをパッケージングしてリリースする方法と、 開発パターン全体がこうした目標にどう繋がっているのかについて述べていきます。 オープンソースプロジェクトと独占的なソフトウェアのプロジェクトとの主な違いは、 開発チームに対して中央集権的な管理が行なわれているかどうかにあります。 新しいリリースを準備しているとき、この違いは特にはっきりします。 独占的なソフトウェアのプロジェクトでは、企業は今度のリリースにかかわる作業に集中し、 新機能の開発や重大でないバグフィックスは、 リリースが終わるまで脇に置いてくれと開発チーム全体に求めることができます。 ボランティアの集団はそんな一枚岩ではありません。 オープンソースプロジェクトの人々は様々な理由で働いています。 よってリリース作業を手伝うことに興味がない人たちは、 たとえリリース作業が進行中でも日々の開発作業を続けたいと考えます。 開発が止まることはないので、 オープンソースソフトウェアのリリース作業は、 独占的なソフトウェアのそれに比べて時間がかかりがちですが、 混沌としたものではありません。 これは高速道路の修復にちょっと似ています。 道路を直すには二つやり方があります。 ひとつは、道路全体に作業員が群がって問題が解決するまで全力で働けるように、 道路を完全に閉鎖することです。 もうひとつは、一度にひとつの車線でだけ作業を行い、 もう一方は通行できるようにしておくことです。 はじめのやり方は 修理を行なう作業員にとっては 効率がいいやり方ですが、 それ以外の人にはよくありません — 作業が終わるまで道路全体が閉鎖されるからです。 ふたつめのやり方は時間がかかり、修理する作業員は大変です(少ない人数、少ない機械、 窮屈な環境での作業を強いられる上、 通行する車を徐行させて交通整理をする旗振り役も置かなければいけない、など)が、 作業員が全力を出さなくても少なくとも道路は使いやすい状態のままです。 オープンソースプロジェクトはよくふたつめのやり方で動いています。 実際、複数の異なったリリースラインがある状態で、 成熟したソフトウェアのモジュールを管理するために、 プロジェクトはずっと小規模な道路修理を続けているような状態です。 いつも二つの車線が閉鎖して作業をしています。つまり、 リリースを定期的なスケジュールに従って行なえるように、 開発チームは裏で起こるささいな不都合にはいつも目をつぶっているのです。 この作業モデルはリリース作業以外にも一般化できます。 互いに依存していないタスクは平行して処理をするという原則です。— これはオープンソースソフトウェアの開発に限ったものではありませんが、 オープンソースプロジェクトは、独自のやり方でこの原則を実践しています。 プロジェクトで作業をしているボランティア達は、 道路工事の作業員や通行する車を気にする余裕はそんなにありませんし、 カラーコーンの傍に待機して車に旗を振らせることに作業員を専念させる余裕もないのです。 つまり、彼らはプロジェクト管理の負荷の変化が激しい管理プロセスよりは、 負荷が一定か、変化が少なくなるようなプロセスを好みます。 ボランティアたちは、ちょっと不便だなと思う状態が続いても嫌がりません。 自分にかかる負荷が予想できるからこそ、 彼らはプロジェクトで起こっていることがスケジュールと衝突しているかどうかを気にせずに作業できるのです。 プロジェクトが別の作業をやめてある作業に専念させるようなマスタースケジュールに縛られていると、 多くの開発者が長い間何もしない状態が発生します — これは非効率であるばかりか、 退屈なので危険です。退屈した開発者は、すぐに辞めてしまうでしょう。 リリース作業は、 平行して行なわれる作業のなかでも開発とは関係ないもっとも目立つタスクです。 よって次のセクションで説明するやり方で、 リリース作業を行なうタイミングを調整しています。 しかし、リリース作業と平行して行なえる作業、 たとえば翻訳や国際化、 コードベース全体に徐々に浸透するようにAPIを大規模に変更する、 などが同時に行なわれていることに注意してください。 リリースに番号を付ける リリースを行なう方法を議論する前に、 リリースに対する名前の付け方をみておきましょう。 これは、リリースがユーザーにとって何を意味するのかを知らせるのに必要なものです。 リリースとは、次のようなものです。 古いバグが直っています。 これは全てのリリースに当てはまると多分ユーザーが期待していいことでしょう。 新しいバグが入り込んでいます。 これは時々行なわれるセキュリティリリース(この章の後半のを参照してください)や他の単発リリースを除いて、普通は十分過ぎるほどあり得ることです。 新機能が追加されているかもしれません。 新しい設定オプションが追加され、 古いオプションの意味が微妙に変わっているかもしれません。 あって欲しくないことですが、 直前のリリースと比べてインストール手順も変わっている可能性があります。 互換性のない変更が入っているかもしれません。たとえば、 古いバージョンで使われていたデータフォーマットはある種の変換を(多分手動で)しないともはや使えなくなっているといったものです。 見てわかる通り、全てが良いことばかりではありません。 よって経験豊富なユーザーは、新しいリリースを少し恐る恐る扱います。 特にそのソフトウェアが成熟しており、 既にユーザーが求めた(または欲しいと思った)動きをほとんどしてくれていた場合はなおさらです。 たとえ新機能が追加されても、 それによってソフトウェアが意図しない振舞いをするかもしれないという点で、 ありがた迷惑なものなのです。 よって、リリースに番号を付ける目的はふたつあります。 当然、 リリース番号はリリースの順番を明確に伝える(i.e. ふたつのリリース番号を見れば、 どちらが新しいものかがわかる)べきものですが、 それだけではなくて、 変更の性質や程度をできるだけ簡潔に示すものでなければなりません。 そんなことを全部数字で表現するのかって? まあ、程度の差はありますが答えはYESです。 リリース番号の付け方は、 些細な話題なのに最も古くからあちこちで議論されてきた( を参照してください)もののひとつですが、 近い将来、唯一の完全な標準に落ち着く気配はありません。 しかし、一貫していること という普遍的に受け入れられた原則に基づいて、 優れた戦略がいくつか出てきています。 番号の付け方を選び、それを文書化し、守るようにしましょう。 番号の付け方をはっきりさせれば、ユーザーはあなたに感謝することでしょう。 リリース番号の構成要素 このセクションではリリース番号を付ける規約を説明しますが、 読者に前提となる知識が殆どないことを想定しています。 主に参考資料として読まれることを意図していますが、 あなたが既にこうした規約に馴染んでいるのなら、飛ばして読んでも構いません。 リリース番号はドットで区切られた数字の集まりです。 Scanley 2.3 Singer 5.11.4 ... などです。ドットは 小数点では なく、 単なる区切りです。"5.3.9" の次は "5.3.10" となります。 プロジェクトによっては、ドットを小数点ととしてあらわすところもあります。 もっとも有名な Linux Kernel では、Linux 1.0 に至るまでに、 "0.95", "0.96" ... "0.99" と番号が続きますが、 ドットが小数点ではないという規約は今や確固としたものとして確立され、 標準となっているはずです。 バージョン番号の構成要素(ドットを除いた数字の部分)の数に制限はありませんが、 殆どのプロジェクトでは3つか4つにとどめています。 その理由は後に明らかにしていきます。 数字の部分に加えて、 "Alpha" とか "Beta"( を参照してください) といった、 バージョンの状態を説明するラベルを付加するプロジェクトもあります。 たとえば次のようなものです。 Scanley 2.3.0 (Alpha) Singer 5.11.4 (Beta) Alpha や Beta といった識別子は、 同じバージョン番号ながら、 こうした識別子がつかないものが将来リリースされることを示しています。 よって、"2.3.0 (Alpha)" は結局 "2.3.0" になります。 このように、複数の最終リリースの候補となるものを一行であらわすために、 識別子そのものが メタ識別子 を持つことができます。 例として、一般の人が利用できるようになるまでの順番で、 一連のリリースを以下に示します。 Scanley 2.3.0 (Alpha 1) Scanley 2.3.0 (Alpha 2) Scanley 2.3.0 (Beta 1) Scanley 2.3.0 (Beta 2) Scanley 2.3.0 (Beta 3) Scanley 2.3.0 "Alpha" という識別子がついているときに、 Scanley "2.3" は "2.3.0" と記されていることに注意してください。 "2.3" と "2.3.0" は等しいものです。 — つまり、番号にくっついているゼロの部分は簡潔にするためにいつでも省略できます。— しかし、識別子があるときは、簡潔さはもはや問題ではありません。 よって、"2.3" という簡潔な記述ではなく、"2.3.0" と完全な形で表記する方がよいでしょう。 比較的よく使われる他の識別子には "Stable", "Unstable", "Development", そして "RC"(リリース候補 という意味)があります。 もっとも広く使われているのは 未だ "Alpha" と "Beta" で、 "RC" が3番目あたりの位置にきますが、 "RC" の後には常に数字のメタ修飾子が付くことに注意してください。 つまり、"Scanley 2.3.0 (RC)" をリリースするのではなく、 "Scanley 2.3.0 (RC 1)" をリリースしてから RC2 を、という具合です。 "Alpha", "Beta", "RC" という3つのラベルは今や広く知られているので、 たとえ他のラベルが、内輪の用語ではなく、 普通の用語だからという理由で一見よい選択のように見えても、 他のラベルを使うのはお薦めしません。 ソフトウェアをインストールする人々はこの3つのラベルに既に馴染んでいますし、 根拠無しに他のプロジェクトがやっていることと違ったことをする理由はありません。 リリース番号にあるドットは小数点ではありませんが、 数字の位置には重要な意味があります。 バージョン "1.0"(これはもちろん、"1.0.0" と等しいです) より前のリリースは全て "0.X.Y" というリリースです。 "3.14.158" のすぐ後は、"3.14.159" であって、 "3.14.160" や、"3.15.XXXXXX" などではないのです。 リリース番号を付ける一貫した決まりがあれば、 ユーザーは同じソフトウェアのふたつのリリース番号を見て、 数字だけでふたつの重要な違いを区別できるようになります。 3つの数字からなる典型的なリリース番号では、 はじめの数字は メジャー番号、 ふたつめは マイナー番号、 そして三つめは マイクロ番号 になります。 たとえば、バージョン "2.10.17" は 2番目のメジャーリリースシリーズのうち、 10番目のマイナーリリースラインであり、 そのライン上での17番目のリリースということになります。 "ライン" と "シリーズ" という言葉は、ここではくだけた使い方をしていますが、 文字通りの意味です。メジャーシリーズというのは、 単に同じメジャー番号を共有するリリース全てを指し、 マイナーシリーズ(またはマイナーライン)は、 同じメジャー番号 マイナー番号を共有する全てのリリースを指します。 つまり、"2.4.0" と "3.4.1" は "4" というマイナー番号は同じですが、 同じマイナーシリーズではありません。 一方、"2.4.0" と "2.4.2" は 、 "2.4.1" がそれらの間にリリースされる場合には隣り合うリリースにはなりませんが、 同じマイナーシリーズに属しています。 これらの数字の意味は、あなたが期待する通りの意味になります。 つまり、メジャー番号をひとつ増やすことは、大きな変更が行われたことを示しています。 マイナー番号をひとつ増やすことは、小さな変更が行われたことを意味しています。 そしてマイクロ番号をひとつ増やすことは、 本当につまらない変更が行われたということになります。 プロジェクトによっては、特にリリース間の違いをきめ細かく管理するために、 パッチ番号 と通常呼ばれる4番目の番号を追加しているところもあります。 (混乱しやすいのですが、"パッチ番号" を、 3番目のマイクロ番号と同じ意味で用いているプロジェクトもあります。) 最後の数字を ビルド番号 として用いるプロジェクトもあります。 ビルド番号はソフトウェアがビルドされるたびにひとつ増えていき、 ビルド以外の変更がないことをあらわしています。 ビルド番号はバグレポートを特定のビルド番号に結びつけるのに役立ちますし、 バイナリパッケージを通常配布しているプロジェクトで、恐らくもっとも役に立つでしょう。 いくつ数字を使うのか、それぞれの数字が何を意味するのかについては、 多くの異なる規約がありますが、その違いの多くはマイナー番号に関するものです。 — マイナー番号については裁量の余地がありますが、そう多くはありません。 次の2つのセクションでは、 もっとも広く使われている規約のうち、いくつかを議論します。 単純なやり方 ほとんどのプロジェクトには、たとえマイクロ番号をひとつ増やすだけの場合であっても、 どんな修正をリリースに取り込むかについてのルールがあります。 マイナー番号を増やす場合にはまた違ったルールがありますし、 メジャー番号を増やす場合はさらにルールが違います。 こうしたルールに決まった基準はありませんが、 複数のプロジェクトでうまく使われてきたルールをここで説明します。 あなたのプロジェクトでこのルールを単純に採用してもよいのですが、 たとえそうしなくても、これはリリース番号が伝える情報をうまく表現する見本になります。 このルールは、APRプロジェクトで使われているものです。 を参照してください。 マイクロ番号だけに影響する(つまり、 同じマイナーライン上で行う)変更は、 前方互換性と後方互換性の両方がなければなりません。 つまり、変更はバグ修正のみか、 既にある機能に対するわずかな改善にとどめるべきです。 新機能は、マイクロ番号を変更するリリースに取り込んではいけません。 マイナー番号に影響する(つまり、 同じメジャーラインで行う)変更には、 後方互換性がなければなりませんが、前方互換性は必ずしも必要ありません。 マイナー番号を変更するリリースでは、 新機能を取り込むのが普通ですが、 一度にたくさん取り込んだりはしません。 互換性を維持するには限度があります。 メジャー番号に影響する変更がその境目となります。 新しいメジャーリリースには前方互換性も後方互換性もありません。 メジャーリリースには新機能が含まれているはずですが、 全ての機能が新しくなっている場合さえあります。 後方互換性前方互換性 の正確な意味は、 ソフトウェアが実現することに依存しますが、解釈の余地がないのが普通です。 たとえば、あなたのプロジェクトがクライアント/サーバ アプリケーションを作っているとすると、 "後方互換性" とは、サーバを 2.6.0 にアップグレードしても 既にあるバージョン 2.5.4 のクライアントが以前と異なる振舞い(もちろんバグを直した場合は別です)をしたり、 動かなくなる機能があってはいけないということです。 一方、サーバを 2.6.0 にアップグレードすると同時に、クライアントも2.6.0にすると、 新しい 機能がクライアントで使えるようになるかもしれませんが、 2.5.4で使えていたクライアントの機能は 2.6.0 でどう扱われるかわかりません。 こういうことが起こると、このクライアントのアップグレードには 前方互換性が ない ことになります。 つまり、クライアントを 2.5.4 にダウングレードしても、 2.6.0 で使えていた全ての機能は使えないということになります。 なぜなら、2.6.0 の機能には新機能が含まれているからです。 こういうわけで、マイクロリリースは本来バグフィックスのためだけに存在します。 マイクロリリースでは前方、後方互換性の両方を維持しなければなりません。 つまり、2.5.3 から 2.5.4 にアップグレードしたあとで気が変わって 2.5.3 に戻したとしても、 特定の機能が失われてはいけません。 もちろん、2.5.4 で直したバグはダウングレードするとまた再現するでしょうが、 そのバグがあっても既に動いている機能が使えていれば、 機能が失われたことにはならないのです。 クライアント/サーバ 間のプロトコルは、 互換性の問題が起きる可能性がある分野のひとつです。 別の分野として、データフォーマットがあります。 ソフトウェアがデータを永続的なストレージに保存するでしょうか? もしそうなら、読み書きを行うフォーマットはリリース番号のルールで決まっている互換性のガイドラインに従う必要があります。 バージョン 2.6.0 は 2.5.4 が保存したファイルを読み込める必要がありますが、 2.5.4 が読めないフォーマットに黙ってアップグレードしているかもしれません。 なぜなら、マイナー番号をまたがるとダウングレードできる必要はないからです。 あなたのプロジェクトが他のプログラムで使われているライブラリを配布しているとすると、 その API も互換性の問題が起こる領域に入ります。 新しいバージョンに古いバージョンを置き換える形でアップグレードしても安全かどうか、 詳しいユーザーがわかるように、 ソース、バイナリレベルでの互換性に関するルールを詳しく説明しておかなければいけません。 詳しいユーザーは、バージョン番号をみれば互換性があるかどうかがすぐにわかるでしょう。 このしくみでは、メジャー番号を増やすまで過去のしがらみなしに再出発する機会はありません。 このため不便な状況になることもたびたびあります。 自分が本当に追加したいと思っている新機能があったり、 プロトコルを再設計したいと思ったとしても、互換性を維持している間はそう簡単にできません。 最初から拡張可能な方法で設計すること(このトピックに関しては一冊本を書く価値がありますし、 この本の範囲外でしょう)以外に、この問題に対する魔法の解は存在しません。 しかし、リリース間の互換性に関するルールを示し、 それを守ることはソフトウェアを配布するにあたって不可欠です。 不愉快な思いを一度させてしまうと、多くのユーザーが離れていってしまいます。 ここまで説明してきた互換性に関するルールは、 広く知られているだけでなく、まだそういったルールに馴染みがない人にも説明しやすく、 覚えてもらいやすいという点で優れています。 互換性に関するルールは、バージョン 1.0 以前には適用されないことが一般に知られています。 (しかし、はっきりさせておくために、 リリースポリシーではこのことを明示的に宣言しておくべきです) 開発の初期段階にあるプロジェクトは、 バージョン 0.1, 0.2, 0.3 といった順で、 1.0 の準備ができるまでリリースを行うことができますし、 リリース間の違いを適宜大きくすることができます。 バージョン 1.0 以前は、マイクロ番号を使うかどうかは任意です。 プロジェクトの性質とリリース間の差異によっては、 0.1.0, 0.1.1 といった番号があれば便利かもしれませんし、そうでないかもしれません。 バージョン 1.0 以前のリリース番号のルールはかなりルーズです。 これは互換性に関する制約をきつくすると初期段階の開発を著しく妨げることと、 早くから使っている人はどちらにせよ寛大な傾向にあることが主な理由です。 こうした制約は、3つの数字を使った番号の付け方にだけ当てはまります。 あなたのプロジェクトでは、3つの数字を使って、 これとは違った番号の付け方を簡単に思い付くでしょう。 もしくは、細かい粒度は必要ないので、 代わりに2つの番号を使おうと決めることもできるでしょう。 重要なのは、こういうことは早めに決めておいて、 それぞれの数字が意味するところを正確に皆に知らせ、それを守ることです。 奇数/偶数 に意味を持たせるやり方 プロジェクトによっては、 マイナー番号の 偶数/奇数 をソフトウェアの安定度を示すために使うことがあります。 つまり、偶数は安定版で、奇数は不安定版ということです。 これはマイナー番号にのみ当てはまることで、 メジャー番号とマイクロ番号には当てはまりません。 マイクロ番号をひとつ増やすことは、 バグフィックスが行われた(新機能はない)ことを示しますし、 メジャー番号をひとつ増やすことは、 大きな変更が行われたか、新機能が揃っていることをあらわしています。 数あるプロジェクトの中でも、 特に Linux Kernel プロジェクトで使われてきたこの仕組みの利点は、 製品版を使うユーザーが潜在的に不安定なコードの影響を受けることなく、 新しい機能をテスト用にリリースできることです。 ユーザーは、リリース番号から、 "2.4.21" は現在動いているWebサーバのマシンにインストールしていいが、 "2.5.1" は多分家のワークステーションの実験用に限るべきだろう、 ということがわかります。 開発チームは不安定版(マイナー番号が奇数のもの)に関するバグレポートを扱い、 不安定版でいくつかのマイクロ番号のリリースを重ねて安定してきたら、 マイナー番号をひとつ増やし(つまり、マイナー番号を偶数にします)、 マイクロ番号を "0" にリセットします。 そして恐らくは、安定版のパッケージをリリースしていくことになるでしょう。 この仕組みは少なくとも、以前説明した互換性のガイドラインと衝突しないことを保証します。 これはマイナー番号にいくらか追加情報を付加したものです。 これによって、他の仕組みよりマイナー番号がひとつ増える回数が2倍多くなりますが、 大きな害はありません。 奇数/偶数に意味を持たせる仕組みは、 リリースサイクルがとても長いプロジェクトでもっとも有効でしょうし、 プロジェクトの性質上、 新機能よりも安定性に重きを置く保守的なユーザーの割合が高いところでも有効です。 この仕組みが、新機能を大胆にテストする唯一の方法ではありません。 この章の後半の でも説明していますが、 潜在的に不安定なコードをリリースするもっと一般的な方法は、 ユーザーがリスクと利益のトレードオフをリリース名からすぐに把握できるように、 リリースにマークを付けることです。 リリースブランチ 開発者の視点から見ると、 フリーソフトウェアプロジェクトは継続してソフトウェアをリリースしている状態です。 開発者は通常、最新の利用可能なコードをいつも実行しています。 なぜならバグを発見したいですし、 最新だが機能として不安定な領域を避けつつ、 間近なところでプロジェクトの状態を追いかけているからです。 彼らは毎日ソフトウェアのコピーを更新していますが、 一日に一回以上更新することもあります。 よって変更をコミットするときは、 他の開発者も24時間以内にコミットした変更のコピーを入手すると期待できるのです。 では、プロジェクトはソフトウェアをどうやって正式にリリースすべきなのでしょうか。 ある時点のソースツリーのスナップショットを取得してパッケージにまとめ、 たとえばバージョン "3.5.0" として世界中に配布すべきなのでしょうか。 常識からいって答えはNOです。第一、開発ツリー全体が綺麗になっていて、 リリースの準備ができている瞬間なんて多分ありません。 開発を始めた新機能のコードが、様々な完成度でそこらじゅうに転がっているでしょう。 バグを直すために大きな変更をコミットする人もいますが、 その変更には議論の余地があり、スナップショットをとったときには議論中の場合もあります。 この場合、議論が終わるまでスナップショットの取得を遅らせるだけではうまくいきません。 なぜなら、別の関係ない議論がその間に始まってしまう可能性がありますし、 そうなると その議論も 終わるまで待たねばならなくなります。 このプロセスはいつ終わるのか保証できません。 とにかく、ソースツリーの完全なスナップショットを使ってしまうと、 たとえツリーをリリースできる状態にもっていけたとしても、 そのとき進行している開発を妨げてしまいがちです。 たとえば、現在のスナップショットを仮に "3.5.0" とし、 次のスナップショットが "3.5.1" になるとして、 "3.5.1" にはリリース 3.5.0 で見つかったバグの修正が殆ど含まれているとしましょう。 しかし、この両方のスナップショットが同じツリーにあると、 開発者はこのふたつがリリースされている間何をすべきでしょうか? 互換性に関するガイドラインがあるため、新機能を追加することはできません。 しかし、開発者全員が 3.5.0 のコードに入っているバグを熱心に修正するとは限りません。 新機能を完成させようとしている開発者もいます。 リリース作業がソースツリーを不自然な休止状態にする必要があるという理由だけで、 自分が興味がないことに取り組むか、 ぼけっとしているかを選ばねばならなくなったら、開発者は怒ってしまうでしょう。 こうした問題に対する解は、 いつも リリースブランチ を使うことです。 リリースブランチは、バージョン管理システムの単なるブランチ( を参照してください)です。 そこでは、リリースされることになっているコードが開発の本線から隔離されます。 リリースブランチの概念は、フリーソフトウェアプロジェクトで生まれたものではありません。 たくさんの商用ソフトウェアの開発チームもリリースブランチを使っています。 しかし、商用ソフトウェアの開発では、 リリースブランチは贅沢なものだと考えられることがあります — つまり、開発チームがメインツリーを安定させる作業を急いでいる間は、 大きな締切に追われて省略されてしまう一種の "ベストプラクティス" になってしまう可能性があるのです。 しかし、リリースブランチはオープンソースプロジェクトに不可欠なものです。 私はリリースブランチ無しでリリースを行っているプロジェクトを見たことがありますが、 いつもぼけっとしている開発者がいる一方で — 通常は少数の — 開発者がリリースを世に出すために働いていたのです。 これは複数の点で悪い結果をもたらしてしまいます。 まず第一に、開発全体の勢いが衰えてしまいます。 ふたつめに、リリースの質が必要以上に下がってしまいます。なぜなら、 開発者は2, 3人しか働いていませんし、 他の開発者が早く開発に復帰できるように急いで作業を終えようとしてしまうからです。 3つめは、異なった仕事が開発者同士を不必要に衝突させてしまうため、 開発者チームが精神的に分裂してしまうことです。 ぼーっとしている開発者は、自分達のスケジュールや興味に沿って行動を選べるのであれば、 リリースブランチに 少し 注意を向けるだけで多分幸せなのです。 しかしブランチがなければ、彼らが選べるのは "俺は今日リリース作業をやろうか、 それとも本線で開発している新機能の作業をしようか?" という二択ではなく、 "俺は今日プロジェクトに参加しようか、それともやめちゃおうか?" となってしまいます。 リリースブランチの使い方 リリースブランチを作る正確な手順は、 利用しているバージョン管理システムに依存しますが、 ほとんどのシステムでは、一般的な概念は勿論同じです。 ブランチは通常別のブランチか、trunk(幹)から派生します。 伝統的に、trunk では本線の開発が進んでおり、リリースの制限を受けません。 リリース "1.0" 用のはじめてのリリースブランチは trunk から派生します。 CVS では、ブランチを作成するコマンドは次のようになります。 $ cd trunk-working-copy $ cvs tag -b RELEASE_1_0_X Subversionでは、次のようにします。 $ svn copy http://.../repos/trunk http://.../repos/branches/1.0.x (これらの例はすべて、3つの数でリリース番号を付けるやり方を想定したものです。 それぞれのバージョン管理システムで使われる正確なコマンドを示すことはできませんが、 CVS と Subversion の例を示すことで、 他のシステムで対応するコマンドが予測できればいいなと思っています。) "1.0.0" ではなく、 (文字通り "x" という文字を使って)"1.0.x" ブランチを作成したことに注意してください。 これは同じマイナーライン — つまり、同じブランチということです — が全てのマイクロリリースで使われるということです。 リリースのためにブランチを安定させる実際のプロセスについては、 この章の後半の で説明しています。 ここでは、バージョン管理システムとリリースプロセスの関係にだけ注意を払うことにします。 ブランチが安定し、リリースの準備ができたら、 ブランチのスナップショットにタグを打つときです。 CVS では、次のようにします。 $ cd RELEASE_1_0_X-working-copy $ cvs tag RELEASE_1_0_0 Subversion では、次のようにします。 $ svn copy http://.../repos/branches/1.0.x http://.../repos/tags/1.0.0 このタグは 1.0.0 がリリースされた時点の、 プロジェクトのソースツリーの正確な状態を表しています。 (これはパッケージ化された配布物やバイナリが削除された後で、 古いバージョンを取得したい場合に役立ちます。) 同じリリースラインでの次のマイクロリリースは、 同じく 1.0.x ブランチ上で準備され、リリースの準備が出来次第、 1.0.1 のタグが打たれます。 1.0.2 に向けて繰り返しブランチを綺麗にしていきましょう。 1.1.x リリースラインについて考え始める時期が来たら、 新しいブランチを trunk から作ります。 CVS では、次のようにします。 $ cd trunk-working-copy $ cvs tag -b RELEASE_1_1_X Subversion では、次のようにします。 $ svn copy http://.../repos/trunk http://.../repos/branches/1.1.x メンテナンスは 1.0.x と 1.1.x ラインに対して並行して続けられ、 リリースは両方のラインから独立して行えます。 実際、ふたつの異なったラインからほとんど同時にリリースが行われることも珍しくありません。 古いラインからのリリースは、 一気に(たとえば)1.1 へバージョンアップしたいときは、 必ず周到な準備をしたいと望む保守的なサイト管理者にお薦めです。 一方で大胆なユーザーは通常、 不安定なバージョンであるというリスクを負ってでも、 必ず最新の機能を使うために、 より新しいラインの最新のリリースを採用します。 ここで説明したことが、リリースブランチの唯一の使い方ではありません。 自分が参加していたプロジェクトではとてもうまくいっていたのに、 ある状況下ではうまくいかないことがあるかもしれません。 うまくいきそうなやり方を使ってください。 しかし、以下の点は重要なので覚えておきましょう。 つまり、リリースブランチの目的は、 日々の開発作業によって生まれる変化からリリース作業を分離することと、 リリース作業を組織的に行うために、 物理的な作業スペースをプロジェクトに与えることです。 このプロセスは次のセクションで説明します。 リリースを安定させるプロセス リリースを安定させるプロセス とは、 リリースブランチをリリースできる状態に持っていく作業です。 つまり、どの変更をリリースに含めるか、含めないかを決定し、 その方針に従ってブランチを整備することです。 この "決定" という言葉には、厄介なことがたくさん含まれています。 リリース直前に新機能がたくさん出てくるのは、 協調的なソフトウェアプロジェクトでは日常茶飯事です。 開発者はリリースが近いことを知ると、 それに乗り遅れまいとして大急ぎで変更作業を終えようとします。 これは勿論、リリースするときにはまさに起こって欲しくないことです。 開発者は自分の好きなペースで新機能を実装していればいいのであって、 自分の変更が今回、または次のリリースに含まれるかどうかは心配しない方がいいのです。 ひとつのリリースに多くの変更を直前に詰め込もうとすればするほど、 コードは不安定になり、(普通)多くのバグが発生してしまうのです。 ほとんどのソフトウェアエンジニアは、 リリースを安定化する過程でどの変更をリリースに取り込むべきかについて、 おおまかな点で一致しています。深刻なバグ、 特に回避しようがないバグの修正は含めていいでしょう。 ドキュメントの更新も含めていいでしょうし、エラーメッセージの修正(但し、それがインターフェイスの一部と考えられていて、 安定していなければいけない場合は別です)も同様です。 多くのプロジェクトでは、リスクが低いか、コアに影響しない変更も受け入れますし、 リスクを測るための正式なガイドラインもあるでしょう。 しかし、どんな基準があったとしても人間の判断は必ず必要です。 変更をリリースに取り込むか否かをプロジェクトが決めなければいけないのは日常茶飯事でしょう。 危険なのは、開発者それぞれが自分の変更をリリースに含めたいと思っているので、 変更を受け入れることを望む人は多いのに、それに対して NO という人が少ないことです。 そういうわけで、リリースを安定化させるプロセスは、 ほとんどが "NO" と言う仕組みを作ることと同じです。 オープンソースプロジェクトに特有なのは、 開発者を傷つけたり、がっかりさせることなく "NO" といいつつ、 価値がある変更はリリースに取り込むようにする方法に知恵を絞っていることです。 たくさんの方法がありますが、いったん開発チームがそれらを重要な基準として注目すれば、 基準を満たす仕組みを作るのは簡単です。 ここではもっとも人気のある、両極端なやり方をふたつ簡単に説明しますが、 二つだけにすることで、プロジェクトが創造性をなくしてはいけません。 他のやり方はたくさんあるでしょうから、 私が実際に使われているのを見たことがあるふたつだけに留めておきます。 リリースオーナーによる独裁 開発者グループは特定の人物がリリースオーナーになることに同意します。 リリースオーナーはどの変更をリリースに取り込むかを決める最終的な権限を持ちます。 勿論、それについては通常議論が行われますし、期待されていますが、 開発者グループは結局、リリースオーナーに最終的な決断を行うための十分な権限を与えなければなりません。 この仕組みがうまく機能するには、加えられた全ての変更を理解できる卓越した技術力を持ち、 社会的にうまくやっており、多くの人を傷つけずにリリースにもっていけるよう議論を導くコミュニケーション能力がある人を選ばなければいけません。 よくあるのは、"この変更は間違ってないけど、テストをする十分な時間がとれていない。 だから、今回のリリースに含めるべきではない。" というものです。 これは、リリースオーナーがプロジェクトに関連した技術の知識を広く持っている場合に大いに役立ちますし、 その変更が潜在的にコードを不安定にする(たとえば、ソフトウェアの他の部分に与える影響や、移植性に関することなど)理由を得ることができます。 場合によっては、リリースオーナーの決定が正しいことを証明せよという人や、 見た目ほどその変更はリスキーでないと主張する人も現れます。 リリースーオーナーは、こうした主張のすべてが自分の決定に反対しているか、 反対に固執しているわけではないと判断できれば、 こうした主張に真正面からぶつかる必要はありません。 プロジェクトリーダーがリリースオーナーになる必要はないことに注意してください。 (そもそもプロジェクトリーダーがいる場合は、 を参照してください) 実際、プロジェクトリーダーとリリースオーナーは兼任 しない ほうがよいことがあります。 優れたプロジェクトリーダーになるのに必要なスキルは、リリースオーナーになるのに必要なそれと同じではありません。 リリースプロセスと同じくらい重要な局面では、 誰かがプロジェクトリーダーの判断を相殺するくらいの方が賢いかもしれません。 この章の後半にある で説明するリリースマネージャーは、 リリースオーナーとは対照的に独裁的ではありません。 リリースに含める変更を投票で決める リリースオーナーの独裁と正反対のやり方ですが、 開発者はどの変更をリリースに取り込むかを投票することができます。 しかし、リリースの安定化するプロセスで一番重要なのは変更を除外することなので、 複数の開発者が積極的に賛成した変更をリリースに取り込めるように投票システムを設計することが重要になります。 変更をリリースに取り込むには、過半数以上の賛成が必要とすべきです() を参照してください)。 別のやり方として、一人が賛成し、他の人が反対しなければ十分という考え方もあるでしょうが、 不幸な政治力学によって、各々の開発者は自分が加えた変更に賛成票を投じるが、 報復を恐れて他の開発者の変更には反対票を投じたがらなくなるという状況が生まれます。 これを避けるには、開発者達にあらゆる変更をリリースに取り込めるよう協力して行動させるように、システムを変えるべきです。 これは多くの開発者が個々の変更をレビューするだけでなく、 それぞれの開発者が変更に対して反対票をためらわずに投じることも意味します。 なぜなら、自分の意見とは反対の票を投じる人が、自分を侮辱していると思う人はいないからです。 参加する人が多くなればなるほど、個人に関する議論ではなく、 変更に関する議論が多く行われるようになります。 Subversion プロジェクトで使われているシステムは、 うまくバランスがとれているようなので、私はここでそれをお勧めします。 ある変更をリリースブランチに適用するには、 少なくとも3人の開発者が賛成しなければならず、反対する人がひとりもいてはいけません。 "反対" の票がひとつでもあれば、リリースに含めるのを止めるのに十分です。つまり、 リリースにおける "反対" 票は拒否権と同じになります( を参照してください)。 当然のことですが、この手の反対票を投じるには正当な理由がなければなりませんし、 理屈の上では十分多くの人が不当だと感じれば覆すことができますし、 特別な投票があっても同様です。実際、こんなことは決して起こりませんし、 起こって欲しくもありません。どちらにせよ人々はリリースに対しては保守的ですし、 誰かがある変更をリリースに含めることに拒否権を投じたいと強く感じるときは、 普通は十分な理由があるときです。 リリースの手続きはわざと保守主義に偏っているので、 正当な理由が付けられた反対票は、技術的というより手続き的に扱われることがあります。 たとえば、ある変更はよく書かれていて、バグは起こさないだろうけど、 マイクロリリースに含めるには変更の規模が大きいからという理由で反対票を投じる人がいるかもしれません。 — 多分その変更は新機能を加えるものか、 微妙な点で互換性のガイドラインに完全に準拠していないのでしょう。 ある変更にもっとテストが必要だと直感で思ったという理由で反対票を投じる開発者を見たことがありますが、 綿密に調べても何のバグも見付けられなかったのです。 開発者たちはちょっと不平をいいましたが、反対票は有効なまま、 その変更はリリースに含められなかったのです。 (ですが、後のテストでバグが見付かったかどうかを私は覚えていません) リリースを安定させるプロセスを管理する プロジェクトで投票システムを変える選択をした場合、 投票用紙や決選投票を行う物理的な仕組みをできるだけ便利にすることが求められます。 たくさんの電子投票システムがオープンソースで公開されていますが、 実際もっとも簡単なのは、 リリースブランチに STATUS または VOTES といったテキストファイルを用意することです。 このファイルは提案されている変更を一覧にしています。— 開発者であれば誰でも変更をリリースに取り込むよう提案することができます。 — このファイルには、全ての投票と、それに対する賛成、反対意見、それに加えてあらゆるメモ、そしてコメントが書き込まれています。 (ところで、変更を提案することは、 必ずしもその変更に賛成票を投じているというわけではありません。しかし、 そのふたつは同時に行われることがよくあります。) こうしたファイルのエントリは、次のようになるでしょう。 * r2401 (問題 #49) クライアント/サーバのハンドシェイクが2度行われるのを避ける。 変更する理由: 余計なネットワークのターンアラウンド時間を減らす。変更の規模は小さく、レビューしやすい。 メモ: これについては http://.../mailing-lists/message-7777.html 及びこのスレッドにある他のメッセージで議論された。 投票: +1: jsmith, kimf -1: tmartin (バージョン 1.0以前のサーバとの互換性が壊れてしまう。 確かに、1.0以前のサーバはバグが多いが、だからといって 何故必要もないのに互換性を壊すのか?) この場合、提案された変更は賛成票を2つ得ていますが、 tmartin によって拒否権を行使されています。 tmartin は括弧つきのメモで拒否権を行使した理由を述べています。 正確なフォーマットは問題ではありません。 つまり、プロジェクトでどのように決めてもよいのです — 多分、 tmartin が拒否権を行使した理由は "メモ:" のセクションに移すか、 変更の理由は他のセクションに合わせて "説明:" ヘッダをつけるべきでしょう。 重要なのは、変更を評価するのに必要な全ての情報を到達可能にしておくことと、 決選投票をする仕組みをできるだけ簡単にしておくことです。 提案されている変更はリポジトリのリビジョン番号で参照します。 (今回の場合は、単一のリビジョン r2401 ですが、複数のリビジョンでも簡単にできます) リビジョン番号は、trunk に加えられた変更を参照することが想定されています。 既にリリースブランチに変更が加えられている場合は、投票する必要はないでしょう。 もしバージョン管理システムが個々の変更を参照する明示的な文法を持ってない場合は、 プロジェクトが作るべきです。投票を実効性のあるものにするためには、 対象となる各々の変更は曖昧でない状態で識別できなければならないのです。 こうした変更の提案、もしくは投票の対象になる変更は、 必ずリリースブランチに綺麗に適用できなければなりません。つまり、 衝突せずに適用できるということです( を参照してください) もし衝突がある場合は、綺麗に適用するよう調整したパッチか、 変更を調整したバージョンを格納した一時ブランチを投票のエントリに記述すべきです。 たとえば次のようなものです。 * r13222, r13223, r13232 libsvn_fs_fs の自動マージアルゴリズムを書き直した 変更する理由: 30万リビジョンが格納されたリポジトリのパフォーマンスが許容できない (小さなコミットをしても50分以上かかる) 変更を加えたブランチ: 1.1.x-r13222@13517 投票: +1: epg, ghudson この例は実在のプロジェクト、 つまり Subversion 1.1.4 のリリースプロセスで作られた STATUS ファイルから引用したものです。 変更が起こした衝突を調整したブランチがあるにもかかわらず、 オリジナルのリビジョンを、どうやって変更を表現する規則的な名前にしているかに注意してください。 (そのブランチも、変更をリリースにマージするのを容易にするために3つのtrunkリビジョンを r13517 というリビジョンにまとめていますが、これは許されるはずです) この例にはオリジナルのリビジョンが記述されています。 なぜなら、ログメッセージが残っているので、もっともレビューしやすいからです。 一時的なブランチにはそうしたログメッセージはないでしょう。 情報の重複を避けるため( を参照してください)、 ブランチのログメッセージは"r13222, r13223, r13232 を 1.1.x ブランチ用に調整した" と簡単にすべきでしょう。 変更に関する情報は全てオリジナルのリビジョンから追いかけることができます。 リリースマネージャー リリースに取り込む変更を実際にリリースブランチにマージする( を参照してください)プロセスは、開発者であれば誰でもできます。 変更をマージする専門の人を置く必要はありません。もし変更がたくさんあれば、 マージする負担を分散させた方がよいかもしれません。 投票することと変更をマージすることは別々に行われますが、 実際にはリリースプロセスを指揮する人がひとりかふたりはいます。 この役割を正式に リリースマネージャー と呼ぶことがありますが、 どの変更を取り込むかに関する最終的な決定権があるリリースオーナー(この章のはじめの方の を参照してください)とは全く別物です。 リリースマネージャーは、リリースに取り込む候補になる変更の数や、 実際に取り込まれた変更の数、そして取り込まれる可能性が高い変更の数などを追いかけています。 重要な変更に対して開発者が十分に注意を払わず、 投票もされずに放置されるかもしれないとリリースマネージャーが感じた場合、 彼らは他の開発者に小言を言ってレビューや投票をするよう促します。 リリースに取り込む変更がたまってきたら、 リリースマネージャーが引き取ってまとめてリリースブランチにマージすることもあります。 変更を明示的にコミットする以外の仕事を全て彼らにやらせる必要はないと理解しているのなら、 他の開発者がそうした仕事をリリースマネージャーに任せられるのはよい状態です。 リリースを世に出す時がきたら(この章の後半の を参照してください)、 リリースマネージャーは最終的なリリースパッケージを作成したり、 デジタル署名を集めたり、パッケージをアップロードしたり、 公式にアナウンスを出す作業に注意を払います。 パッケージング フリーソフトウェアを配布する標準的なやり方は、ソースコードを配布することです。 これはソフトウェアがソースコードをそのまま実行できる(i.e. Perl, Python, PHP などのように、 インタプリタによって解釈できるもの)か、 はじめに(C, C++, Javaなどによって)コンパイルする必要があるかどうかに関わらず当てはまります。 コンパイルする必要があるソフトウェアの場合、 ほとんどのユーザーが多分自分でソースをコンパイルせず、 あらかじめビルドされたバイナリパッケージをインストールするでしょう。 (この章の後半にある を参照してください) しかしながら、バイナリパッケージはオリジナルのソースコードを元にして作られています。 ソースパッケージで重要なのは、曖昧でない形でリリースを定義していることです。 プロジェクトが "Scanley 2.5.0" を配布する場合、それが特に意味するところは "コンパイルして(必要であれば)インストールすると、Scanley 2.5.0 を生成するソースファイルのツリーである" ということです。 どういう形でソースファイルをリリースすべきかについては、かなり厳格な基準があります。 基準から外れた部分も時折見つかるでしょうが、それはルールではなく例外です。 やむを得ない理由がなければ、あなたのプロジェクトでもこの基準に従うべきです。 パッケージのフォーマット ソースコードはディレクトリツリーを保存してくれる標準的なフォーマットでリリースすべきです。 Unix または Unixライクなオペレーティングシステムでは、 compress コマンドや、gzipbzip または bzip2 コマンドを使って圧縮した TAR フォーマットを使うという決まりがあります。Microsoft Windows では、 ディレクトリツリーを保存した状態で配布する標準的なやり方として zip フォーマットを使う方法があります。これはたまたま圧縮もしてくれるので、 アーカイブを作った後に圧縮を行う必要がありません。 TAR ファイル TAR とは、"Tape ARchive" を略したものです。 なぜなら、tar フォーマットはディレクトリツリーを磁気テープに保存するのに理想的な直列のデータストリームとして表現するからです。 また、この性質ゆえにディレクトリツリーを単一のファイルとして配布することが標準となっています。 圧縮された tar ファイル(またはtarボール)を提供するのは非常に簡単です。 システムによっては、tarコマンド自体が圧縮済みのtarボールを生成するものもありますし、 圧縮するのにtarコマンドとは別のコマンドを使うシステムもあります。 パッケージ名とレイアウト パッケージの名前は、ソフトウェアの名前とリリース番号の後で、 アーカイブのやり方に合った適切なフォーマットの拡張子を最後につけるようにしましょう。 たとえば、Scanley 2.5.0 を Unix向けにパッケージングし、 GNU Zip(gzip) フォーマットで圧縮したときの名前は次のようになるでしょう。 scanley-2.5.0.tar.gz また、Windows 向けに zip フォーマットで圧縮した場合の名前は次のようになるでしょう。 scanley-2.5.0.zip どちらのアーカイブを展開しても、 カレントディレクトリに scanley-2.5.0 という名前の単一のディレクトリツリーが生成されるはずです。 このディレクトリには、ソースコードを(必要なら)コンパイルし、 インストールできる状態でソースコードを配置すべきでしょう。 ディレクトリツリーの最上部には、このソフトウェアが何をするもので、 今回のリリース内容がどういうものか、 そしてプロジェクトのWebサイトやその他面白いファイルなどのリソースについて説明した README ファイルをプレーンテキストで配置します。 他の面白いファイルとしては、README ファイルの兄弟分にあたり、 サポートする全てのオペレーティングシステム上でソフトウェアをビルドし、 インストールする方法を説明した INSTALL ファイルがあげられます。 でも説明していますが、 ソフトウェアの配付条件を示した COPYINGLICENSEファイルもツリーの最上部に配置します。 今回のリリースで新しくなったことを説明する CHANGES (NEWS と呼ばれることもあります) ファイルもツリーの最上部に配置します。 この CHANGES ファイルは、 これまで行われたリリース全ての変更点を集めたもので、 今回のリリースの変更点の一覧が一番最初になるように、 リリースされた順番とは逆順に記されています。 この変更点一覧を完成させるのは、 リリースブランチをリリースできる状態にする作業の最後に行うのが普通です。 開発している間に少しずつ変更点を書き足していくプロジェクトもあれば、 バージョン管理システムのログを組み合わせることで情報を集め、 最後にひとりの人間がまとめるまで作業を保留するのを好むプロジェクトもあります。 変更点の一覧は、次のようになるでしょう。 Version 2.5.0 (2004年12月20日に /branches/2.5.x からリリース) http://svn.scanley.org/repos/svn/tags/2.5.0/ 新機能、改良点: * 正規表現による問い合わせを追加 (問題 #53) * UTF-8 と UTF-16 で書かれたドキュメントのサポートを追加 * ドキュメントが ポーランド語、ロシア語、マダガスカル語に翻訳された。 * ... バグ修正: * 再インデックス時のバグを修正 (問題 #945) * 問い合わせに関するバグをいくつか修正 (問題 #815, #1007, #1008) * ... 変更点の一覧は、必要であればどれだけ長くても構いませんが、 小さなバグ修正や機能追加を全て含めてしまうことで、内容が退屈にならないようにしましょう。 このファイルの目的は、新しいリリースにアップグレードすることで得られるものの概要をユーザーに示すだけです。 実際、変更点の一覧はリリースアナウンスの電子メールに書くことが普通なので、 それを見る人のことを考えて書くようにしましょう。 CHANGES ファイルと ChangeLog ファイル 伝統的に ChangeLog ファイルは、 プロジェクトでこれまで行われたあらゆる変更を一覧にします。 — つまり、バージョン管理システムにコミットされた全てのリビジョンです。 ChangeLog ファイルには様々なフォーマットがあります。 どんなフォーマットでも同じ情報が含まれているので、 フォーマットの詳細はここでは重要ではありません。 その情報とは、変更日、変更した人、変更に関する簡単な要約(または単にその変更のログメッセージ)です。 CHANGES ファイルは違います。 このファイルは変更点を一覧にするだけでなく、 ある人達が見て重要だと思われるものも一覧に加えます。 そして正確な変更日や変更した人のようなメタデータはよく省略されます。 混乱を避けるため、CHANGES と ChangeLog ファイルを同じ意味で使わないでください。 プロジェクトによっては、"CHANGELOG" ではなく、 "NEWS" というファイル名を使うところもあります。 こうすることで "ChangeLog" との混同は避けられますが、 この名前はぴったり来る名前ではありません。なぜなら、 CHANGES ファイルは全てのリリースの変更点を保持しているので、 先頭に書いてある最新のニュースに加えて、 たくさんの古いニュースも掲載することになるからです。 ChangeLog ファイルは、どちらにせよ徐々に消えつつあるものかもしれません。 このファイルはCVSがバージョン管理システムの唯一の選択肢だった時代には役に立つものでした。 なぜなら、CVSでは変更点の情報が展開しにくかったからです。 しかし、最近のバージョン管理システムを使うと、 ChangeLogで保存されていたデータは、 バージョン管理システムのリポジトリに要求することでいつでも引き出すことができます。 これによって、プロジェクトが変更点を静的なファイルに保存する意味がなくなります。 — 実際には、リポジトリに保存されたログメッセージは、 ChangeLog ファイルの内容と重複するだけなので、もっと無意味なことが起こります。 ツリーにあるソースコードのレイアウトは、 バージョン管理システムのリポジトリから直接プロジェクトをチェックアウトしたときに得られるものと同じか、 できるだけ似たものにすべきです。 これらの間には少し違いがあるのが普通です。 たとえば、リリースされるパッケージには設定やコンパイルに必要な自動生成されたファイル(この章の後半の を参照してください) が含まれていたり、 プロジェクトが管理していないが、必須のものであったり、 ユーザーがまだインストールしていないかもしれないサードパーティーのソフトウェアが含まれているからです。 しかしながら、たとえ配布されたディレクトリツリーが、 バージョン管理システムのリポジトリにある開発ツリーと全く同じだったとしても、 その配布物は作業コピーと同じであってはいけません( を参照してください)。 あるリリースは、開発ツリーへの静的な参照ポイントです。 — これは特に、ある時点の固定されたソースファイルの設定 を表したものです。 もし配布物が作業コピーと同じだと、ユーザーがそれを変更するかもしれません。 また、実際に変更した後でリリースがあることを考えると危険です。 パッケージの中身は、パッケージングのやり方に関わらず同じであることを忘れないでください。 リリース—つまり、"Scanley 2.5.0" と呼ぶ場合に参照する正確なものは、 zipやtarボールを展開したときに生成されるディレクトリツリーと同じです。 よって、プロジェクトはこれら全てのフォーマットをダウンロード用に提供しても構いません。 scanley-2.5.0.tar.bz2 scanley-2.5.0.tar.gz scanley-2.5.0.zip しかし、パッケージを展開して生成されるソースツリーは全て同じでなければなりません。 このソースツリーは配布物です。つまり、ダウンロードするパッケージのフォーマットは、 ユーザーの便宜のためだけに存在します。 ソースパッケージにちょっとした違いがあっても許される場合があります。 たとえば、Windows用のパッケージでは、 テキストファイルの行はCRLF(キャリッジリターンとラインフィード)コードで終わるべきです。 一方でUnix用のパッケージでは、LFで終了します。 仮に異なったオペレーティングシステム間で違うコンパイル用のレイアウトが必要なら、 異なったオペレーティングシステム用のソースパッケージでは、 ソースツリーが少し異なっていても構いません。 しかし、こうした違いは基本的にちょっとした変換で済ませるものです。 基本的なソースファイルは、同じリリースのパッケージの範囲では同じにしておくべきです。 大文字にするか、小文字のままにするか プロジェクトの名前を引用する場合、普通は適当な名詞を大文字にし、 もし頭文字だけを大文字にする単語があれば、そのようにします。 たとえば "MySQL 5.0", "Scanley 2.5.0" などです。 大文字の表現をパッケージ名でも使うかどうかは、プロジェクトによって異なります。 たとえば、Scanley-2.5.0.tar.gzscanley-2.5.0.tar.gz のどちらがよいか、ということです。(私は後者が好きです。 なぜなら、シフトキーを人に打たせるのが嫌だからではなく、 大文字を使うパッケージをたくさんのプロジェクトに出荷させることになるからです) 重要なのは、tarボールを展開したときに作られるディレクトリが同じ名前を使っているかどうかです。 ユーザーを驚かせないようにすべきです。つまり、配布物を展開して生成されるディレクトリ名は、 ユーザーが正確に予測できるようにしておかなければなりません。 プレリリース版 プレリリース版またはリリース候補のパッケージをリリースする場合は、 その識別子はリリース番号の一部になります。 よって、パッケージ名にその識別子を含めるようにしましょう。 たとえば、 で説明したアルファ版やベータ版のリリースの順番は、パッケージ名では以下のように表現します。 scanley-2.3.0-alpha1.tar.gz scanley-2.3.0-alpha2.tar.gz scanley-2.3.0-beta1.tar.gz scanley-2.3.0-beta2.tar.gz scanley-2.3.0-beta3.tar.gz scanley-2.3.0.tar.gz はじめのパッケージは、scanley-2.3.0-alpha1というディレクトリに展開され、ふたつめは scanley-2.3.0-alpha2 に展開される ... などです。 コンパイルとインストール ソースコードをコンパイルし、インストールを行う必要があるソフトウェアは、 経験豊富なユーザーが従う標準的な手順があります。 たとえば、C, C++, その他のコンパイル言語で書かれたプログラムでは、 Unixライクなシステムでユーザーがタイプする標準的な手順は次のようなものです。 $ ./configure $ make # make install はじめのコマンドは、自動的に実行環境をできるだけ把握し、ビルドの準備を行います。 ふたつめのコマンドはソフトウェアをビルドします。(しかしインストールは行いません) 最後のコマンドはシステムにソフトウェアをインストールします。 最初のふたつのコマンドは通常のユーザーで実行し、最後はrootユーザーで実行します。 このシステムをセットアップする作業の詳細は、Vaughan, Elliston, Tromey, Taylor が書いた GNU Autoconf, Automake, and Libtool という優れた本があるので、それを参照してください。 この本は 出版社 New Riders によってツリーウェアドキュメントやその他の印刷物を指すハッカー用語として公開されており、 でもオンラインで利用可能です。 この手順が唯一の標準というわけではありませんが、 もっとも普及しているもののひとつです。 Ant () ビルドシステムが特にJavaで書かれたプロジェクトで人気を得つつありますが、Antもビルドとインストールの標準的な手順を持っています。 同様に、PerlやPythonのようなプログラミング言語では、 その言語で書かれた殆どのプログラムで同じ手順を使うことを勧めています(たとえば、Perlモジュールは次のようなコマンドを使います。 perl Makefile.PL) 自分のプロジェクトにどの標準を使うかがわからない場合は、 経験豊富な開発者に尋ねてみましょう Python では python setup.py install という、Distutils を使った標準的なコマンドがあります。Ruby の場合は Rubygems 経由で gem install [パッケージ名] というコマンドを使います。。 たとえどの標準を使うかがはじめわからなくても、 適用できる標準が 存在する と思っても大丈夫です。 自分のプロジェクトに適した標準が何であれ、 やむを得ない場合以外はそれを破ってはいけません。 標準的なインストール手順は、たくさんのシステム管理者が反射的に実践しているものです。 プロジェクトの INSTALLファイル に自分が馴染んだ手順が書かれているのがわかれば、 このプロジェクトは標準的な規約を守っているという信頼をすぐに得られます。 標準的な手順をドキュメントに記すことで、他のことも理解しやすくなるでしょう。 また、 でも議論していますが、 標準的なビルド手順があると、開発者になる可能性がある人も喜んでくれます。 Windows では、ビルドとインストールの標準的な手順がUnixライクなシステムほど決まっているわけではありません。 コンパイルする必要があるプロジェクトでは、 Microsoft の標準的な開発環境(Developer Studio, Visual Studio, VS.NET, MSVC++, など)の ワークスペース/プロジェクトモデルに合った形でソースツリーをリリースすることが標準的な規約のようです。 ソフトウェアの性質にもよりますが、Cygwin環境()経由でUnixライクなビルドオプションを提供することもできるでしょう。 もちろん、自前のビルドとインストール手順があるプログラミング言語やフレームワーク—e.g Perl や Python のような— があるときは、 環境が Windows, Unix, Mac OS X, あるいは他のオペレーティングシステム上であっても、 それが提供している標準的な手順を採用すべきです。 標準的なビルド、インストール手順にプロジェクトを合わせる努力を惜しまないようにしましょう。 ビルドとインストールはソフトウェアを使う入口となる作業です。 それを終えたら、やむを得ないならソフトウェアが扱いにくくてもよいのです。 しかし、ユーザーや開発者がソフトウェアに触れる最初の段階で、 予想外の手順を踏む必要があるなら、それは恥ずかしいことなのです。 バイナリパッケージ ソースコードをパッケージングしてリリースするのが正式なやり方ですが、 ほとんどのユーザーは、オペレーティングシステムのソフトウェア配布システムや、 プロジェクト自体や、サードパーティーから取得したバイナリパッケージをインストールします。 ここでいう "バイナリ" というのは必ずしも "コンパイルして生成したもの" という意味ではありません。 ここでは単に、ソースコードをビルドしてインストールする手順を経ずに、 コンピューターにインストールすることができる設定済みのパッケージのことをいいます。 RedHat GNU/Linux では、その仕組みはRPMシステムと呼ばれ、Debian GNU/Linux では、 APT (.deb) システムといいます。Microsoft Windows では、 .MSI ファイル や、実行すればインストールを行ってくれる .exe ファイルであることが普通です。 バイナリパッケージを作る人がプロジェクトに深く関わっている人であれ、 サードパーティーであれ、 ユーザーはそれらをプロジェクトの公式なリリースとして扱い、 バイナリパッケージの振る舞いをベースにしてバグ報告システムに問題を登録してきます。 よって、パッケージャーに明確なガイドラインを提供し、 彼らが提供するパッケージが、 プロジェクトのソフトウェアを適切に表現してくれるように、 彼らと緊密に連携することがプロジェクトの関心事になります。 パッケージャーが主に知っておくべきことは、生成するバイナリパッケージは、 プロジェクトからリリースされたオフィシャルなソースコードを元にすべきだということです。 ユーザーにバグ修正や機能追加を提供するために、 パッケージャーはソースコードリポジトリのコピーや、 リリース後にコミットされた修正を選んでバイナリパッケージに取り込むことがあります。 しかしこうした習慣は、実際には多くの混乱を引きおこします。 プロジェクトはリリース済みのバージョンで見つかったバグ報告や、 最近の trunk や主要なブランチのソースコードのバグ報告(つまり、 注意深く最先端のコードを実行している人が見つけたバグ)を受け付ける準備をしています。 バグ報告があがってくると、 応答する人はそのバグがある時点のスナップショットで発生したということや、 修正済みであること、そしてユーザーがアップグレードすべきか、 次のリリースを待つべきかを確認することができます。 仮にまだ報告されていないバグの場合は、 リリースの時点が明確であれば、 それの再現やバグ報告システム上でのバグの分類もやりやすくなります。 しかしながら、ユーザーが改造を加えたものや、 バージョンが決まっていない中間的なコードに対するバグ報告は、 プロジェクトは受け付ける準備ができていません。こうした報告は再現させるのが難しく、 後の開発で加えられる別の変更に予想外の影響を与える可能性もあります。 このため、開発者が責任を取る必要がない不正な振舞いをソフトウェアが起こしてしまうのです。 過去に発生していたはずのバグが 発生しなくなってしまった ために、 多くの時間を浪費してしまってげんなりしたことがあります。 これはユーザーが公式のリリース(全く同じではない)にちょっと改造を加えたバージョンを使っていたためです。 バグが発生しなかったのが予想外だったので、 開発者全員がその理由を調べるために詳細な調査をしなければなりませんでした。 さらに、リリースされたソースコードには変更が必要だとパッケージャーが主張することもあります。 パッケージャーは、プロジェクトの開発者にこうした変更を報告し、変更の計画を説明すべきです。 パッケージャーが加えた変更は、開発者が受け入れてくれるかもしれませんが、 受け入れてもらえなくても、自分がソースコードに変更を加える理由をプロジェクトに知らせておくべきです。 これは、プロジェクトが予想外のバグ報告を見張ることができるようにするためです。 開発者はプロジェクトのウェブサイトに免責事項を記載することで、 こうしたバグ報告に対応してもよいでしょう。また、バイナリパッケージのユーザーに、 自分たちが使っているパッケージがプロジェクトが公式にリリースしたものとは正確に同じものではないことを知らせるために、 適切な場所で作業をするようにパッケージャーに求めることもできます。 こういう状況で、パッケージャーと開発者がいがみ合う必要はありませんが、 残念なことに対立してしまうこともあります。 パッケージャーは、目指すものが開発者と少し違うだけなのです。 パッケージャーはユーザーがインストールすればすぐに使えるものを主に求めています。 開発者ももちろんそれを追求してはいますが、彼らは一貫したバグ報告を受付け、 互換性を保証するためにパッケージャーが使っているバージョンを知らなればいけません。 このふたつの目標はたびたび対立します。対立が起きたときには、 プロジェクトはパッケージャーを拘束していないし、パッケージャーと開発者は、 持ちつ持たれつの関係にあることを思い出すとよいでしょう。 プロジェクトは、ソフトウェアを作るだけであっても、 パッケージャーにとって良いことをしているのは事実です。 しかし、パッケージャーもユーザーにソフトウェアを広めるために地道な作業のほとんどをこなすことで、 開発者にとってよいことをしているのです。この作業は、とてつもない数のユーザーを対象にすることもあります。パッケージャーに反対の意思を示すのはよいことですが、喧嘩をしてはいけません。 開発者は自分が出せる最良のソフトウェアを世に送り出すことのみに注力すればよいのです。 テストとリリース 安定版のリリースブランチから、ソースコードのtarボールがいったん作成されると、 正式なリリースの手続きが始まります。しかし、tarボールを世界中で利用できるように する前にはテストを行い、最低限の、通常は3人以上の開発者からリリースしてよいとの同 意をもらっておくべきです。この手続きは、明らかな欠陥を探すために単にリリースを調 べることではありません。理想を言えば、開発者がtarボールをダウンロードし、インスト ールしたばかりのシステム上でそれをビルドし、インストールして自動回帰テスト( を参照してください) を実行し、 さらに手動でテストをいくらかしておくべきでしょう。これらのチェックや、プロジ ェクトが持っているリリース時のチェックリストの項目をすべてクリアすれば、開発者は GnuPG() や PGP()、 または PGP と互換性のある他のプログラムを使ってtarボールに電子署名を行います。 ほとんどのプロジェクトでは、開発者はプロジェクトが共有している鍵を使わず、 自分の鍵を使って電子署名をします。そしてできるだけ多くの (すなわち、最低限 の人数が必要という意味であって、署名する開発者の数を限ればいいという意味で はありません) 開発者が同じtarボールに署名します。署名する開発者が多くなれば なるほど、多くテストされているということになり、セキュリティに関心があるユー ザーが、そのtarボールから自分が信頼するルートを見つけられる可能性が高くなります。 開発者達からリリースしてよいとの同意をもらったら、リリース(つまり、 すべてのtarボール、zipファイル、そして配布される他のあらゆるフォー マットのファイル) は、電子署名と MD5/SHA1のチェックサム( を参照 してください) と一緒にプロジェクトのダウンロードエリアに置きましょう。 これには標準的なやり方がいくつかあります。ひとつは、それぞれのリリー スするパッケージを、対応する電子署名を記したファイルと、チェックサム が書かれたファイルと一緒に置くことです。 たとえば、リリースするパッケージのひとつが、scanley-2.5.0.tar.gz だとすると、同じディレクトリにそのtarボールに行った電子署名が含まれている scanley-2.5.0.tar.gz.asc と、MD5 チェックサムを記した scanley-2.5.0.tar.gz.md5 や、 SHA1チェックサムを記した scanley-2.5.0.tar.gz.sha1 を置いておきます。 別の方法として、リリースするパッケージに対する全ての電子署名を scanley-2.5.0.sigs のようなひとつのファイルに集めておく ことがあります。同じやり方がチェックサムにも使えます。 どの方法を使っても構いません。単純な手続きに留めるようにし、それを 明確に文書化するようにしましょう。そして、以後のリリースに対しても それを一貫して適用するようにします。このように、電子署名とチェック サムをつける目的は、自分が受け取ったコピーが悪意がある人間によって 改竄されていないことを確認する手段をユーザーに与えることです。 ユーザーはダウンロードしたコードをすぐに自分のマシンで実行してしま います — つまり、コードが改竄されていれば、攻撃者がそのデータ にバックドアを仕掛けることができてしまいます。 セキュリティに関して偏執的なユーザーについては、この章の後の方にある を参照してください。 リリース候補 多くの変更が加えられた重要なリリースでは、多くのプロジェクトは好んで リリース候補 をはじめにリリースします。 たとえば、scanley-2.5.0 をリリースする前に scanley-2.5.0-beta1 をリリースするといった具合です。 リリース候補を出す目的は、正式なリリースを行う前に、コードを広くテストしてもらうことです。 問題が見つかれば、それはリリースブランチで修正され、新しいリリース候補が(scanley-2.5.0-beta2のような形で)リリースされます。 このサイクルは、見過ごせないバグが残っていない状態になるまで続けられ、その時点で最後のリリース候補が正式なリリースとなります — つまり、最後のリリース候補と正式なリリースの唯一の違いは、バージョン番号の識別子を除いた点だけ、ということになります。 ほとんどの点で、リリース候補は実際の正式リリースと同じように扱うようにします。 alphabeta、そして rc といった識別子は、保守的なユーザーに対して正式リリースまで待つように警告するものであればそれで十分です。 そしてもちろん、リリース候補をアナウンスする電子メールは、リリース候補を出す目的がフィードバックを求めるためのものであることを記しておきましょう。 それ以外は、リリース候補に対して正式なリリースと同じだけの注意を払うようにします。 結局は、衆目の眼に晒すことはバグを発見する最高の方法ですし、 リリース候補が最終的に正式リリースになるかどうかわからないからこそ、 開発者はリリース候補を人々に使ってもらいたいと願うのです。 リリースを告知する リリースを告知するのは、オープンソースソフトウェアを開発するときに起こる他のイベントと似ていますし、 その手続きも で説明している方法に従うとよいでしょう。 ただ、リリースを告知する場合には特別な点がいくつかあります。 リリースしたtarボールのダウンロード先URLを示す場合は、必ず MD5/SHA1 チェックサムと、 電子署名ファイルの場所も同時に示すようにしましょう。 リリースの告知は複数の場所 (メーリングリストやニュースページなど) で行われるため、 こうすることでユーザーがチェックサムの情報を複数の情報源から得ることができ、 最も強くセキュリティに関心を持つユーザーが、 チェックサムが改竄されていなかったことを確信できるようになります。 電子署名ファイルへのリンクを複数回張ったとしても、 その電子署名ファイルがより安全になるわけではありませんが、 プロジェクトがセキュリティに真面目に取り組んでいることを人々 (特にプロジェクトを間近で追いかけていない人) が再び確認できます。 電子メールとニュースページで告知をするときは、 リリースを宣伝する文章以上の情報も含めるようにし、 ユーザーがなぜアップグレードすべきかがわかるように、 関連する CHANGES ファイルの部分を必ず含めるようにしましょう。 この重要性は、正式なリリースのときも、リリース候補の場合でも同様に当てはまります。 バグ修正と新機能の内容を示すことは、ユーザーにリリース候補を試すように誘う意味で重要です。 最後に、開発チームとテスター、そして優れたバグ報告に時間を割いてくれた全てのユーザーに対して感謝の言葉を忘れないようにしましょう。 しかし、個人で巨大な仕事をする責任があった人がいない限り、特定の人を名指ししてはいけません。その仕事の価値はプロジェクトのメンバー全員がよーく知っていることですから。 クレジットの洪水に脚をとられないように注意しましょう。( を参照してください) 複数のリリースラインを管理する ほとんどの成熟したプロジェクトは、複数のリリースラインを平行して管理しています。 たとえば バージョン 1.0.0 がリリースされた後は、 プロジェクトが明示的にリリースラインの維持をやめるまで、 マイクロ(バグ修正)リリースを 1.0.1, 1.0.2 などの形でリリースするようにします。 ただ (マイナー番号が上がった) 1.1.0 をリリースすることが、 1.0.x ラインの維持をやめる十分な理由にはならないことに注意してください。 たとえば、新しいマイナー(メジャー)シリーズのはじめのリリースは絶対にアップグレードの対象にしないことをポリシーにしているユーザーもいます — つまり、彼らはたとえば 1.1.0 の間は他のユーザーにバグを探させ、 1.1.1 のリリースを待っているのです。これは必ずしも自分勝手な行動とは言えません。 (彼らは、新機能や、バグ修正の恩恵を受けることを控えていることも覚えておきましょう) ただ、理由が何であれ、彼らはアップグレードをとても慎重に行うと決めただけなのです。 よって、プロジェクトが 1.1.0 のリリースを目前にして 1.0.3 で重大なバグを発見した場合は、 ちょっと厳しいですが 1.1.0 でその修正を行い、 すべての 1.0.x 系を使っているユーザーにアップグレードを推奨することになるでしょう。 この場合、1.1.0 と 1.0.4 を両方リリースしたとして、開発者とユーザーの双方がハッピーでしょうか? そうではないですよね。 1.1.x ラインの維持がうまくいくと、プロジェクトは 1.0.x ラインの 維持をやめる と宣言することができます。 この宣言は公式なものとして行いましょう。その告知は単独で行うこともできますし、 1.1.x ラインのリリース告知と一緒に行うこともできます。どの方法をとるにしても、 ユーザーは古いリリースラインが維持されなくなることを知らなければいけません。 なぜなら、その告知に従って、ユーザーはアップグレードをする決断ができるからです。 プロジェクトによっては、以前のリリースラインのサポートを保証する期間を設定するところもあります。 オープンソースの文脈でいえば、"サポート" とはそのリリースラインに対するバグ報告を受け付け、 バグが十分出尽くすまでメンテナンスリリースを行うということです。 一方で、明示的にサポート期間は設定しないものの、 古いリリースラインを使っているユーザーの数を把握するため、 バグ報告の数を見張るプロジェクトもあります。 古いリリースラインを使うユーザーの率がある値より下がった時点で、 プロジェクトはそのラインの維持をやめると宣言し、サポートをやめるのです。 リリースを行うごとに、必ず ターゲットバージョン または ターゲットとなるマイルストーン をバグ報告システムに設定するようにしましょう。 これは、ユーザーが適切なリリースに対してバグを報告できるようにするためです。 開発中の最新のソースコードに対しては、 "development" や "latest" と呼ばれるターゲット名を設定することも忘れないでください。 なぜなら、ユーザーによっては、 — 活発な開発者だけではありません — 公式なリリースより新しいコードを実行しているからです。 セキュリティリリース セキュリティに関わるバグを扱う方法の詳細は で扱っていますが、 セキュリティリリースを行うにあたっては、特に議論すべきことがいくつかあります。 セキュリティリリース とは、 セキュリティ脆弱性を修正するためだけに行われるリリースです。 脆弱性を修正したコードはリリースが公になるまで明らかにできません。 これは修正がリリースの日までリポジトリにコミットできないだけでなく、 リリースされるまで公の場でテストできないことも意味しています。 開発者は、当然のことながら自分たちで修正箇所を調べ、内部でテストすることができますが、 広くユーザーにテストしてもらうことはできないのです。 このようにテストが不足することから、 セキュリティリリースは常に既に存在するリリースに対して修正を行い、 それ以外には 何も変更しない ようにすべきです。 これは、テストなしに多くの変更をリリースすればするほど、新しいバグが発生する可能性が高くなるうえ、 新しいセキュリティ上の脆弱性が発生する可能性すらあるからです! この保守的なやり方は、セキュリティ上の修正を展開する必要があるシステム管理者だけでなく、 セキュリティ上の修正とそれ以外の修正を同時にマシンに展開しないというアップグレードポリシーを持つ管理者にも馴染みやすいものです。 セキュリティリリースを行うために、ユーザーをちょっと騙す場合もあります。 たとえば、プロジェクトが 1.1.3 のリリースに向けて動いていて、 1.1.2 に対するバグ修正を行うと公に宣言しているときに、 セキュリティに関わるバグ報告が行われた場合です。 当然、開発者達はその修正がリリースされるまでセキュリティ問題について話すことはできません。 つまり、そのときまで 1.1.3 は計画通り 1.1.2 のバグ修正が含まれたものになると言い続けなければならないのです。 しかし、実際に 1.1.3 が出てみると、1.1.2 にセキュリティバグの修正が加わったことだけが変更点で、 他の修正は 1.1.4 に先送りされてしまっていました。(これはもちろん、セキュリティバグの修正に加え、 他の修正も 1.1.4 には含まれることになるということです) セキュリティの修正だけが含まれたリリースであることを示すために、 リリース番号に追加の構成要素を加えることもできます。 たとえば、 1.1.2.1 というリリース番号は、 1.1.2 に対してセキュリティ修正だけが加わったリリースだと区別できます。 そしてそれより "大きい" リリース番号 (e.g. 1.1.3, 1.2.0 など) は、 同じセキュリティ修正が加えられたリリースであるとわかります。 一方、プロジェクトを間近で追いかけていない人にとっては、 ほとんどの場合は3つの数字でリリース番号が構成されているのに、 ランダムに、ときどき4つの番号を見ると少し混乱する可能性があります。 私が見てきたほとんどのプロジェクトは、リリース番号を一貫させる方針を採用し、 セキュリティの修正が含まれたリリースの場合も、 たとえそれが他のリリース計画を番号ひとつ分ずらすことを意味するとしても、 最新リリースの次の番号を使っています。 リリースと日々の開発 平行して行われるリリースを同時に管理するということから、 日々の開発のやり方を推測することができます。 特に、次のことはどんなときでも推奨される強制的な規律になります。 つまり、コミットのひとつひとつは、論理的な変更単位であること、 そして関連のない変更をごっちゃにして一度にコミットしてはいけない、ということです。 変更する量がとても多い、または一度にコミットするのが破壊的である場合は、 それをN回のコミットに分割し、 それぞれのコミットが変更全体をうまく分割したサブセットであるようにします。 そして変更全体に関係のないものは一切含まれないようにします。 次に示すのは、まとまりのない悪いコミットの例です。: ------------------------------------------------------------------------ r6228 | jrandom | 2004-06-30 22:13:07 -0500 (Wed, 30 Jun 2004) | 8 lines 問題 #1729 を修正 : インデックス作成を上品に行うようにした。これに伴い、 ファイルにインデックスを作成している最中にユーザーがファイルを変更していたら警告するようにした。 * ui/repl.py (ChangingFile): 新しい例外クラス (DoIndex): 新しい例外を処理するようにした * indexer/index.py (FollowStream): インデックスを作成中にファイルが変更されたら、例外を生成するようにした (BuildDir): 上記とは関係ないが、いくつかの古いコメントを削除し、 コードのフォーマットをいくつか修正した。また、ディレクトリ作成時のエラーチェックを修正した。 その他関連のないクリーンアップ: * www/index.html: typoを修正し、次のリリース日を設定。 ------------------------------------------------------------------------ 問題点が浮き彫りになるのは、来るべきメンテナンスリリースに備えて、 BuildDir 関数のエラーチェックをリリースブランチに移植する必要が出てきたときです。 移植する人は、それ以外の変更点はいらないのです。 たとえば、問題 #1729 の修正自体をメンテナンスブランチに取り込むことは認められず、 index.html の調整もここでは関係ありません。 しかし、BuildDir の変更を、 バージョン管理システムのマージ機能を使って容易に取り出すことはできません。 なぜなら、バージョン管理システムは、 この変更を他の関係のないものとグループ化するように指示されているからです。 実際には、マージする前でさえ問題が出てくるでしょう。投票を行うために変更点を羅列する場合です。: 投票を提案する人は、該当する変更のリビジョン番号を与える代わりに、 提案されているコミットの一部分を分離するためだけに、特別なパッチを作ったり、 変更用のブランチを切らなければならなくなります。 このため、他の人がうんざりする量の仕事をすることになります。 それというのもすべて、変更点を論理的なグループに分割するのを面倒臭がったコミッターのせいなのです。 実際には、このコミットは 4つ に分割すべきでした。 ひとつは 問題 #1729 の修正、 もうひとつは 古いコメントの削除と BuildDir 関数のコードフォーマットの修正、 そして BuildDir 関数のエラーチェックの修正、 最後に index.html の微調整です。 3番目のコミットこそが、メンテナンスリリースのブランチに含めるよう提案されているものなのです。 それぞれのコミットを論理的な変更単位に分割するのが望ましいのは、 もちろんリリースブランチを安定させるためだけではありません。 心理的にも、意味がまとまっているコミットはレビューしやすく、 必要な時に元に戻しやすい (バージョン管理システムによっては、変更を元に戻すことで、特殊なマージを行うものもあります) ということもあります。 前もって皆が規律をちょっと守っておけば、プロジェクトが後に頭痛の種を多く抱えずに済むのです。 リリースの計画を立てる オープンソースプロジェクトが、歴史的に独占的なソフトウェアのプロジェクトと異なる点は、 リリースの計画に関するものです。 独占的なソフトウェアのプロジェクトでは、確固とした〆切があるのが普通です。 その理由は、顧客にある時点でアップグレードを提供すると約束している場合もあれば、 新しいリリースをマーケティング上の理由から他の仕事と連携させる必要があったりとか、 プロジェクトにお金を出しているベンチャーキャピタルの人が、 さらに投資をする前に成果を見る必要がある場合もあります。 一方、フリーソフトウェアプロジェクトでは、 ほとんど文字通りの意味での「道楽」が最近までほとんどの動機付けとなってきました。: つまり、好きだからコードを書いてきたのです。 全ての機能が揃う前にリリースする必要性を感じる人はいませんし、 そもそもなぜそうすべきなのでしょう? フリーソフトウェアプロジェクトでは、皆の仕事がひとつの生産ラインに乗っているわけではないのです。 最近では、多くのオープンソースプロジェクトが企業からお金を出してもらうようになり、 それに伴って企業の〆切文化の影響をより多く受けるようになってきています。 これは多くの点では良いことなのですが、 お金を貰って雇われている開発者とボランティアの開発者の間で、 優先順位の衝突が起きる可能性があります。 こうした衝突はリリーススケジュールをいつ、どのようにするかという問題でよく発生します。 プレッシャーが強い雇われ開発者は、当然リリースする日程を決めたがりますが、 ボランティアの開発者は他の問題意識の方が強いかもしれません — それは自分たちが求める機能や、仕上げておきたいテストであったりします — よって、ボランティアの開発者達はリリースを待つべきだと感じることになります。 もちろんこの問題については、議論し、妥協する以外に一般的な解決策はありません。 しかし、提案されているリリースの 存在 から、 日付を切り離すことで、衝突の頻度や度合いを最小限にすることができます。 つまり、はじめはざっくりとした見積り別のアプローチとして、 Martin Michlmayr の Ph.D論文 Quality Improvement in Volunteer Free and Open Source Software Projects: Exploring the Impact of Release Management () を読むとよいかもしれません。 これは巨大なソフトウェアプロジェクトにおいて、 機能ベースのリリースプロセスとは正反対の、 時間軸をベースとしたリリースプロセスを採用することに関する論文です。 Michlmayr は、Google でこれを題材にした講演も行っています。Google Video で視聴可能です。 以外は日付について触れず、 直近から中期的な段階で、プロジェクトはどういった形のリリースができるか、 そしてそのリリースにどんな機能を含めるのか、という方向に議論を誘導してみるのです。 機能について早期に確定しておくことで、 個々のリリースに関する議論が複雑になる度合いを減らすことができ、 予測可能性を高めることができます。 また、新機能や他の複雑なことをリリースに追加することで、 リリースの定義を拡大解釈する提案に反対させるある種の先入観を植え付けることができます。 たとえリリースの日取りが決まっていなくても、 その内容がうまく決まっていれば、 リリースの内容を拡大するのを正当化するのはそれを提案する人の責任になります。 トマス・ジェファーソン の伝記 Jefferson and His Time では、 Dumas Malone が、バージニア大学の組織を決めるための初ミーティングを彼がどのように進めたかについて語っています。 大学を設立するというアイディアはもともとジェファーソンのアイディアでしたが、 (オープンソースプロジェクトに限らず、どこででもあることですが) 他の多くの関係者が、自分たちの興味があることや議題を持って会議に乗り込んできたのです。 彼らがミーティングに集まってそれらを徹底的に議論していると、 ジェファーソンは周到に準備した建築図面や、その予算や実作業、提案されているカリキュラム、 そして自分がヨーロッパから輸入したいと考えていた特別な学部の名前を示して見せたのです。 会議室にいた人の中に、彼以外でそうした議題についてほんのわずかでも準備にした人はいませんでした。 つまり、彼らはそうした議題についてはジェファーソンのビジョンに従わざるを得ません。結局、 バージニア大学設立は多かれ少なかれ彼の計画通りに進んだのです。 建築費が予算をオーバーしていたり、彼のアイディアの多くは様々な理由で実現しなかったりしましたが、 ジェファーソンはそれらすべてが起こることをあらかじめ完全に予想していたのでしょう。 彼の狙いは戦略的でした。ミーティングで他の人が修正を提案せざるをえないような現実的な路線を提示するようにしたのです。 その結果、全体の枠組み、そしてプロジェクトのスケジュールも、だいたい彼が望むものになったのです。 フリーソフトウェアプロジェクトの場合、"ミーティング" はありませんが、 小さな提案の積み重ねは、そのほとんどがバグ追跡システムで行われます。 プロジェクトであなたがちょっと信頼されていて、 いろいろな新機能や改善やバグ修正をターゲットとなるリリースに割り当てはじめれば、 アナウンスした全体のプランに従って、人々はあなたについてくるでしょう。 いったんそれらが多かれ少なかれあなたの思い通りに進めば、 実際のリリース 時期 に関する議論もより進みやすくなるでしょう。 もちろん、個々の決定をまるで文書で確定したかのように示さないのが重要です。 特定のリリースで問題の解決をすると決めるときには、 コメントで議論に参加してもらい、反対意見を述べてもらったりし、 可能な時はいつでも、真摯に説得に応じましょう。 単に権力を行使するために、力を振りかざしてはいけません。 リリース計画を立てる過程で他の人が議論に参加すればするほど ( を参照してください) 、 自分が本当に重視している問題の優先度を高めることに賛同するよう説得することも容易になるのです。 リリース計画を立てるときに緊張を緩める別の方法として、 リリースを頻繁に行うことがあります。リリースする間隔が長期間空くと、 それぞれのリリースの重要性がメンバーの中で増してしまいます。 つまり、自分たちのコードが取り込まれなかったときのショックが大きくなってしまうのです。 なぜなら、次に取り込まれるチャンスまでどれくらい時間がかかるかがわかってしまうからです。 リリースプロセスの複雑さと、プロジェクトの性質にもよりますが、 3ヶ月から6ヶ月の間くらいが、普通は適切なリリース間隔です。しかし、 安定版のリリースラインは、もうすこし早い間隔でマイクロリリースを出した方がよいかもしれません。