セマンティック バージョニング 2.0.0

概要

バージョン番号 MAJOR.MINOR.PATCH を前提として、

  1. あなたが互換性のない API の変更を行うときに MAJOR バージョンを、
  2. 後方互換性のある方法で機能性を追加したときに MINOR バージョンを、
  3. そして、後方互換性のあるバグ フィックスをしたときに PATCH バージョンを、

インクリメントします。

追加のラベルとして、プレリリースとビルド メタデータが MAJOR.MINOR.PATCH フォーマットへの拡張として利用することができます。

序論

ソフトウェア マネジメントの世界には「依存関係地獄」と呼ばれる非常に恐ろしい場所が存在します。 あなたのシステムがより大きくなるほど、あなたのソフトウェアの中へより多くのパッケージを溶け込ませるほど、いつかこの絶望の底にいるあなた自身に気づく、そんな可能性が高くなるでしょう。

多くの依存関係を持っているシステムにおいて新しいパッケージのバージョンをリリースすると、すぐに悪夢のような経験となるでしょう。 もし過度に厳しい依存関係の仕様ならば、あなたはバージョン ロック(依存している全パッケージの新しいバージョンのリリースなしに、パッケージをアップグレードすることができなくなること)の危険があります。 もし依存関係があまりにも緩い仕様ならば、バージョンの混乱(合理性よりもむしろ将来のバージョンの互換性を考える)に取り付かれることは多分避けられないでしょう。 依存関係地獄とは、バージョン ロックとバージョンの混乱、その両方またはいずれか一方によって、あなたが容易かつ安全にプロジェクトを進めるのを邪魔されることです。

この問題の解決策として、バージョン番号の割り当てとインクリメントをどのようにするか、ということを決めるためのシンプルな規則と要件を提案します。 これらの規則は、クローズドおよびオープンソース ソフトウェアともに使われている既存の一般的な方法に基づいていますが、必ずしもそうであるとは限りません。 このシステムを機能させるために、まず最初にパブリック API を宣言する必要があります。 これはドキュメンテーションで構成されるか、またはコードそのものによって励行されているかもしれません。 とにかく、はっきりと明確な API であるということが重要です。 一度あなたがパブリック API を認めたならば、そのパブリック API の変更に伴ってバージョン番号が明確に増加することをはっきりと明らかにします。 X.Y.Z (Major.Minor.Patch) というバージョンのフォーマットを検討してください。 API に影響を及ぼさないバグ フィックスではパッチ (patch) バージョンをインクリメントし、後方互換性を持つ API の追加や変更ではマイナー (minor) バージョンをインクリメントし、そして後方互換性を持たない API の変更ではメジャー (major) バージョンをインクリメントします。

この方式を「セマンティック バージョニング」と呼びます。 この手法に基づいて、バージョン番号とそれらの変更を伝える方法が意味することは、根底となるコードと何かが、あるバージョンから次のバージョンへと変更されて過去のものとなったことです。

セマンティック バージョニング仕様書 (SemVer)

