この記事はQiitaで公開されていました
このQiita記事は、Go & Versioningで掲載された一連の記事を読んで、自分なりのまとめと感想です。私の周りはあまり騒いでないけど、これ感覚的なものが大きく変わるなあ、と思ったので、主に表面上に現れる変更をまとめました。
これは、Go 1.11で試験的な導入、Go 1.12で正式サポートとなる予定の機能に関する話です。
@nekketsuuuさんが原文の和訳をされています。
何が変わるのか
バージョン管理機能の導入
go
コマンドにバージョン管理の機能が追加されます。バージョンは常にセマンティックバージョニングで表します。今もdep
コマンドが(go
とは別に)存在しますが、バージョン管理機能が追加されたgo
コマンド(以下vgo
と表記)は、dep
やglide
などの依存管理ツールとは別のアプローチでバージョンを管理します。とはいえ、目的はどちらもバージョン管理なので、vgo
を使う場合はdep
を使いません。また、vgo
はvendorディレクトリを使わないためvendorも不要です。
モジュールという単位の追加
バージョン管理機能に伴って、Goのパッケージにモジュールという単位が追加されます。モジュールは複数のパッケージをまとめたもので、go.modというファイルで管理します。Go & Versioningでは以下の例が記されていました。
// My hello, world module "rsc.io/hello" require ( "golang.org/x/text" v0.0.0-20180208041248-4e4a3210bb54 "rsc.io/quote" v1.5.2 )
モジュールは、vgo
でバージョン管理を行う基本的な単位となります。1つのリポジトリが1つのモジュールに該当し、タグ(git tag
)を使ってモジュールにバージョンを与えます。従って、バージョン管理を行う単位はモジュールです。例えば、上のgo.modでリストされているgolang.org/x/text
とrsc.io/quote
もモジュールです。今まではパッケージという扱いでしたが、モジュールに変わります。
モジュールのアップデートはvgo get
モジュールはgo.modファイルでバージョンを指定しますが、これを人が維持するのは大変です。vgo get
で必要なモジュールを追加したり、vgo get -u
でアップデートを行ったりするようです。
たくさんのExampleが書かれているのでA Tour of Versioned Goを眺めてみてください。これだけで雰囲気はつかめると思います。
破壊的変更を加える場合はimport pathを変更する
vgo
で扱うパッケージは、全て後方互換性を持たなければなりません。例えばA
というパッケージの作者は、メジャーバージョンが同じ間は後方互換性を維持する必要があります。この制約によって、v1.1.0を参照しているプログラムは、v1.2.1が使われた場合でも同じように動作することが保証されます。もしマイナーバージョンのアップデートでビルドが壊れた場合、A
はv1.2.2で過去の互換性を取り戻すべきです。例えば、関数の動作を変更する場合は、仕様変更ではなく名前を変えて新しい関数として追加しましょう。
とはいえ、どうしても破壊的な変更が避けられないケースは存在します。その場合はimport pathを変更することで別のパッケージとして作成してください。例えば、lufia.org/pkg/x
に破壊的変更を加える場合、新しいバージョンはlufia.org/pkg/x/v2
のようにメジャーバージョンを含むimport pathにしましょう。そうするとv1
とv2
で重複する部分がソースコードの二重管理になりがちですが、それはtypealias
等を使って頑張ってください。
最初からimport pathをlufia.org/pkg/x/v1
のようにするべきかについては、最終的にどうなるかは分かりませんが、個人的には「最初はバージョンを含めない」でいいと思います。
$GOPATHが不要になる
これまで$GOPATHはGoワークスペースのルートとして必要でしたが、vgo
ではgo.modによってモジュールのURLやバージョンが明確に特定できるため、$GOPATHがなくてもソースコードの取得やビルドの再現性には困りません。参照するモジュールのマイナーバージョンは上がるかもしれませんが、マイナーバージョンの変更はモジュール作者の努力によって互換性が維持されるため、最終的な動作は変わらないことが保証できます。
これによって、任意のディレクトリでGoのコードを書くことが可能となります。今までのように、$GOPATH配下にワークスペースを構築する必要は無くなります。
ただこれ疑問なのは、今までの$GOPATH直下には
$ ls $GOPATH bin pkg src
が存在していて、まあsrcとpkgは無くてもいいかなと思うのですが、go get
でインストールする場所としての$GOPATHはどうなるんだろう?と思いました。
何が変わらないのか
今までのコードはそのままビルド可能
vgo
だからといって今までのコードが壊れることはありません。$GOPATHもvendorも、不要になるだけで、そのまま使えます。go.modがないリポジトリもそのままビルドできるはずです。
dep
はvgo
が普及するまでは残る
長期的にみればdep
は無くなるのかもしれませんが、少なくともvgo
がリリースされて、十分に普及するまでは継続することが書かれていました。今すぐ何かが変わることはないので、そのまま使い続けても問題ないと思います。
今後の話
vgo
は、この記事の最初にも書きましたけれど、Go 1.11で試験的な導入、Go 1.12で正式サポートとなる予定です。今はまだGo 1.10がリリースされたばかりなので何もしなくても良いと思いますが、半年後にGo 1.11がリリースされたら、特にパッケージ作者は以下のことに注意しましょう。
- go.modを作成しましょう
- セマンティックバージョニングでタグを打ちましょう
- import pathが同一である限り後方互換性を維持しましょう