vgoを今やり始めると辛いからやめとけ

注意

ここの記事で書かれている操作は、 https://github.com/golang/go/issues/24917 で報告した https://github.com/ory/fosite-example をvgoでビルドしようとして検証しています。

利用したvgo

  • golang.org/x/vgo203abfb0741bf96c7c5e8dab019f6fe9c89bded3 の時点で go get -u golang.org/x/vgo したもの
  • go version go1.10.2 darwin/amd64 vgo:2018-02-20.1

TL;DL

思った通りの状態にならない。
ライブラリ作者全員semverで殴って回る必要がある。
ログから情報が得られない。
実行もクソ遅い。
ゆえに辛い。

まずはじめに

Goユーザは $GOPATH の中で生きている。
アプリケーションのパッケージ管理のため、vendoringの仕組みができた。
パッケージマネージャとしてgbとかdepとか色々なものがあった。

あったけど、最終的にgoコマンドに組み込みとなる、最終的なパッケージ管理の仕組みが生まれようとしている。
vgoだ。
今はvgoという名前だけど、最終的にはgoに組み込まれる(はずだ)。
このproposalは既にacceptedになっていて、未来は確定しつつあります。

この記事ではこれ以上のvgoについての説明を行わない。
詳しく知りたい人は、Go & Versioning[和訳]を読むといいだろう。

vgoのここが良い!

まずは良いところを。

$GOPATH free

プロジェクトを配置する場所が $GOPATH 配下に限定されなくなります。
好きな場所に置いてよい!やったー!

SemVerの採用とタグベースの運用

Goもsemverで運用されていきます。
何かしら更新があれば、gitでtagを打ちpushされる世界になるでしょう。
この文化が浸透すれば、依存しているライブラリのバージョンアップは非常に容易な作業になっていくでしょう。
npmにpublishしているユーザがみんなお行儀よくなっていったように、Goコミュニティもsemverに慣れていくでしょう。

同一ライブラリの異なるバージョンへの依存への(文化的)解決

複数のライブラリを使う場合、依存関係的には孫にあたるライブラリが重複し、かつ異なるバージョンを参照したい場合があります。
これは、今までの単層のvendoringでは難しかったのですが、これに対して github.com/vvakame/hoge/v1github.com/vvakame/hoge/v2 に分けておけばいいじゃない という斜め上の解決が行われました。

斜め上といえば斜め上なんですが、旧バージョンについてもpatchを受け付けられるとか、管理がしやすくなるという点で良いこともあります。

素直に読むと、リポジトリのrootに置いてあるコードは互換性のためにずっと残しておけ、みたいなことを言っててヤベーこと言いよる…という気持ちです。
でもまぁこれは v0 を切って、最初はそこで開発するなどの開発者側のワークアラウンドでなんとかなるレベルかもしれません。