この文書における次の各キーワード「しなければならない (MUST)」、「してはならない (MUST NOT)」、「要求されている (REQUIRED)」、「することになる (SHALL)」、「することはない (SHALL NOT)」、「する必要がある (SHOULD)」、「しないほうがよい (SHOULD NOT)」、「推奨される (RECOMMENDED)」、「してもよい (MAY)」、「選択できる (OPTIONAL)」は、RFC 2119 で述べられているように解釈されるべきものです。

  1. セマンティック バージョニングを用いるソフトウェアは、パブリック API を宣言しなければならない (MUST)。 この API は、コードそのものにおいて宣言されているか、ドキュメンテーションの中で厳密に存在しているということもあり得る。 どんな仕方で宣言されていようとも、それは明確かつ包括的でなければならない。

  2. 通常のバージョン番号は X.Y.Z の形を取らなければならない (MUST)。このとき X, Y, Z は非負の整数とし、頭にゼロを入れてはならない (MUST NOT)。 X はメジャー バージョン、Y はマイナー バージョン、Z はパッチ バージョンである。 それぞれの要素は数値的に増やさなければならない (MUST)。 例:1.9.0 -> 1.10.0 -> 1.11.0

  3. 一度バージョン付けられたパッケージがリリースされたならば、そのバージョンの内容は修正してはならない (MUST NOT)。 あらゆる修正は新しいバージョンとしてリリースしなければならない (MUST)。

  4. メジャー バージョン 0 (0.y.z) は、初期の開発のためのものである。 いつでもどんなものでも変化する可能性がある。 パブリック API は安定的と考えられるべきではない。

  5. バージョン 1.0.0 はパブリック API を定義する。 このリリースの後でバージョン番号がインクリメントされることは、このパブリック API とそれの変更がどの程度であるかに左右される。

  6. パッチ バージョン Z (x.y.Z | x > 0) は、後方互換性を持つバグ フィックスが取り入れられた場合にインクリメントしなければならない (MUST)。 バグ フィックスとは、間違った振る舞いを修正する内部の変更とする。

  7. マイナー バージョン Y (x.Y.z | x > 0) は、後方互換性を持つ機能が新たにパブリック API に取り入れられた場合にインクリメントしなければならない (MUST)。 任意のパブリック API の機能が廃止予定(非推奨)としてマークされた場合にインクリメントしなければならない (MUST)。 プライベート コードの中に相当な新機能または改良が取り入れられた場合にインクリメントしてもよい (MAY)。 パッチ レベルの変更を含めてもよい (MAY)。 パッチ バージョンは、マイナー バージョンがインクリメントされたとき 0 にリセットされなければならない (MUST)。

  8. メジャー バージョン X (X.y.z | X > 0) は、なんらかの後方互換性を持たない変更がパブリック API に取り入れられた場合にインクリメントしなければならない (MUST)。 マイナーとパッチ レベルの変更を含めてもよい (MAY)。 パッチとマイナー バージョンは、メジャー バージョンがインクリメントされたとき 0 にリセットされなければならない (MUST)。

  9. プレリリース バージョンは、パッチ バージョンの直後のハイフンとドット区切りの識別子によって示されていてもよい (MAY)。 識別子は、ASCII 英数字とダッシュ [0-9A-Za-z-] のみから構成されていなければならない (MUST)。 識別子は、ASCII 英数字とハイフン [0-9A-Za-z-] のみから構成されていなければならない (MUST)。 識別子は空であってはならない (MUST NOT)。 数値的な識別子には頭にゼロを入れてはならない (MUST NOT)。 プレリリース バージョンは、関連する通常のバージョンよりも低位に位置する。 プレリリース バージョンは、不安定で、関連する通常のバージョンで意図した互換性要求を満たさない恐れがあることを意味するバージョンであることを示す。 用例:1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92

  10. ビルド メタデータは、パッチまたはプレリリース バージョンの直後にプラス記号を付加した上でドット区切りの識別子によって示されていてもよい (MAY)。 識別子は、ASCII 英数字とハイフン [0-9A-Za-z-] のみから構成されていなければならない (MUST)。 識別子は空であってはならない (MUST NOT)。 バージョンの優先順位を決定する際、ビルド メタデータは無視されなければならない (MUST)。 したがって、ビルド メタデータだけが異なる 2 つのバージョンは、同じ優先順位を持つ。 用例:1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85

  11. 優先順位とは、バージョン同士を順序づけるとき、どのように比較するかを指す。 優先順位は、メジャー、マイナー、パッチ、プレリリース識別子の順(ビルド メタデータは優先順位の中に現れない)に独立して計算されなければならない (MUST)。 優先順位は、メジャー、マイナー、パッチ バージョンのそれぞれの識別子の左から右に比較したとき、一番目に異なる部分によって決まる。ここで、メジャー、マイナー、パッチ バージョンは常に数値的に比較する。 例:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。 メジャー、マイナー、パッチが等しいとき、プレリリース バージョンは通常のバージョンよりも低い優先順位を持つ。 例:1.0.0-alpha < 1.0.0。 同じメジャー、マイナー、パッチ バージョンを持つ 2 つのプレリリース バージョンの優先順位は、異なる部分が見つかるまで識別子の左から右にドット区切りのそれぞれの識別子の比較によって決定しなければならない (MUST)。ここで、数字だけからなる識別子なら数値的に、文字またはハイフンを伴う識別子は ASCII ソート順に辞書的に比較される。 数値的な識別子は、常に非数値的な識別子よりも優先順位が低い。 すべての先行する識別子が等しいならば、より大きいセットのプレリリース フィールドは、より小さいセットよりも高い優先順位を持つ。 例:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0

なぜ、セマンティック バージョニングを使うのか?

これは新しくもなければ画期的でもないアイディアです。 実際に、おそらくあなたはすでにこれに近い何かをしているでしょう。 問題は「近い」では不十分だということです。 いくつかの正式な仕様書のソートに整合性がなくて、バージョン番号は依存関係の管理に関してどうしても役に立ちません。 名前とはっきりとした定義を与えるということは、あなたのソフトウェアのユーザにあなたの目的を伝えることが容易になります。 一度、このようなはっきりとした目的があることで、柔軟な(しかし柔軟すぎない)依存関係の仕様を最終的に作ることができます。

セマンティック バージョニングがどのようにして依存関係地獄を過去のものとするのか、簡単な例を用いて説明しましょう。 "Firetruck" と呼ばれるライブラリを考えてみてください(訳注:Firetruck = 消防車)。 それは "Ladder" と名付けられているセマンティックなバージョン付けのパッケージを必要とします(訳注:Ladder = はしご)。 Firetruck が作り出された時点で、Ladder はバージョン 3.1.0 でした。 Firetruck は、3.1.0 において最初に取り入れられたいくつかの機能を使います。あなたは安全に Ladder は 3.1.0 以上 4.0.0 未満に依存していると明言できます。 さて、Ladder バージョン 3.1.1 と 3.2.0 が利用できるようになったとき、あなたのパッケージ管理システムにそれらをリリースすることができ、依存するソフトウェアに互換性があることを知っていることができます。

