Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17737] ファイルの概要

このコミットは、Go言語の公式FAQドキュメント(doc/go_faq.html)に、パッケージのバージョン管理に関する新しいセクションを追加するものです。具体的には、go getコマンドがどのようにパッケージバージョンを扱うか、そしてGoエコシステムにおけるバージョン管理の推奨プラクティスについて説明しています。これは、当時のGoのパッケージ管理におけるバージョン管理の課題と、それに対する公式の見解を示す重要なドキュメントの追加です。

コミット

commit dc8d9031550e4adc5c83dadd48d9e1e8d0f7ea6d
Author: Russ Cox <rsc@golang.org>
Date:   Thu Oct 3 09:18:47 2013 -0400

    doc/faq: add a FAQ about versioning
    
    Fixes #5633.
    
    R=golang-dev, r, tommi.virtanen, adg, nj
    CC=golang-dev
    https://golang.org/cl/14283044
---
 doc/go_faq.html | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/doc/go_faq.html b/doc/go_faq.html
index fbce94a4ae..ecfc84ff70 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1029,6 +1029,42 @@ these two lines to <code>~/.gitconfig</code>:
 </li>
 </ul>
 
+<h3 id=\"get_version\">\n+How should I manage package versions using \"go get\"?</h3>\n+\n+<p>\n+\"Go get\" does not have any explicit concept of package versions.\n+Versioning is a source of significant complexity, especially in large code bases,\n+and we are unaware of any approach that works well at scale in a large enough\n+variety of situations to be appropriate to force on all Go users.\n+What \"go get\" and the larger Go toolchain do provide is isolation of\n+packages with different import paths.\n+For example, the standard library\'s <code>html/template</code> and <code>text/template</code>\n+coexist even though both are \"package template\".\n+This observation leads to some advice for package authors and package users.\n+</p>\n+\n+<p>\n+Packages intended for public use should try to maintain backwards compatibility as they evolve.\n+The <a href=\"/doc/go1compat.html\">Go 1 compatibility guidelines</a> are a good reference here:\n+don\'t remove exported names, encourage tagged composite literals, and so on.\n+If different functionality is required, add a new name instead of changing an old one.\n+If a complete break is required, create a new package with a new import path.</p>\n+\n+<p>\n+If you\'re using an externally supplied package and worry that it might change in\n+unexpected ways, the simplest solution is to copy it to your local repository.\n+(This is the approach Google takes internally.)\n+Store the copy under a new import path that identifies it as a local copy.\n+For example, you might copy \"original.com/pkg\" to \"you.com/external/original.com/pkg\".\n+Keith Rarick\'s <a href=\"https://github.com/kr/goven\">goven</a> is one tool to help automate this process.\n+</p>\n+\n+<p>\n+The <a href=\"/wiki/PackageVersioning\">PackageVersioning</a> wiki page collects \n+additional tools and approaches.\n+</p>\n+\n <h2 id=\"Pointers\">Pointers and Allocation</h2>
 
 <h3 id=\"pass_by_value\">\n```

## GitHub上でのコミットページへのリンク

