📑 この章の目次
- title: バージョニング・パッケージ管理 icon: 📦 card_desc: 「1.2.3」の意味と、依存ライブラリの管理 — セマンティックバージョニング/メジャー・マイナー・パッチ・依存関係・ロックファイル slug: 10-versioning-package
- 一言でいうと
- 1. なぜバージョニング・パッケージ管理が必要なのか
- 2. セマンティックバージョニング(SemVer)とは —— 「1.2.3」の読み方
- 3. 🔑 番号は「互換性の約束」 —— SemVerの核心
- 4. パッケージ管理とは —— 依存関係を宣言で管理する
- 5. 🔑 ロックファイルと範囲指定 —— 再現性の鍵
- 6. なぜ「バージョンを正しく管理する」が開発の作法なのか
- 7. よくある落とし穴と対処
- まとめ
title: バージョニング・パッケージ管理 icon: 📦 card_desc: 「1.2.3」の意味と、依存ライブラリの管理 — セマンティックバージョニング/メジャー・マイナー・パッチ・依存関係・ロックファイル slug: 10-versioning-package
10 バージョニング・パッケージ管理 — 「1.2.3」の意味と、依存ライブラリを壊さずに更新する作法
自分の書いたコードだけでは動かない。他人が作ったライブラリ(道具の詰め合わせ)を組み合わせて動かす。その「組み合わせ」を番号で管理し、壊さずに更新する作法。
一言でいうと
モダンな開発は、自分のコード + 無数の外部ライブラリ(部品) の組み合わせで成り立ちます。それぞれの部品には「バージョン(版)」という番号が付いていて、この番号の意味を読み解き、組み合わせを記録しておくのが「バージョニング・パッケージ管理」の作法です。
1. なぜバージョニング・パッケージ管理が必要なのか
「私の環境では動いた」の罠
開発していると、こういうことが起きます。
- あなたのパソコンでは動いたコードが、他人のパソコンでは動かない
- 昨日は動いたのに、今日は壊れた(自分は何も変えていないのに)
原因の多くは「使っている部品(ライブラリ)のバージョンが違う」ことです。ある部品が新しくなって仕様が変わり、それに依存していたあなたのコードが動かなくなった、という現象です。これを依存地獄(依存関係の地獄/dependency hell)と呼びます。
2つの問いに答える
バージョニング・パッケージ管理は、次の2つの問いに答える作法です。
- 「この部品が新しくなったとき、私のコードは壊れるか?」 — バージョン番号の読み方(セマンティックバージョニング)で分かる
- 「半年後にこのコードを別の人が動かしたとき、同じく動くか?」 — 組み合わせの記録(ロックファイル)で保証する
この2つが揃って初めて、「どこでも・いつでも同じように動く」(再現性)が手に入ります。
2. セマンティックバージョニング(SemVer)とは —— 「1.2.3」の読み方
3つの数字
ライブラリのバージョンは、たいてい 1.2.3 のようにピリオドで区切られた3つの数字で表されます。これをセマンティックバージョニング(Semantic Versioning/通称 SemVer/セムヴァー)と呼びます。
| 位置 | 名前 | 役割 |
|---|---|---|
1 |
メジャー(major) | 後方互換性が壊れる変更 |
2 |
マイナー(minor) | 後方互換性を保つ機能追加 |
3 |
パッチ(patch) | バグ修正(機能は変わらない) |
「後方互換性」(こうほうごかんせい/backward compatibility)とは、古い使い方が新しい版でもそのまま動くという性質のことです。「前の版のコードが、新しい版でも壊れずに動く」という約束を表します。
どう上がるか
あるライブラリが 1.2.3 から次のように変わったとき、意味が違います。
1.2.4— バグを直しただけ(パッチ)。ほぼ確実に壊れない1.3.0— 新機能を足した(マイナー)。原則壊れない2.0.0— 大きく作り変えた(メジャー)。壊れる可能性がある
この「どの桁が上がったかで、壊れるかどうかが分かる」という約束こそが、SemVer の核心です。
3. 🔑 番号は「互換性の約束」 —— SemVerの核心
なぜ番号の読み方が重要か
SemVer が単なる「数え方のルール」でなく作法たるゆえんは、番号が作り手と使い手の間の約束だからです。
- 作り手は「メジャーを上げるときは、古い使い方が壊れることを覚悟して上げる」と約束する
- 使い手は「メジャーが上がっていない更新なら、安心して取り込める」と信頼できる
この約束があるからこそ、無数のライブラリを組み合わせても**「どれを更新していいか・慎重にすべきか」が番号だけで判断**できます。約束が守られていないと、パッチ番号の変更で壊れるようなライブラリは「SemVer を守らない」として不信の目で見られます。
例えていうと: 電化製品のコンセント
- パッチ = 同じ製品の色が変わった程度。コンセント(使い方)はそのまま。安心
- マイナー = 新しい機能が付いた。でも従来のコンセントも使える。たいてい安心
- メジャー = コンセントの形そのものが変わった。古いプラグは刺さらない(壊れる)
「コンセントの形が変わった」のがメジャーアップデートだと分かれば、安易に挿し直さず、変換アダプタ(修正)を用意するか止めるかを判断できます。これと同じことを、番号の桁で行います。
4. パッケージ管理とは —— 依存関係を宣言で管理する
パッケージとパッケージマネージャ
外部ライブラリをパッケージ(package/荷物)と呼びます。そして、パッケージを探して・ダウンロードして・組み込んで・更新する仕組みをパッケージマネージャ(package manager/荷物の管理係)と呼びます。言語ごとに定番があります。
| 言語 | パッケージマネージャ | 例 |
|---|---|---|
| JavaScript | npm(エヌピーエム)・yarn |
npm install react |
| Python | pip(ピップ)・uv |
pip install fastapi |
| Rust | cargo(カルゴ) |
cargo add serde |
| Ruby | bundler(バンドラー) |
bundle install |
「宣言」で管理する
モダンなパッケージ管理の作法は「何を使うかを宣言ファイルに書く」ことです。JavaScript なら package.json、Python なら requirements.txt 等に「このライブラリのこの版を使う」と宣言します。
fastapi == 0.115.0
uvicorn >= 0.30.0
こう書いておけば、パッケージマネージャが宣言を読んで必要な部品を自動で集めてくれます。人数が増えても、別のパソコンでも、宣言ファイル1つあれば「同じ部品構成」が再現できます。
5. 🔑 ロックファイルと範囲指定 —— 再現性の鍵
範囲指定の誘惑と罠
宣言ファイルには「この版ぴったり」でなく「この版以上」のように範囲で書くことができます。
| 書き方 | 意味 |
|---|---|
1.2.3 |
この版ぴったり(固定) |
^1.2.3 |
1.2.3 以上 2.0.0 未満(マイナー・パッチは自動で新しくなる) |
~1.2.3 |
1.2.3 以上 1.3.0 未満(パッチだけ新しくなる) |
範囲指定は「バグ修正や新機能を自動で取り込める」という利点があります。しかしこれには裏があります。範囲を許すと、インストールのたびに実際に入る版が少しずつ違う可能性があるのです。「昨日は動いた、今日は壊れた」の再現です。
💡 0.x 系(1.0.0 未満)は例外: 開発初期のライブラリ(0.2.5 等)は SemVer のルールがまだ緩く、マイナー更新でも壊れる変更が入りうると定められています。0.x 系への範囲指定(^0.2.3 等)はとくに慎重に扱いましょう。
ロックファイル —— 実際の組み合わせを固定する
この問題を解決するのがロックファイル(lock file/鍵ファイル)です。パッケージマネージャは、宣言を元に部品を集めたあと、**「実際に入れた版を、部品ごとにすべて書き留めた別のファイル」**を生成します。
| 言語 | ロックファイル |
|---|---|
| JavaScript(npm) | package-lock.json |
| JavaScript(yarn) | yarn.lock |
| Python(uv) | uv.lock |
| Rust | Cargo.lock |
ロックファイルのおかげで「半年後に別の人が install しても、私が動かした時と全く同じ版組み合わせが入る」ことが保証されます。範囲指定(宣言)で柔軟性を保ちつつ、ロックファイル(記録)で再現性を固める、という2枚構えがモダンな作法です。
⚠ ロックファイルは原則コミット(Git に保存)します。特にアプリ開発では、再現性のためにメンバー・CI 全員で共有する必須ファイルです。「.gitignore で無視する」は誤解です。※一方でライブラリ開発(他人が組み込む部品を作る側)では、使う側の依存関係を縛りすぎないよう、あえてコミットしない運用も一般的です。
6. なぜ「バージョンを正しく管理する」が開発の作法なのか
作法として位置づけられる理由
- チーム開発の前提: メンバー全員が同じ部品構成で動かせなければ、開発すら始まりません。宣言ファイルとロックファイルがその共通基盤です。
- CI でも再現性が要る: 第1章で扱った CI(自動検査)は、CI サーバー上で改めて部品をインストールして検査します。ロックファイルがなければ**「あなたのPCでは緑・CIサーバーでは赤」**になり、CI の意味が崩れます。
- セキュリティにも直結: ライブラリに脆弱性(セキュリティの穴)が見つかると、修正版への更新が必要です。番号の読み方が分かっていれば「この更新は安全に取り込めるか」を素早く判断できます。
面接・実務での意味
- 「依存関係はどう管理していますか?」という質問に、宣言ファイルとロックファイルの2枚構えで答えられるかが、現場経験の有無を分けます。
- 「SemVer を守っていますか?」は、ライブラリを公開する側になるとさらに重要になります。自分のライブラリの番号の上げ方1つで、使ってくれる人のコードを壊しかねないからです。
- 「私の環境では動きました」は、再現性の管理ができていないことの赤信号として扱われます。現場では「環境が同じであること」を証明できることが前提です。
7. よくある落とし穴と対処
| 落とし穴 | 何が起きるか | 正しい対応 |
|---|---|---|
| ロックファイルをコミットしない | メンバー・CI で版がズレて「私の環境では動く」が再発 | アプリ開発ではGitに保存(※ライブラリ開発では逆にコミットしないのが一般) |
| メジャーアップデートを雑に取り込む | 後方互換性が壊れ、あちこちでエラー | メジャー上がりは必ず動作確認・範囲指定で上限を 2.0.0 未満に抑える |
| 範囲指定の範囲を広くしすぎる | 知らぬ間に新しすぎる版が入って壊れる | ^ や ~ の意味を理解し、本当に許したい範囲だけ指定する |
| SemVer を守らずに番号を上げる | 使う人が「パッチのはずが壊れた」と不信に陥る | 公開側はメジャー=壊れる変更の約束を厳格に守る |
| 使わなくなった部品を放置 | セキュリティリスク・無駄な依存が増える | 定期的に依存関係を棚卸しし、未使用のものは外す |
| 宣言ファイルと実際が乖離 | 「書いてある版」と「入っている版」が違う事故 | install は必ずパッケージマネージャ経由で、宣言ファイルを正とする |
💡 依存地獄(dependency hell): 依存する部品が多くなりすぎて、「部品Aのために部品Bは新しくしたいが、部品Cが古いBしか受け付けない」のように版の矛盾で身動きが取れなくなる状態。SemVer・ロックファイル・定期的な棚卸しは、すべてこの地獄に落ちないための作法です。
まとめ
- モダンな開発は自分のコード+無数の外部ライブラリの組み合わせ。これを番号で管理するのがバージョニング・パッケージ管理
- セマンティックバージョニング(SemVer) は
メジャー.マイナー.パッチの3桁。メジャーが上がった=後方互換性が壊れる可能性、が核心の約束 - パッケージ管理は「何を使うかを宣言ファイルに書く」作法。言語ごとのパッケージマネージャ(
npm・pip等)が部品を自動で集める - 範囲指定(
^・~)は柔軟だが再現性を緩める。ロックファイルで「実際に入った版」を固定して補う(原則コミット) - 「どこでも・いつでも同じように動く=再現性」を支えるのがこの作法の目的。「私の環境では動く」は管理不足の赤信号
💡 次のステップ: 部品の組み合わせを管理できるようになりました。しかし、どんなに管理してもバグは起きます。第11章「デバッグの作法」では、起きたバグの原因を、当てずっぽうでなく論理的に切り分けていく手順を扱います。