責任ある開発者であるあなたは、言うまでもなく、公表されたいくつかのパッケージ アップグレードの機能を確かめたいと思うことでしょう。 現実の世界は乱雑な場所です。我々はそれらについて気を配る必要はありません。 セマンティック バージョニングは、依存するパッケージの新しいバージョンに巻き込まれることなく、パッケージのリリースとアップグレードのまっとうな手段を提供し、あなたの時間と手間を省いてくれます。

もし全面的に魅力的に思えたならば、必要なことはセマンティック バージョニングを使い始めたことを公表し、規則に従うことです。 ほかの人々が規則の理解と利益を得られるように、README からこのウェブサイト(訳注:原文は <http://semver.org/> にて公開されている)へリンクしてください。

FAQ

初期の開発段階 0.y.z における修正はどうすればいいのですか?

最も簡単なのは、最初の開発リリースを 0.1.0 で始め、その後それに続くリリースごとにマイナー バージョンをインクリメントすることです。

いつ 1.0.0 をリリースしたらいいのか、どうすればわかりますか?

もしあなたのソフトウェアが製品に用いられるのならば、おそらく既に 1.0.0 であるべきです。 もし複数のユーザーに頼られるようになった安定した API を持つならば、1.0.0 であるべきです。 もし後方互換性に関することをあなたはとても心配しているのならば、おそらく既に 1.0.0 であるべきです。

Doesn't this discourage rapid development and fast iteration?

Major version zero is all about rapid development. If you're changing the API every day you should either still be in version 0.y.z or on a separate development branch working on the next major version.

If even the tiniest backwards incompatible changes to the public API require a major version bump, won't I end up at version 42.0.0 very rapidly?

This is a question of responsible development and foresight. Incompatible changes should not be introduced lightly to software that has a lot of dependent code. The cost that must be incurred to upgrade can be significant. Having to bump major versions to release incompatible changes means you'll think through the impact of your changes, and evaluate the cost/benefit ratio involved.

Documenting the entire public API is too much work!

It is your responsibility as a professional developer to properly document software that is intended for use by others. Managing software complexity is a hugely important part of keeping a project efficient, and that's hard to do if nobody knows how to use your software, or what methods are safe to call. In the long run, Semantic Versioning, and the insistence on a well defined public API can keep everyone and everything running smoothly.

What do I do if I accidentally release a backwards incompatible change as a minor version?

As soon as you realize that you've broken the Semantic Versioning spec, fix the problem and release a new minor version that corrects the problem and restores backwards compatibility. Even under this circumstance, it is unacceptable to modify versioned releases. If it's appropriate, document the offending version and inform your users of the problem so that they are aware of the offending version.

What should I do if I update my own dependencies without changing the public API?

That would be considered compatible since it does not affect the public API. Software that explicitly depends on the same dependencies as your package should have their own dependency specifications and the author will notice any conflicts. Determining whether the change is a patch level or minor level modification depends on whether you updated your dependencies in order to fix a bug or introduce new functionality. I would usually expect additional code for the latter instance, in which case it's obviously a minor level increment.

What should I do if the bug that is being fixed returns the code to being compliant with the public API (i.e. the code was incorrectly out of sync with the public API documentation)?

Use your best judgment. If you have a huge audience that will be drastically impacted by changing the behavior back to what the public API intended, then it may be best to perform a major version release, even though the fix could strictly be considered a patch release. Remember, Semantic Versioning is all about conveying meaning by how the version number changes. If these changes are important to your users, use the version number to inform them.

How should I handle deprecating functionality?

Deprecating existing functionality is a normal part of software development and is often required to make forward progress. When you deprecate part of your public API, you should do two things: (1) update your documentation to let users know about the change, (2) issue a new minor release with the deprecation in place. Before you completely remove the functionality in a new major release there should be at least one minor release that contains the deprecation so that users can smoothly transition to the new API.

About

セマンティック バージョニング仕様書は、GitHub の共同創設者で Gravatar の発案者である Tom Preston-Werner によって書かれました。

If you'd like to leave feedback, please open an issue on GitHub.

訳注:この日本語訳は、Tom Preston-Werner 氏によって書かれた Semantic Versioning 2.0.0 <http://semver.org/> を、クリエイティブ・コモンズ・ライセンスに基づき shijimiii が翻訳し、公開しているものです。翻訳上の誤りなど、この日本語訳についての意見は ブログの記事のコメントへお願いします。

ライセンス

Creative Commons - CC BY 3.0