セマンティックバージョニングのバージョン番号を上げる際の判断基準について考えてみる
はじめに
セマンティックバージョニングというものをご存知でしょうか。
セマンティックバージョニングとは、 APIにバージョン番号を設定する際のルールのことです。
セマンティックバージョニングはこちらに公開されており、バージョン番号を決定する際の一つの基準となります。しかし、どのような場合にバージョン番号を上げるべきかについて、まだ曖昧な理解があります。そこで、これを深く理解するために、この記事を書くことにしました。
セマンティックバージョニングの規則
2023年12月17日時点で、日本語版の資料には、以下のように記載されています。
バージョンナンバーは、メジャー.マイナー.パッチ とし、バージョンを上げるには、
- APIの変更に互換性のない場合はメジャーバージョンを、
- 後方互換性があり機能性を追加した場合はマイナーバージョンを、
- 後方互換性を伴うバグ修正をした場合はパッチバージョンを上げます。
プレリリースやビルドナンバーなどのラベルに関しては、メジャー.マイナー.パッチ の形式を拡張する形で利用することができます。
ひとつひとつ、順番に見ていきます。
バージョンナンバーは、メジャー.マイナー.パッチ とし
セマンティックバージョニングは3つの番号で構成されており、各番号は「.」で区切られます。
つまり、1.2.3
や0.23.102
のようなフォーマットになるという意味だと読み取ることができます。
- APIの変更に互換性のない場合はメジャーバージョンを、
- 後方互換性があり機能性を追加した場合はマイナーバージョンを、
- 後方互換性を伴うバグ修正をした場合はパッチバージョンを上げます。
バージョン番号を上げる際のルールが、記載されています。
まず、APIに変更があった場合には、バージョン番号を上げる必要があります。
そして、バージョン番号の上げ方は、後方互換性の有無、機能性の追加かバグ修正か、によって分岐します。
まず、後方互換性がない変更をする場合には、メジャーバージョンの番号を上げます。
つまり、1.0.0
というバージョンがあったとしたら2.0.0
に変更するという形になります。
後方互換性がある場合は、次の2つに分岐します。
機能性を追加した場合にはマイナーバージョンを上げます。つまり、1.0.0
というバージョンがあったとしたら1.1.0
に変更するという形です。
バグを修正した場合にはパッチバージョンを上げます。つまり、1.0.0
というバージョンがあったとしたら1.0.1
に変更するという形です。
プレリリースやビルドナンバーなどのラベルに関しては、メジャー.マイナー.パッチ の形式を拡張する形で利用することができます。
これは資料のセマンティック バージョニング仕様書 (SemVer)とSemVerバージョンを表すバッカス・ナウア記法を見ると、理解できます。
例えば、プレリリース(ここでは正式なリリースの前に公開されるバージョンとする)であれば、1.0.0-alpha.1
のように、-
を利用して、元のバージョン番号に追加でラベルを設定します。
ビルド(ここでは特定のビルドに関するメタデータと理解)であれば、1.0.0+20130313144700
のように、+
を利用して、元のバージョン番号に追加でラベルを設定します。
セマンティックバージョニングを扱う上で細かいルールがあるのですが、今回はそこは飛ばし、バージョン番号を上げるルールの解釈を中心に考えていきます。
後方互換性とは
後方互換性の解釈をはっきりさせることで、バージョン番号をどのように上げるかの判断において、迷いを少なくすることができそうです。
資料には後方互換性の定義が記載されていなかったため、資料が指し示す後方互換性の正確な意味を把握することはできませんでした。
ここでは、後方互換性を「新しいバージョンのソフトウェアやシステムが、旧バージョンで作成されたデータやインターフェースと互換性を持つこと」とし、それに基づいて読み進めます。
後方互換性がある場合、新しいバージョンを使用しても、以前のバージョンで使用されていたシステムはそのまま動作し続けます。
一方、後方互換性がない場合は、新しいバージョンを使用した際に、以前のバージョンで使用されていたシステムが動作しなくなります。
このような理解で、セマンティックバージョニングの解釈を進めます。
後方互換性のない場合とはどんな場合か
資料には「APIの変更に互換性のない場合はメジャーバージョンを」、つまり後方互換性がない変更をした場合には、メジャーバージョンを上げる必要があると記載がありました。
では、具体的に後方互換性がない変更とは何なのでしょうか?
思いついた限りでは、以下の通りです。
- 関数やメソッドの削除
- 既存のAPIから特定の関数やメソッドを完全に削除する
- 関数やメソッドのシグネチャの変更
- 引数の数や型を変更する
- 戻り値の型を変更する
- 入力パラメータの変更
- 必須パラメータを追加する
- 既存のパラメータのデフォルト値を変更する
- 出力フォーマットの変更:
- 戻り値やレスポンスの構造を変更する(例:JSONのキーを変更する)
- エラーコードやステータスコードを変更する
- 動作の変更
- 同じ入力に対して異なる出力や振る舞いをするようにする
- サイドエフェクトや副作用を変更する
- セキュリティ要件の変更
- 認証や認可のプロセスを変更する
- 通信の暗号化要件を変更する
- エンドポイントの変更
- APIのURLやエンドポイントの構造を変更する
- 依存ライブラリの要件変更
- APIが依存する外部ライブラリのバージョンを変更する
つまり、これらの変更が加わる場合には、メジャーバージョンを上げるという判断をするということになるでしょう。
後方互換性があり機能性の追加した場合とはどんな場合か
次はマイナーバージョンを上げる場合を考えます。
マイナーバージョンを上げるのは「後方互換性があり機能性を追加した場合」でした。
では、後方互換性があり機能性を追加した場合とはどんな場合でしょうか?
思いついた限りでは、以下の通りです。
- 新しい機能の実装
- 新しい操作や処理の追加
- 新しいユーザーインターフェースのコンポーネントやページの追加
- APIの拡張
- 新しいAPIエンドポイントやメソッドの追加
- 既存のAPIに、必須ではない新しいパラメータやオプションの追加
- パフォーマンスの改善
- 処理速度や効率の向上
- より高速なアルゴリズムや最適化されたコードの導入
- 互換性の拡大
- 新しいデバイスやオペレーティングシステムとの互換性の追加
- 異なる言語や地域設定への対応の拡大
- セキュリティ機能の向上
- 新しいセキュリティ機能やプロトコルの導入
- データ保護の強化
- ユーザビリティの向上
- インターフェースの改善やナビゲーションの簡略化
- ユーザーエクスペリエンスの向上のためのデザイン変更
デザイン変更は追加というより、改善という方向性に思えますが、機能性の追加と解釈できるかなと判断し、入れても良いと思ったので入れてみました。
後方互換性を伴うバグ修正をした場合とはどんな場合か
マイナーバージョンアップをする場合を考えます。
これはセマンティック バージョニング仕様書 (SemVer)の6に、以下のような説明があります
バグ修正とは間違った振る舞いを修正する内部の変更のことを指します
では、上記の説明を踏まえ、後方互換性を伴うバグ修正をした場合とはどんな場合でしょうか?
思いついた限りでは、以下の通りです。
- 機能的な不具合の修正
- ソフトウェアが予定通りに動作しない場合の修正
- ユーザーインターフェースのエラーや誤動作の修正
- パフォーマンスの問題の修正
- ソフトウェアの応答時間が遅い、またはリソース使用量が異常に高い問題の解決
- セキュリティの脆弱性の修正
- セキュリティホールや脆弱性を修正し、ソフトウェアをより安全にする
- データ処理の誤りの修正
- 計算エラーやデータの不正な処理の修正
- 互換性問題の修正
- 特定のシステムやハードウェアでのみ発生する互換性の問題を修正
- ドキュメントやメッセージの修正
- ユーザーガイドやエラーメッセージの誤りの修正
許容できないくらいのパフォーマンスの劣化に関してはバグと判断し、それの修正はバグ修正として解釈して良いと思ったので入れてみました。パフォーマンス問題に関しては、機能性の追加とするか、バグ修正とするかは、実運用においては都度判断することになりそうです。
おわりに
セマンティックバージョニングにおいて、どういった場合にどのバージョン番号を上げるかを自分なりに言語化してみました。
もやもやしていた部分の解像度が上がって満足です。
考慮漏れやアドバイスなどあれば、コメントいただけるととても喜びますので、ぜひ。
それでは、また。
Discussion