あとは、エディタがpackage内でちぐはぐなバージョンを自動的にimportしないように気をつける必要があります(つらそう

goコマンドに組み込み

単にgit cloneして、 vgo test all とかすれば、依存ライブラリを自動的に取ってきてくれて動きはじめる!
ライブラリ追加したければ vgo get go.mercari.io/datastore とかやるだけ!
すごい!楽!わかりやすい!初心者の味方!

vgoのここがヤバい

ついでやばいところを述べていきます。

中途半端にタグがついているリポジトリ

google.golang.org/appengine はアクティブに開発されているリポジトリだが、2016年に v1.0.0 タグが切られ、その後は何もない
vgo(やdep)で単純に google.golang.org/appengine を追加すると、2年も前のリビジョンを使わされてしまう!
辛いですね。

この問題はライブラリ作者全員がヤル気を出し、ちゃんとタグをつける運用を開始したら解決されます。
ライブラリ作者全員をsemverで叩いて回りましょう。

使えない master/HEAD

上記の問題を解消するには、 vgo get google.golang.org/appengine@master を実行すれば…。
と思いきや、コレでもダメで、 v1.0.0 にされてしまいます。
vgo get google.golang.org/appengine@b1f26356af11148e710935ed1ac8a7f5702c7612 も同様。
go.mod 中の requiregoogle.golang.org/appengine master に書き換えて vgo get -u しても v1.0.0 に戻される…。

どうすればいいんですかね…?
なにがどうなってどう go.mod が書き換わったのか、というのがログから全く読み取れない…。
気持ちよく動いてる間は便利なのかもしれないけど、意図通りにならない時に完全にブラックボックス化していて辛い。
しかもこのブラックボックスは将来的に go 本体に組み込まれてしまい回避不可能になるんだぜ…。

この問題はライブラリ作者全員がヤル気を出し、ちゃんとタグをつける運用を開始したら(masterを使いたいという欲求がなくなるので)解決されます。

いつの間にか巻き戻るバージョン、消えるパッケージ

vgo get google.golang.org/appengine@master すると何故か require に書かれるパッケージが減ります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
diff --git a/go.mod b/go.mod
index 4c08ba1..d2f7a72 100644
--- a/go.mod
+++ b/go.mod
@@ -2,28 +2,24 @@ module github.com/ory/fosite-example

require (
github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f
- github.com/davecgh/go-spew v1.1.0
github.com/dgrijalva/jwt-go v1.0.2
github.com/golang/mock v1.1.1
github.com/golang/protobuf v1.1.0
github.com/gorilla/context v1.1.1
github.com/gorilla/mux v1.6.2
- github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69
github.com/jtolds/gls v0.0.0-20170503224851-77f18212c9c7
github.com/magiconair/properties v1.8.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b
github.com/oleiade/reflections v1.0.0
- github.com/ory/fosite v0.20.3
+ github.com/ory/fosite v0.12.0
github.com/ory/go-convenience v0.0.3
github.com/parnurzeal/gorequest v0.2.15
github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3
github.com/pkg/errors v0.8.0
- github.com/pmezard/go-difflib v1.0.0
github.com/smartystreets/assertions v0.0.0-20180607162144-eb5b59917fa2
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a
github.com/stretchr/objx v0.0.0-20180531200725-0ab728f62c7f
- github.com/stretchr/testify v1.2.1
golang.org/x/crypto v0.0.0-20180606015541-b47b15873692
golang.org/x/net v0.0.0-20180530234432-1e491301e022
golang.org/x/oauth2 v0.0.0-20180603041954-1e0a3fa8ba9a

なんでやねん。
google.golang.org/appengine は変わってないくせに…。
何がどうなってこうなったのかはログからは全くわかりません。

本当に最新なのかわからない vgo list -m -u

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ vgo list -m -u
MODULE VERSION LATEST
github.com/ory/fosite-example - -
github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f -
github.com/davecgh/go-spew v1.1.0 (2016-10-30 05:57) -
github.com/dgrijalva/jwt-go v1.0.2 (2014-08-27 05:51) -
github.com/golang/mock v1.1.1 (2018-04-06 06:54) -
github.com/golang/protobuf v1.1.0 (2018-05-01 03:52) -
github.com/gorilla/context v1.1.1 (2016-08-18 03:46) -
github.com/gorilla/mux v1.6.2 (2018-05-13 12:22) -
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 -
github.com/jtolds/gls v0.0.0-20170503224851-77f18212c9c7 -
github.com/magiconair/properties v1.8.0 (2018-05-16 05:40) -
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 -
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b -
github.com/oleiade/reflections v1.0.0 (2016-08-17 15:46) -
github.com/ory/fosite v0.12.0 (2017-10-25 19:16) v0.20.3 (2018-06-07 19:52)
github.com/ory/go-convenience v0.0.3 (2018-05-29 20:36) -
github.com/parnurzeal/gorequest v0.2.15 (2017-02-21 02:20) -
github.com/pborman/uuid v0.0.0-20180122190007-c65b2f87fee3 -
github.com/pkg/errors v0.8.0 (2016-09-29 10:48) -
github.com/pmezard/go-difflib v1.0.0 (2016-01-10 19:55) -
github.com/smartystreets/assertions v0.0.0-20180607162144-eb5b59917fa2 -
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a -
github.com/stretchr/objx v0.0.0-20180531200725-0ab728f62c7f -
github.com/stretchr/testify v1.2.1 (2018-02-01 07:38) -
golang.org/x/crypto v0.0.0-20180606015541-b47b15873692 -
golang.org/x/net v0.0.0-20180530234432-1e491301e022 -
golang.org/x/oauth2 v0.0.0-20180603041954-1e0a3fa8ba9a -
golang.org/x/text v0.3.0 (2017-12-14 22:08) -
google.golang.org/appengine v1.0.0 (2016-09-30 05:31) -

上から順に見てVERSIONがくっそ古い jwt-go を適当に見に行ってみました。
最新はv3.2.0です。
確かに、 ^1.0.0 の範囲だと v1.0.2 は LATESTなんですが、プロジェクトを健全に保つために知りたいLATESTは v3.2.0 だと思います。
vgo get github.com/dgrijalva/jwt-go しても v3.2.0 にはなりません。
vgo get github.com/dgrijalva/jwt-go@v3 してみたら go.mod から jwt-go が消えました。
一体全体どういうことだってばよ…。
何がどうなってこうなったのかはログからは全くわかりません。

ひたすらに遅いコマンド類

1
2
$ time vgo list -m -u
vgo list -m -u 1.60s user 0.89s system 8% cpu 28.836 total

何回も実行した上でコレです。
初めて vgo get google.golang.org/appengine@master を実行した時はカップラーメンのためにお湯を沸かしてお湯入れて待って食べてSplatoon2起動するぐらいの時間がかかりました。

まとめ

この中で何が起こってるかもよくわからず --help でロクな情報が得られないシステム、誰が使えるの???
ストレスでハゲそう。

この記事は社内Slackでクダをまいてたらそれを#4 Open Go Fridayで話せと @tenntenn さんに言われたので書かれました。