[https://github.com/golang/go/commit/dc8d9031550e4adc5c83dadd48d9e1e8d0f7ea6d](https://github.com/golang/go/commit/dc8d9031550e4adc5c83dadd48d9e1e8d0f7ea6d)

## 元コミット内容

このコミットは、GoのFAQドキュメント(`doc/go_faq.html`)にバージョン管理に関するFAQを追加します。具体的には、`go get`がパッケージバージョンをどのように扱うか、そしてパッケージのバージョン管理に関する推奨事項について説明しています。これはIssue #5633を修正するものです。

## 変更の背景

このコミットが行われた2013年当時、Go言語には現在のような公式のモジュールシステム(Go Modules)は存在しませんでした。`go get`コマンドは、指定されたインポートパスに基づいて、GitHubなどのリポジトリからパッケージの最新バージョンを直接取得するシンプルな仕組みでした。このアプローチは、開発の初期段階では迅速なプロトタイピングと依存関係の管理を容易にしましたが、以下のような課題を抱えていました。

1.  **バージョンの不安定性**: `go get`は常に最新の`HEAD`を取得するため、依存するパッケージが後方互換性のない変更を行った場合、ユーザーのビルドが突然壊れる可能性がありました。
2.  **再現性の欠如**: 特定のバージョンの依存関係を固定するメカニズムがなかったため、異なる環境や異なる時期に同じコードベースをビルドしても、同じ結果が得られる保証がありませんでした。
3.  **依存関係の衝突**: 異なるパッケージが同じライブラリの異なるバージョンに依存している場合、衝突が発生する可能性がありました。

これらの課題は、特に大規模なプロジェクトや、複数の開発者が関わるチーム開発において顕著でした。開発者コミュニティからは、Goにおけるより堅牢なバージョン管理メカニズムを求める声が高まっていました。

このコミットは、そのような背景の中で、Goチームが当時の公式な見解と推奨プラクティスをFAQとして提供することで、開発者の混乱を解消し、ベストプラクティスを広めることを目的としています。これは、Go Modulesが登場するまでの過渡期における、Goのパッケージ管理戦略の一端を示すものです。

## 前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語の概念と当時のパッケージ管理の状況について理解しておく必要があります。

*   **`go get`コマンド**:
    `go get`は、Go言語のパッケージをリモートリポジトリからダウンロードし、`GOPATH`内の適切なディレクトリに配置するためのコマンドです。当時、このコマンドは常にリポジトリの最新のコミット(`HEAD`)を取得し、特定のバージョンを指定する機能は組み込まれていませんでした。これにより、依存関係の管理がシンプルになる一方で、前述のようなバージョンの不安定性の問題を引き起こす可能性がありました。

*   **インポートパス (Import Path)**:
    Go言語では、パッケージは一意のインポートパスによって識別されます。例えば、`"github.com/user/repo/package"`のような形式です。このインポートパスは、パッケージのソースコードがどこにあるかを示すだけでなく、Goのツールチェインがパッケージを識別し、依存関係を解決するための主要なメカニズムでもありました。同じパッケージ名であっても、インポートパスが異なれば、Goはそれらを異なるパッケージとして扱います。

*   **後方互換性 (Backward Compatibility)**:
    ソフトウェア開発において、新しいバージョンが古いバージョンと互換性があることを指します。Go言語では、特にGo 1のリリース以降、安定したAPIを提供し、後方互換性を維持することが強く推奨されていました。これは、依存関係の不安定性を最小限に抑えるための重要な原則でした。

*   **パッケージのローカルコピー (Vendoring)**:
    当時のGoエコシステムでは、外部依存パッケージのバージョンを固定する一般的な方法として、「ベンダーリング(Vendoring)」、つまり外部パッケージのソースコードを自身のプロジェクトのリポジトリ内にコピーして管理する手法が広く用いられていました。これにより、外部パッケージの予期せぬ変更から自身のプロジェクトを保護し、ビルドの再現性を確保することができました。このFAQで言及されている「Googleが内部で採用しているアプローチ」とは、このベンダーリングを指しています。

*   **`GOPATH`**:
    Go 1.11でGo Modulesが導入されるまで、`GOPATH`はGoのワークスペースの概念を定義する重要な環境変数でした。Goのソースコード、コンパイルされたバイナリ、およびパッケージの依存関係はすべて`GOPATH`内で管理されていました。`go get`はパッケージを`GOPATH/src`以下にダウンロードしていました。

## 技術的詳細

このFAQの追加は、Go言語のパッケージ管理における初期の哲学と、当時の現実的な課題への対応を示しています。

**1. `go get`とバージョン管理の非存在**:
FAQの冒頭で明確に述べられているように、「`go get`はパッケージのバージョンに関する明示的な概念を持っていません」。これは、Goチームがバージョン管理の複雑さを認識し、特に大規模なコードベースにおいて、あらゆるGoユーザーに強制できるほど「うまく機能するアプローチ」が存在しないと考えていたことを示唆しています。この考え方は、Goがシンプルさと実用性を重視する設計哲学と一致しています。

**2. インポートパスによる分離**:
バージョン管理の概念がない代わりに、Goは「異なるインポートパスを持つパッケージの分離」を提供します。これは、たとえパッケージ名が同じであっても(例: `html/template`と`text/template`が両方とも`package template`であるように)、インポートパスが異なれば、それらは完全に独立したパッケージとして扱われるというGoの基本的な設計原則を強調しています。このメカニズムが、Goにおける依存関係の衝突を回避する主要な手段でした。

**3. パッケージ作者へのアドバイス**:
FAQは、公開されるパッケージの作者に対して、進化するにつれて後方互換性を維持するよう強く推奨しています。これは、Go 1互換性ガイドライン(Go 1 compatibility guidelines)を参照しており、具体的には以下の点を挙げています。
*   エクスポートされた名前を削除しない。
*   タグ付き複合リテラルを推奨する。
*   異なる機能が必要な場合は、既存のものを変更するのではなく、新しい名前を追加する。
*   完全に互換性を破る変更が必要な場合は、新しいインポートパスを持つ新しいパッケージを作成する。
このアドバイスは、Goエコシステム全体の安定性を維持するための重要な指針でした。

**4. パッケージ利用者へのアドバイス(ローカルコピー/ベンダーリング)**:
外部パッケージが予期せぬ変更を行うことを懸念する利用者に対しては、「最も簡単な解決策は、それをローカルリポジトリにコピーすること」と提案しています。これは、Googleが内部で採用しているアプローチであると明記されており、当時のGoコミュニティで広く行われていた「ベンダーリング」というプラクティスを公式に推奨するものです。ローカルコピーは、新しいインポートパス(例: `you.com/external/original.com/pkg`)の下に保存することで、元のパッケージとの混同を避けることができます。`kr/goven`のようなツールが、このプロセスを自動化するのに役立つと紹介されています。

**5. PackageVersioning Wikiページへの言及**:
最後に、`PackageVersioning`というWikiページが、追加のツールやアプローチを収集していると述べられています。これは、Goチームがバージョン管理の問題に対する単一の「銀の弾丸」が存在しないことを認識し、コミュニティが様々な解決策を模索していることを認めていたことを示しています。

このFAQは、Go Modulesが登場する前のGoのパッケージ管理における「ベストエフォート」なアプローチを体系的にまとめたものであり、Goの設計哲学であるシンプルさと実用性を反映しています。

## コアとなるコードの変更箇所

このコミットは、`doc/go_faq.html`ファイルに以下のHTMLスニペットを追加しています。

```diff
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -1029,6 +1029,42 @@ these two lines to <code>~/.gitconfig</code>:
 </li>
 </ul>
 
+<h3 id="get_version">
+How should I manage package versions using "go get"?</h3>
+
+<p>
+"Go get" does not have any explicit concept of package versions.
+Versioning is a source of significant complexity, especially in large code bases,
+and we are unaware of any approach that works well at scale in a large enough
+variety of situations to be appropriate to force on all Go users.
+What "go get" and the larger Go toolchain do provide is isolation of
+packages with different import paths.
+For example, the standard library's <code>html/template</code> and <code>text/template</code>
+coexist even though both are "package template".
+This observation leads to some advice for package authors and package users.
+</p>
+
+<p>
+Packages intended for public use should try to maintain backwards compatibility as they evolve.
+The <a href="/doc/go1compat.html">Go 1 compatibility guidelines</a> are a good reference here:
+don't remove exported names, encourage tagged composite literals, and so on.
+If different functionality is required, add a new name instead of changing an old one.
+If a complete break is required, create a new package with a new import path.</p>
+
+<p>
+If you're using an externally supplied package and worry that it might change in
+unexpected ways, the simplest solution is to copy it to your local repository.
+(This is the approach Google takes internally.)
+Store the copy under a new import path that identifies it as a local copy.
+For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg".
+Keith Rarick's <a href="https://github.com/kr/goven">goven</a> is one tool to help automate this process.
+</p>
+
+<p>
+The <a href="/wiki/PackageVersioning">PackageVersioning</a> wiki page collects 
+additional tools and approaches.
+</p>
+
 <h2 id="Pointers">Pointers and Allocation</h2>
 
 <h3 id="pass_by_value">\n```

この変更は、既存のFAQセクションの後に、新しい`<h3>`見出しとそれに続く複数の`<p>`タグで構成される新しいセクションを追加しています。

## コアとなるコードの解説

追加されたHTMLスニペットは、Goのパッケージバージョン管理に関するFAQの回答を構成しています。

1.  **見出し (`<h3>`)**:
    `How should I manage package versions using "go get"?`
    この見出しは、ユーザーが`go get`を使用してパッケージバージョンをどのように管理すべきかという疑問に直接答えることを意図しています。

2.  **最初の段落 (`<p>`)**:
    `"Go get" does not have any explicit concept of package versions. Versioning is a source of significant complexity, especially in large code bases, and we are unaware of any approach that works well at scale in a large enough variety of situations to be appropriate to force on all Go users. What "go get" and the larger Go toolchain do provide is isolation of packages with different import paths. For example, the standard library's <code>html/template</code> and <code>text/template</code> coexist even though both are "package template". This observation leads to some advice for package authors and package users.`
    この段落は、`go get`が明示的なバージョン管理の概念を持たないことを明確に述べています。そして、バージョン管理の複雑さに触れ、GoチームがすべてのGoユーザーに強制できるような普遍的な解決策を見出していないことを示唆しています。その代わりに、Goツールチェインが提供するのは「異なるインポートパスを持つパッケージの分離」であると説明し、標準ライブラリの`html/template`と`text/template`の例を挙げています。この前提に基づいて、パッケージの作者と利用者へのアドバイスが続くことを示唆しています。

3.  **二番目の段落 (`<p>`)**:
    `Packages intended for public use should try to maintain backwards compatibility as they evolve. The <a href="/doc/go1compat.html">Go 1 compatibility guidelines</a> are a good reference here: don't remove exported names, encourage tagged composite literals, and so on. If different functionality is required, add a new name instead of changing an old one. If a complete break is required, create a new package with a new import path.`
    この段落は、公開パッケージの作者に向けたアドバイスです。進化するにつれて後方互換性を維持するよう推奨し、Go 1互換性ガイドラインを参照するよう促しています。具体的なアドバイスとして、エクスポートされた名前の削除を避けること、タグ付き複合リテラルを推奨すること、機能変更が必要な場合は新しい名前を追加すること、そして完全に互換性を破る場合は新しいインポートパスを持つ新しいパッケージを作成することを挙げています。

4.  **三番目の段落 (`<p>`)**:
    `If you're using an externally supplied package and worry that it might change in unexpected ways, the simplest solution is to copy it to your local repository. (This is the approach Google takes internally.) Store the copy under a new import path that identifies it as a local copy. For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg". Keith Rarick's <a href="https://github.com/kr/goven">goven</a> is one tool to help automate this process.`
    この段落は、外部パッケージを利用するユーザーに向けたアドバイスです。予期せぬ変更を懸念する場合の最も簡単な解決策として、パッケージをローカルリポジトリにコピーすること(ベンダーリング)を推奨しています。これはGoogleが内部で採用しているアプローチであると明記し、ローカルコピーを新しいインポートパスの下に保存する例(`you.com/external/original.com/pkg`)を示しています。また、このプロセスを自動化するツールとして`goven`が紹介されています。

5.  **四番目の段落 (`<p>`)**:
    `The <a href="/wiki/PackageVersioning">PackageVersioning</a> wiki page collects additional tools and approaches.`
    この段落は、GoのWikiにある`PackageVersioning`ページが、バージョン管理に関する追加のツールやアプローチを収集していることを示し、さらなる情報源を提供しています。

これらの段落は、当時のGoのパッケージ管理におけるバージョン管理の課題に対する公式な見解と、開発者が採用すべき具体的なプラクティスを体系的に説明しています。

## 関連リンク

*   **Go 1 compatibility guidelines**: [https://go.dev/doc/go1compat](https://go.dev/doc/go1compat) (コミット当時のリンクは `/doc/go1compat.html` でしたが、現在は `go.dev` にリダイレクトされます)
*   **PackageVersioning wiki page**: [https://go.dev/wiki/PackageVersioning](https://go.dev/wiki/PackageVersioning) (コミット当時のリンクは `/wiki/PackageVersioning` でしたが、現在は `go.dev` にリダイレクトされます)
*   **goven (Keith Rarick's tool)**: [https://github.com/kr/goven](https://github.com/kr/goven)

## 参考にした情報源リンク

*   Go Modulesの歴史と背景に関する一般的な知識
*   Go言語の公式ドキュメントとFAQ
*   当時のGoコミュニティにおけるパッケージ管理に関する議論(Issue #5633など)
*   Russ Cox氏のGo Modulesに関する発表や記事(このコミットの時点ではGo Modulesは存在しませんが、後のGo Modulesの設計思想を理解する上で参考になります)
*   `go get`コマンドの当時の挙動に関する情報