収録時間: 51:12 | Download MP3 (37.3MB)
Daisuke Makiさんをゲストに迎えて、Go言語について話しました。
- The Go Programming Language
- stf-storage/go-stf-server
- Go Object Oriented Design
- Go言語での構造体実装パターン
- Defer, Panic, and Recover - The Go Blog
- Error handling and Go - The Go Blog
- Tokyo Golang Developers - Meetup
- template
- How to Write Go Code (GOPATH)
- GoDoc
- Read the Docs
- theplant/pak
- mattn/gom
- Martini - Classy web development in Go.
- #117: Go, Martini and Gophercasts with Jeremy Saenz - The Changelog
- lestrrat/go-xslate
- jteeuwen/go-bindata
- braintree/manners
- lestrrat/go-server-starter-listener
- smartystreets/goconvey
- GopherCasts
- Toward Go 1.3
- gopkg.in - Stable APIs for the Go language
0:00
miyagawa: 今日で2回目だよね、これ出てもらうの。
lestrrat: 2回目ですね。
miyagawa: lestrrat さんこと、牧さんです。
lestrrat: 牧です。よろしくお願いします。
miyagawa: 牧さんといえば、前出てもらったときも Perl の関係の YAPC とかでお馴染みだと思うんですけど。最近、GitHub とか Twitter とかの活動状況見てると、別のことをずっとやっていそうな雰囲気がすごいあってですね。それは何かというと、Go、Golang ですね。で、結構その辺の話を他のゲスト、例えば typester さんのときとかにちょこっと話したりしたんですけど、Go が盛り上がってる感があるんでその辺をまた話してみたいな、という感じですね。
lestrrat: 本当のこと言うと、mattn さんの方がこの話はいいような気もするんだけど。
miyagawa: (笑)
lestrrat: まあ、いちユーザーとしては僕の方が多分ユーザー側に偏ってるんでいいのかもしれないですね。
miyagawa: Go をどれくらいのタイミングでやろうと思ったんですかね?
lestrrat: タイミング的には、去年の YAPC 前くらいから少し触ったのかなぁ。だから、夏くらいっすね。
miyagawa: それはどういうキッカケがあったんですか?
lestrrat: 元々、Perl に嫌気がさしたというわけではなくて、単純に10年以上 Perl やってるから、もういいかげん、まともな、ただ「ちょっと書ける」っていうだけじゃなくて、ちゃんとチームでガッツリ出来ますよっていう第二言語を作ろうかな、と思ってて。C とかはできるけども、そっちの方じゃなくてもう少し Lightweight なのがいいかな、と思ってて探してたんですよね。
で、Ruby も Python も表に出さないで色々書いたりしたんだけど、いまいちピンと来なくて。で、Go を書いてみたらガッチリ「あ、これいいな」と思えたので、割とその後は極めるというか、ちゃんと分かるとこまで持って行きたいなと思って色々やってる感じですね。
miyagawa: さっき C って話があったけど、Go が出てきたときって Google が出したってのもあるから、C++ なのを置き換える感じなのか、それともスクリプティング言語、Perl とか Python とかそっち系を補完するような感じなのかってのが最初のころは僕はよく分からなくて。そういう見方ってのはどうっすかね?
lestrrat: どっちっすかねー。基本は C とか C++ なんだけど LL くらいの気軽さで動かせるっていうところなんだと思うんすよね。でもやっぱり、コンパイルの手順が面倒ちゃあ面倒。気にならないくらいの速さなんだけど、Perl や Ruby をガツッと動かすあの感覚とは違いますね。
miyagawa: 一旦コンパイルってのが間に入るっていうね。
lestrrat: そうそう。で、やっぱりデプロイとかはバイナリを作りなおさないとダメとか、そういうのもあるから。実務的には大差ないんだけど、頭のなかで置き換えをしないと時々つまづく。
miyagawa: なるほどね。最初はそういう第二言語的な部分で試してたり遊んだりしたって感じだと思うんですけど。見てると業務的なところでも使ってたりする感じですよね。
3:26
lestrrat: といっても、本当に業務で使えてはいないんですよね。なんでかっていうと、単純に運用だったり、既に存在するソフトウェアをそれで置き換える必要はない。だから、新規の案件がちょっとあって、なおかつある程度 Ops の人とかがデバッグとかするときに余裕がある状態であれば Go でもいいかな、とは思ってるんですけど。
そうじゃなくて、今までの体制があって、そこにいきなりポンっと放り込んだときに、Ops の人がやばい状況で僕がいないときにどうにかしなきゃいけないことがあるかもしれない。そういうことが起こりえるときは使わないようにはしてますけどね。
miyagawa: 自分が SPOF にならないようにするっていうことだよね。
lestrrat: ていうか、今は SPOF にならざるをえないんで、いきなりガツンとは入れられなかったっていうとこですよね。
miyagawa: でも、その辺も徐々に本番とかで使っていけばたまっていく感じですかね。
lestrrat: そうっすね。特に今まで Perl とかで出来てた、サクッと strace して「あ、このファイル読み込みが数が多い」とか、そういったことがまだノウハウとして蓄積されてないからググってもサッと出てこないし。そういうところがたまってくれば割と行けるんじゃないかな、って感じですね。
miyagawa: なるほどね。ちょっとガンガン飛ばして話しちゃいましたけど(笑)
lestrrat: (笑)
5:00
miyagawa: 見てると、最初、牧さんの書いてる STF っていうファイルストレージなのかな。それの一部を Go で書いてみるぞ、みたいな話をしてたと思うんですけど。その辺をちょっと話してもらえますかね。
lestrrat: STF は結局、書いたけど今まだちゃんと Production でも Dev でも動いてなくて。一応動くとこまでは行ったんですけどね。
miyagawa: その前に、そもそも STF についてちょっと説明して欲しいんですけど。
lestrrat: あ、そうだ。STF は分散オブジェクトストレージなんで、要は S3 を自分のデータセンターに置きたいならこれを使ってください、的な感じですね。似たようなのだと MogileFS とかがありますけど。
miyagawa: それはストレージは普通のファイルシステムを使うんですか?
lestrrat: そうですね。HTTP を通して普通に PUT/DELETE/GET/POST とかして、ただファイルシステムにぼこぼこ置いていくだけです。
miyagawa: それは、いま運用してる分に関しては Perl とか Plack とかで書いてある感じ?
lestrrat: そうですね。今は完全に Perl で書いてあって。元々は mod_stf っていう Apache のモジュールだったやつを Perl に置き換えて。もう3~4年はずっと Perl で、とあるブログの画像とかを全部裏で配信やってます。
miyagawa: そうね、いま言おうと思ってたけど、ブログに書いてあるからあれなんだろうけど(笑)某ブログの画像とかをさばいてるってことですよね。
lestrrat: はい。
miyagawa: じゃあ、それの一部を Go で書いてみよう、みたいな感じですか?
lestrrat: そうっすね。ほぼ全部書いて、色々やってみたんすけど。あれを書いた一番の理由は、リプレースはあわよくばと思ったんですけど、それよりは練習の意味合いが強くて。ある程度の大きさのプロジェクトで、なおかつ僕が1から10まで全部わかってるから、全部 Go で書き直せるプロジェクトでやってみたって感じですね。
miyagawa: 具体的にはどの部分なんですか?
lestrrat: いや、ほんとに全部っすよ。一番最初のリクエスト受けるところから、後ろのストレージと Worker でオブジェクトの数を調節するとか、そういうとこまでひと通り。2~3個 Worker 抜けてるけど、基本の部分は全部書きました。
miyagawa: じゃあ、一部だけをやってみるんじゃなくて、最初の Web サーバーみたいな通信受けつけるとこから、ファイルストレージに書き込むとこまで全部ってこと?
lestrrat: そうです。
miyagawa: そういうのって、新しい言語を学ぶときとか、"Hello World" みたいなものから始めて書きたいものをちょこちょこっと書いてく、みたいなのはあると思うんだけど。実際に動いてるものを書きなおしてみるってのは結構面白いアプローチだと思うんですけど。
lestrrat: うーん、どうなんですかね。そこを別に一般の人にオススメするわけではないですけど、僕の場合は割と裏側のシステムのマネジメント、ファイルを動かしたりデータを動かしたりとかそっちの方を Go で書きたいと思ったんで。そういうことも含めて全部マルっとできるアプリケーションがあれだったんですよね。だから、これをもし port できたら、俺なんでもできるなって思って。
miyagawa: (笑)じゃあ自分で Perl で全部最初から最後まで知ってるのがあるから、それを Go で書ければ、ってことですよね。
lestrrat: そうっすね。
8:30
miyagawa: 実際書いてみて、「こういうところが Perl より書きやすい」とか、「こういうところはちょっと苦手だな」みたいなのあったんすか?
lestrrat: やっぱり Goroutine があるし、しかもすごい軽いから気軽に thread を作ることができるんで、用途がバッチリ合えばすごくよかったです、それは。あと、Channel の概念も、あれを使って lock の代わりとかにもできるし、何にでも使えてよかったな、って気がしますね。やっぱり、Go の売り文句の Goroutine であったり Channel であったりはすごく使いやすかった。
miyagawa: 他の言語、例えば Perl だと、ちょっと亜流かもしれないけど、Coro っていう coroutine を実装してるものがあって。そういうのとか、あとは非同期系のライブラリとかを使ってると、割とすんなりと入っていけそうな感じだよね。
lestrrat: そうっすね……でもなんかちょっと違うのは、非同期系のライブラリだと思ってやってくと thread の方が近いから。非同期だと callback を色々うまく使うとかそういう形じゃないですか。何にも意識しなくていいのが Goroutine とかのいいところですね。Channel かな、Channel の部分は AnyEvent とかを知ってるとすごくわかりやすいと思う。
miyagawa: そうね。Perl の人しかわかんないかもしれないけど、AnyEvent の Conditional Variables みたいなやつとかだとかなり似た概念だと思うんで。
あれですか、牧さんは Node とかちょっとやってたの?
lestrrat: うーん、あれも「触った」くらいっすね。
10:06
miyagawa: 結構、Node と Golang を、Concurrency、並列処理が必要な環境で「どっちを選択するか」みたいなのがたまに話題にあがったりするんだけど、それについては意見あります?
lestrrat: Node の方そこまで知らないからなんとも言えないかな。ただ、僕は個人的な趣味で JavaScript 系の言語ちょっと苦手意識があるので、それが僕の中では大きい。
miyagawa: さっきも言ってたけど、Node の場合は基本的に非同期で Callback っていう感じの実装だから、そこは結構気にしなきゃいけなくて。 Go だとね、Goroutine とか Channel とかでできるのはね、楽っていうと違うのかもしれないけど、結構すんなりいけるのかな、っていうのはありますよね。
lestrrat: でも、stdio とか stdout とかあの辺を別プロセスで fork したりして IO とかをハンドリングしつつ、非同期で親のほうで読み込むとかあるじゃないですか。プロセスいっぱい作って、そのアウトプットだけ欲しい、とか。それをメインのプロセスは非同期でやってるとか。そういうコードが Golang だと3〜4行で書けるからすごいよかった。
miyagawa: そうだよね。そういうのを Perl とかでやろうとすると kazeburo さんとか奥さんとかが書いた秘伝のライブラリを持ってきてゴニョゴニョやんなきゃいけないけど。
lestrrat: そうなんすよー。
miyagawa: なるほどね。さっき、軽量言語とか C とかの置き換え、とかいう話あったんですけど、Go のオブジェクト指向、「そもそもオブジェクト指向なのか」みたいな話もあるんですけど。僕もちょっとやってみて、最初のうちはシンタックスも含めてオブジェクト指向が素直に実装できる感じではないな、と思ったんですけど、その辺は?
lestrrat: あれはね、miyagawa さんはまだ色々考えてる途中なんだろうけど、オブジェクト指向があると思ってちゃいけないと思うんですよね。
miyagawa: (笑)
lestrrat: で、それをいったん割り切れるときれいに書けると思うんですけど。Superclass だ云々だ、と考えようとするとダメですね。
miyagawa: なるほどね。
lestrrat: あれはね、なんて言えばいいんだろ。ちゃんと Go のなかにそういう term が定義されてるかどうか知らないですけど、Interface ベースで考えなきゃいけなくて。API 共通はできるけど、オブジェクト指向はない。
miyagawa: (笑)例えば JavaScript 組み込みのオブジェクト指向っていうのは、クラスがなくてプロトタイプで、みたいなところがあるけど。そういうのとは全然違うものだけど似てもいて。要はクラス的なものはやろうと思えばできるけどちょっと違う。そういうイメージですね。
lestrrat: 僕のなかでどういう分類したかというと、「やっぱりこれは C なんだ」と。これは構造体なんだ、ってことだけにして。シンタックスも便宜上レシーバーを構造体にすることができるんだけど、ここにオブジェクトは存在しないって思うときれいに書けた。
miyagawa: なるほどね。よくできた C のライブラリとかオープンソースのコードとかって、第1引数に struct を渡して普通にオブジェクト指向っぽくなってたりするけど、それに近いって感じだよね。
lestrrat: そうそう、それに近い。で、代わりといってはなんだけど、struct のtype を明示するんではなくて Interface を定義できるから、オブジェクト指向っぽく型を明示する必要のない書き方ができる。
miyagawa: Ducktyping とかそういうのができる。
lestrrat: だから、C with ducktyping なのかも。
miyagawa: それは結構おもしろい考え方だね。
lestrrat: オブジェクトを作ろうとして Superclass だなんだと考え始めると無理があることにあっという間に気づくんで。それをちょっと前に話し合ったんですけど。誰かがパターンとして書いてたじゃないですか、ブログで。ちょっと今 URL 忘れちゃった。
miyagawa: 見つけたらあとで Show Notes に貼っときます。
lestrrat: それとかを見てて思ったのが、こういう Cheat sheet はあってもいいんだけど、それよりも何よりも Golang をやりたい人はオブジェクトという概念をとりあえず一回忘れるということが必要なんだな、と思って。
miyagawa: (笑)それは例えば Perl4と5のちょうど中間みたいな感じで、Package はあってメソッドは Package に存在させられるけど、それ以上のメタクラスとかシュガーみたいなものはほとんど存在しない、みたいな感じっすかね。
lestrrat: そうっすねー。
miyagawa: 例えば最近の Podcast でも Objective-C の話とかもしていて。Go と Objective-C と Perl の組み合わせは、一見すると違うように見えるかもしれないけど割と結構似てるものがあるなぁ、と思ったりするんですよ。字面的には全然違うんだけど、C 言語ベースのシンタックスで組み込みに hash とか dictionary と array と string があって、メソッドが Package 的なものに紐付けできて。その辺がすごくね、Perl から来た人にとってはわかりやすいというか、ゴチャゴチャしてないところが割り切りがいいな、と思ったんすよね。
lestrrat: そうっすね。あと、Perl の人だけに限って言うと、なんでも bless できるのがすごくいい。
miyagawa: それどういうこと?
lestrrat: 例えば、boolean type を自分でタイプ名つけてエイリアスするんですね。
miyagawa: はいはい。
lestrrat: で、そのエイリアスしたタイプ名をレシーバーにしてメソッドを作れるんですよ。だから、boolean をオブジェクトっぽいものに格上げすることが可能なんですよね。あれがすごく、Perl の人にはすごいしっくり来ると思う。
miyagawa: (笑)確かに、それはあるかも。組み込みの型なんだけど、それを自分のクラスで拡張できるみたいな。
lestrrat: ですです。
16:20
miyagawa: ちょっとパターン的に言うと、value object みたいなものを結構作りやすいですよね。なるほどー。
あと、これ今日録ってるのが4月20日なんですけども、配信するのはもうちょっとあとになるかもしれないんです。
で、Go に限らずなんですけど、Twitter とかで Exception handling があるべきかないべきかみたいな話が色々とあって。去年の YAPC::Asia のときとかも Go を最近つまんでる人たちとかで話をしたんですけど、あまりないことに対する不満を聞いたことがなくて。一応ね、Panic とか Recover とかは仕組みとしてはあるんですけど、それを Try - catch みたいにして分岐処理、エラー復帰のためのものとして使うってのはあんまり推奨されてないとは思うんですけど。そのあたりについてはどうっすかね?
lestrrat: まず是非は置いといて、Go において Panic だなんだを例外だと思って使うとそれもまた壁にぶち当たります。実際にそれが STF を Go で書いてるときにあって。最初は Perl のバージョンと同じように例外を使ってやってたんですけど、やり始めたら「無理じゃんこれ」ってことに気づいて。要は Panic って、一応 Recover できるんだけど、そのあとの処理をそれで分岐するってすごく困難なんですよ。単純にそれはシンタックスの都合上 Defer のなかに入れなきゃいけない、とか色々あるんですけど。
そういう制限もあって、まずは現実的に使えない。例外というのはどうあるべきかというのは置いておいて、使えないです。なので、去年 STF の Go バージョンをだいたい書き終わったころには、「そっか、Go では例外というものはオブジェクト指向と一緒で忘れなきゃいけないんだな」という結論には自分ではなってたんですよね。
miyagawa: 逆にいうと、例外はほんとに例外的な「何も他にすることがない、これは終了するしかない」みたいなときにしか使わない、っていう。
lestrrat: 基本的には Panic が起こったら「そこで終了」ですね。
miyagawa: なんかでも Go の本家ブログの記事を見てたら、JSON かなんかのデコーダーでは Panic と Recover を内部で使っていて、パースがほんとにどうしようもなくなったときはそれで終了する、みたいなことは読みましたけどね。
lestrrat: うんうん、そうですね。一応出来るんだけど、やっぱ相当限られた分野だと思うんで。基本は忘れるべきですね。
miyagawa: なるほどね。で、その代わりというか、エラーが返せるわけで。ほとんどのライブラリとかが基本は return value とエラーをペアで受け付けたりして、エラーを自分でチェックしないとコンパイルタイムにエラーが普通は出るわけですよね。
lestrrat: そうですね。まあ、あれもやっぱり、タイプする量が相当増えるんで賛否両論だとは思うんですけど。で、僕も一概に Go の方がいいよとは言いづらいんですよね。書いてて「またこの if err != nil を書くのか」というのはあるんで考えちゃうところなんですけど。
ただ、1つだけいいなと思ったのは、それとは別に Go の機能として、宣言したけど使わない変数はコンパイルさせてくれないんですよね。それがあると、エラーをチェックしないってことできないんですよ。厳密に言うとできるんだけど、基本は出来ないんですよね。もしくは、するにしても明示的にしなきゃいけなくて。エラーチェックを強制するという意味ではそれがあると忘れないでいいなぁ、というのは思ったんですよね。だから、イディオムとコンパイラのチェックの両方があるとちょうどいい、って感じはしました。
miyagawa: そう、僕も最初、初日書いてたときは if err != nil がプログラムの半分以上占めていて、「エラー処理めんどくさい言語だなぁ」と思ったんですけど、書かないとコンパイルタイムでエラーになっちゃうんでね。逆に言うと、通ったということは「俺はちゃんとエラーチェックをしてるな」っていう感覚が得られるんで、結構いいですよね。
lestrrat: そうそう。だからまあ、コードをあとで読むと、明示的になってるからわかりやすくていいかな、くらいの感じになってました。
miyagawa: さっき話出てましたけど、エラーの代わりに _(アンダースコア)っていう変数を使うと無視することができるっていうことですよね。それも書いてると、自分が明示的に手抜きをしてるってことがコードからわかって結構いいな、と思ってるんですよね。
lestrrat: そうそう。Perl とかだと両方混じったりしてるし、戻り値でエラーチェックしなきゃいけないところもなんの変数にも代入しないで暗黙的に return ができてたりとか。それで、「じゃあ誰がチェックしてるの?」とか色々あるんで、それよりかはいいなぁとは正直思いますね。
miyagawa: しかも、まだ若い言語だからってのもあると思うんですけど、ライブラリとかの作者とかによってインターフェースが違ったりとかしない、というか、本家組み込みのライブラリのインターフェースに結構みんな合わせてるのかなぁ、という感じはありますね。
22:00
lestrrat: そうっすね、割とその辺は。あと、その辺は最初から言語に gofmt だとか、あとこれは確かダウンロードしなきゃいけないんですけど、golint とかあるから、あの辺でいったんソースコードのチェックを走らせるとものすごい文句を言われるから、それで直してくといつの間にか同じようなソースコードになっていきますよね。
miyagawa: そうなんですよね。やっぱそれも「スペースを2にするか4にするか」とか「ハードタブかソフトタブか」とか、多分最初みんなが始めようとすると「なんでこれハードタブなんだよ」とか結構思うと思うんですけど。format がやってくれるからどうでもいいや、っていう感じになりますよね。
lestrrat: そうそう。ちなみにですけど、僕は中二病なんで format を使わずにインデントに関してはスペース2個でやっちゃってます。どうしてもタブには慣れずに「いやだいやだ!」と。
miyagawa: まじっすか。でもそれ、タブ以外の恩恵が得られなくなるんじゃないの?そんなことない?
lestrrat: いや、大丈夫っすよ。format とかは、インデントのことを無視する、みたいな設定しとくと適当にやってくれます。
miyagawa: なるほどね。それはでも、他の人とやり始めるとちょっと問題なんじゃないの?
lestrrat: そうなったときはそうなったときで全部最後に format 通せばいいかな、っていう安心感もある。
miyagawa: まあ、ローカルでは2スペースでやっといて、コミットするときに format 通すとか。
lestrrat: そう、それでもいいかなぁ、と。ただ、「今のところは」レベルになってやってるんだけど、そのうち趣旨替えするかもしれない。
miyagawa: そのうちね。白旗をあげないといけないかもしれない(笑)
lestrrat: そうそう。
miyagawa: なるほど。
Go を書き始めて1年とか経ってると思うんですけど、最初の頃の自分のコードと今の Go のイディオムとか色々知ったコードを比べてみると、色々と違いとかあったりします?
lestrrat: いやー、違うんすよね。だから、STF のコードはあんまり見られたくない(笑)
miyagawa: (笑)
lestrrat: あれはひどい。
miyagawa: それはいまオープンソース?GitHub にあがってんのかな?
lestrrat: あがってます。STF の Organization があるんで、それのなかに入ってますね。
miyagawa: どのへんを書き直したいですか?
lestrrat: やっぱり、さっき言ってた例外とかを使うつもりで色々書いてたからその辺が汚かったり、あとは、どうしても Worker とかを別プロセスを立ちあげなきゃいけないところがあるんですけど、その辺の IPC がひどい。
miyagawa: ひどいというのは?
lestrrat: 3行くらいで書けるコードを100行くらい使って書いてるケースが。
miyagawa: 要は、Go の Goroutine とか Defer とかを使えばもっと簡単に書けるのに、全部自分でやっちゃってるってこと?
lestrrat: あとは、標準ライブラリにこれあったじゃん、とかが抜けてたり、Channel の使い方が下手ですね。Channel をもっとうまく使ってれば、もっときれいに書けてたと思うんすよ。
miyagawa: でもそういうのって Go に限らず色んな言語で結構起こりえるのかな、と思って。新しく Perl でも Ruby でも Python でも、書き始めると「標準ライブラリでこういうのあるし」とか「CPAN とか Rubygems みたいなのにあるこれを使うのが定番だよ」みたいなの結構あると思うんすよ。その辺のノウハウとかは Go だとどういうの見て学ぶのがいいんすかね?
lestrrat: どうなんすかねー。そこは難しくて、ML でもよくその話題出てくるんすよね。一昨日もちょっと、Tokyo Golang Meetup っていう、東京で外人ばっかりだったんだけど、Go を使ってる海外の人たちが集まって「どういうことしてる」みたいな話をしてきたんですけど、みんなやっぱり同じこと考えてて。
Ruby の Ruby toolkit ってあるじゃないですか。あれと同じもの Go で作ろうぜ、とかいう話も出たりして。やっぱりみんな欲しがってるんですよね。そういうものがない状態で Next Best はどこかというと、やっぱり Go 本体のソースコードを読むことなんだな、ってとこに行き着くんですけど。
miyagawa: それはね、こないだ出てもらった typester さんも同じ事言ってて、「一番勉強になるのは標準ライブラリのソースコードを読むこと」って言ってましたね。
26:08
lestrrat: そうっすね。
話が前後しちゃうんですけど、Xslate っていうテンプレートエンジンを Go で書き直したときなんかも、結局 Go に標準でついてるテンプレートの Parser とかの半分くらいパクってきたんですけど。あれとかを読んでると「あー、こうやって使うんだ」ってすごく思いましたね。
miyagawa: それって、具体的にはブラウザとかで読むのか、それとも perldoc -m みたいな感じでコマンドラインで読めたりするんですか?
lestrrat: 僕は両方ともやってたけど、最初、まだ書く前の段階はドキュメントとか読みながら golang.org/pkg をポチポチしながら読んでて。で、あれって、最終的に type の名前とかをクリックすると、それを定義してる場所に飛べるんですよね。そういうのをヒントにしつつ、「あー、こういうところにあるんだ」と見てて、更に見たい場合はローカルのソースコードを見始めましたね。
27:12
miyagawa: なるほどね。さっきパッケージとか Ruby toolkit の話がどういうことかっていうと、例えば Ruby でメール送信をするんだったらこの Gem がいいよ、みたいなのが集まっているサイトがあるんですよね。Go の場合、CPAN みたいなものが存在しなくて。作ってる人もいるみたいですけど、基本的には言語の方に URL を指定して GitHub とか Google Code とかから import したり get したりする機能があるので、そういうのがあまり必要ないって考え方なんですかね?
lestrrat: そうですね。製作者たちは「いらないんじゃないの?」って方向性だと思うんですけど、やっぱり、いいライブラリ探すのは難しいですね、Central repository みたいなのがないと。
miyagawa: Rating とか、どれくらいのソフトウェアが使ってるかとか、ね。やろうと思えば GitHub にある Go のソースコードから import 行を探してきてやればできそうだけどね。
lestrrat: そうっすね。やる気さえあれば Go の標準ライブラリに確か AST を作成するとかいうのがあるんで、import の部分だけ抜き出してきて更に再帰的に探すとかできそうな気がする。
miyagawa: なるほどね。実際でも、GitHub と Google Code と BitBucket とかしかサポートされてないんだよね?
lestrrat: launchpad もだったかな?正式にはそれだけです。
miyagawa: URL があったらそれを get する、とかじゃなくて、結構ハードコードされてるんだよね。
lestrrat: されてる。
miyagawa: そこの割り切りがすごいなと思って。
29:00
lestrrat: まあでも、要は GOPATH っていうディレクトリ以下に入ってりゃいいだけなんで。単純に自動的に go get コマンドで持ってこれないってだけであって、そこに普段から git clone してると何も問題なく使えてしまうので、あんまり違和感を感じたことないですね。
miyagawa: あ、そうなんだ。
lestrrat: 僕の場合、Go を始めてから自分のローカルマシンのディレクトリストラクチャを変えたんですよ。それまでは、git っていうディレクトリがあってそのなかに色々やったりしたんですね、基本的には。それを今度は、dev っていうディレクトリを切って、dev 自体を全部 GOPATH にして、その下に Perl モジュールであろうと Go であろうと Go の流儀で、src/github.com/lestrrat/perlmodule とかそういう感じの形で全部 checkout し始めたんです。
miyagawa: じゃあもう、Go の流儀に合わせちゃったってこと?
lestrrat: 合わせちゃった。
miyagawa: (笑)
lestrrat: なんでそれで大丈夫だと思ったかというと、他の言語は別にその流儀でやってても何も問題なくて、ちょっとディレクトリが深くなるくらいで。あんまり気にならない感じになってしまったんですよ。
miyagawa: 僕もいま言おうとしたんですけど、初日とかにつまづくのが GOPATH ってやつで。
lestrrat: うんうん。
miyagawa: 「こういうディレクトリ構成にしろ」って言ってきますよね。
lestrrat: 言ってきますねー。
miyagawa: もちろん、そうやらないでカレントディレクトリに .go ファイルを作って go run とか go get とかすれば動くには動くんだけど、なんか気持ち悪さがあるというか。
lestrrat: そうそう。GOPATH はちゃんと腑に落ちるまで1ヶ月くらいかかったと思う。
miyagawa: (笑)結局それに surrender して、「俺は Go に合わせるぞ」みたいな感じで。
lestrrat: というか、一番誰も困らないのがこれだな、と。
30:50
miyagawa: 今 Twitter でコメントがあったんですけど、godoc.org というところに登録をすると、そこで API ドキュメントとかが見られるってことなんですか?
lestrrat: godoc.org はね、登録はしないんだけど勝手に持ってかれてますね。
miyagawa: (笑)
lestrrat: 例えば Xslate のやつとかは僕は明示的には何もしてないんですよ。URL を叩くと勝手に go get して勝手に解析してます。
miyagawa: なるほどね。確か Python だと readthedocs.org っていうサイトがあって、PyPy とかにあがってるライブラリのドキュメントが勝手にブラウザで見れるんだけど、多分それと似たような感じなのかな。
lestrrat: でしょうね。
miyagawa: じゃあ、別に自分から登録するために手続きが必要、とかではなくてってことかな。
lestrrat: そうそう。適当にやれます。だから、僕は最近の Go のプロジェクトだと、godoc.org のバッジを GitHub の README にリンクとしてつけてて、API とかは README に書いてないです。もう「こっち見ろ」って感じで。
miyagawa: なるほどね。その辺も流儀がいろんな言語によって結構違ってね。僕は未だに Ruby で慣れてないのが、perldoc 相当のものは rdoc っていうのがあるんだけど、ほとんどの Gem は README.md に Markdown でガーって使い方が書いてあって、「このクラスの実装の詳細はどうなんだろう?」っていうとなかったりとか、ライブラリによって全然まちまちだったりするんで。Perl だとね、perldoc の最初に絶対 SYNOPSIS で使い方書いてあるってのが決まってるから、そういうのがたまに恋しくなることがあるんですけど。
lestrrat: Perl のすごいのは、そこをなんらかの強制力があるツールでやってるんではなくて、あくまでみんなの善意に任せてるのになぜか動いてるところがすごい。
miyagawa: 確かにね。他に関しては TIMTOWTDI というか、多様性が色々あるのにみんなそこはちゃんとやるよね。
lestrrat: そうそう。あれはすごいと思う。で、Go の場合は、生成されたドキュメントのセクションごとにどこからデータ持ってくるかが決まってて、そのルールがあるんですよね。それに従ってコメントを書いていくと、勝手にいい感じになってます。で一番いいのはね、これは他の言語にあってもいいと思うんですけど、サンプルコードをテストのなかに入れられるんですよね。それを毎回テストと一緒に必ずコンパイルしてくれるんですよ。だから、例えば API を変えたときにサンプルだけが古いってことがないんです。ちゃんとコンパイル通すから。
miyagawa: じゃあ、テストとしては動かないけどコンパイルだけはしてくれるってこと?
lestrrat: そうそう。でそれが、Example ってので godoc.org とかのところに載るんで。
miyagawa: ふーん、それはいいですね。そういうの俺確かやったな、Perl で。Test::Synopsis ってやつがあって。
lestrrat: そうそう、それです。
miyagawa: 説明すると、さっきも言いましたけど、SYNOPSIS ってとこにサンプルコードを書くのが Perl のドキュメントの流儀になってるんだけど、そこに書いてあるコードがちゃんとコンパイル通るかっていうテストモジュールを僕は書いて。そんなモジュール書かなくても、それが言語の toolchain のなかに入ってるってことだよね。
lestrrat: そうです。
34:10
miyagawa: なるほど。Package の話だと、よく話題にあがるのがバージョン管理ができないっていう話をよく聞くんですよね。どういうことかというと、サードパーティの Go のライブラリを使って自分のコードを書いて動いた、でデプロイした、よかった、って感じなんだけど、ライブラリの API 仕様が変わったりとかバグ修正をして上げたいんだけど他のところが変わっちゃうとか、そういうのは他の言語だと Ruby の Bundler とか Perl の Carton とかみたいなのでバージョン固定してデプロイするってのが普通だと思うんですけど、Go にはそういう仕組みがないというか、難しいんですよね。
lestrrat: というかね、みんなでこれを使おうって決めた仕組みがないだけで、仕組み自体は100万通りくらいあって。
miyagawa: (笑)
lestrrat: みんな作ってるんですよ。僕はこれといった仕組みを知らなかったんですけど、一昨日の Meetup に行ったら Pak っていうのがあって。それがほぼ Bundler とかと同じ仕組みっぽいんですよね。pakfile.lock とか作ったりとかいろいろやってて。Git でちょっと小ざかしいことしてるように見受けた、それがいらなさそうな気もしたんだけど、基本的にはそういうことをやってくれるみたいです。
miyagawa: そうですね。一応、mattn さんが gom っていうのを作ってて。
lestrrat: それもありますね。
miyagawa: いろいろね、Bundler みたいなものが山ほどあるんだけど、いま注目してるのはそれって感じ?
lestrrat: いや、単純に目の前で動いてるの見たから「あ、ちゃんと動いてるんだ」ってだけです。で、僕はね、個人的にはカチカチに管理しなきゃいけないレベルまで来てないし、結局このあともツール変わるんだったらまだロックインするには早いなと思ってて、まだ手で管理してますね。
miyagawa: それは Makefile とかに書くってこと?
lestrrat: それとか、Submodule で管理するとか。
miyagawa: うんうん。基本的には go get するときに引数をつけてローカルに入れたものをビルドしてデプロイすればいい、ってことですよね。
lestrrat: そうっすね。基本はそういうこと。
36:23
miyagawa: じゃあちょっと、最初の頃に話した話にまた戻っちゃうんですけど。Go の使いどころっていうか、Web アプリケーションフレームワークみたいなのに使いたがる人がどうしても新しい言語が出てくるといるわけですよね。そういうのは向き不向きはあると思うんですけど、どういう風に使うのがよくてどういうところは向かない、みたいなのありますかね?
lestrrat: たぶん皆さんご存知のとおり、Web アプリケーションフレームワークは Go にも4〜5個パッと思いつくだけでもあって。Martini だとか Beego だとかあるんですけど、そういうやつはたぶん全然使えるんでしょうけど、今のところ個人的にはあんまり Go をフロント、ユーザーが直接見る Web の部分に置くメリットはそれほど感じてなくて。速いとかそういうメリットはあるんだろうけど、今のものを置き換えるほどのメリットは感じてないんで。
というのも、書いてみたらわかるんだけど、やっぱりちょっと URL 変えたいとか、ちょっとリダイレクトしたいとかそういう細かいことをしたいときにいちいち再コンパイルの手順とかが意外とめんどくさい。微妙なところですね。使えないわけじゃないし、全然使ったらいいと思うんだけど、まだ積極的にって感じじゃないです。その代わりに、裏側の API 部分ではすごく使ってる、もしくは使おうとしてる。
miyagawa: Web サーバー、REST API とかってことですか?
lestrrat: そうっすね。そういうところはいま実際使ってて、某ブログだと裏側の直接ユーザーと対話しない部分で検索の API とかはいま Go で動いてたりしますね。
miyagawa: それは、ブラウザ直接叩く API、それともシステム的な内部の?
lestrrat: システム的です。
miyagawa: なるほどね。Martini っての僕知らなかったんですけど、最近 Changelog って Podcast で作者の人が話してるのを聞いて。で、コードを見てみたら、基本的に Sinatra とか Node の Express っていうフレームワークに inspire されてる感じなんですよね。
lestrrat: そうそう。
miyagawa: だから、WSGI 的というか、インターフェースがあってそこにミドルウェアをかませて、みたいなのが基本で。ちょっと面白かったのが AngularJS っぽい Dependency Injection というか、func の引数にいろいろ型を書いとくとそれが提供されるみたいな感じになっていて、基本的に Go の built-in の HTTP サーバーと API 互換になってるのかな。その辺が結構面白くって。
僕は Plack を書いたのもあるんですけど、そういうの見てると「おー、なんかすごい似てるな」ってのがあって。結構、それ自体はすごい軽いフレームワークなんで、API を書くのとかそういうのにはすごく向いていて、フロントエンドの Web サイトを作るとかそういうのにはあんまり向いてないよってのは作者の人も言ってはいましたけどね。
lestrrat: そうっすね。あと個人的には、テンプレートを毎回自前で読み込んでメモリ上でコンパイルしなきゃいけないのがすごくめんどくさくて。そういった理由もあって Xslate の port を書いたんですけど。
39:42
miyagawa: それ、もうちょっと話しましょうか。
lestrrat: まず、Xslate が何かというと、元々は Perl 用に書かれたテンプレートエンジンで、その前にあった有名なテンプレートエンジンが機能はたくさんあるけど遅いという致命的な問題があって、それをどうにかしようっていうのが Xslate の命題の半分くらいで。
miyagawa: 前からあったって言ってるのは Template Toolkit のことだよね?
lestrrat: はい。で、それを Go でも使いたいと。Go にもすでにテンプレートエンジンはあるんだけど、基本的にはファイルの読み込みとかは動き出した瞬間にやるとかじゃないと、キャッシュとかの面倒見てくれないので自分で管理しなきゃいけないんですよ。それがめんどくさくて。Xslate とか Perl の元からあるやつだと、基本的にはファイルパスを与えてあげると更新されたら新しいの入れてくれるし、それまではキャッシュしたバージョン使うっていう構成になってるから、そういった機能もあったらいいのに、でなおかつ速ければいいのに、っていう感じで。「じゃあ持ってくればいいじゃん」ってことで持ってきてみたらすごくつらかったんですけど。
miyagawa: (笑)
lestrrat: とりあえずざっくり動くようにはなったから、さっき言った検索の裏側の API の管理画面とかにちょっと使い始めたりしてますけど。
miyagawa: それって、テンプレート言語を作るってことはプログラミング言語を作ることに近いところがあるんじゃないですか?
lestrrat: そうですね。たまたま Xslate も Virtual Machine で動くまさに言語作るやつだったんで、要はそれを全部作ったんですけど(笑)
miyagawa: そうそう。テンプレートライブラリを作るときって複数のアプローチがあると思うんですけど、一番 straight-forward なのは、テンプレート言語を一旦ホスト側の言語にコンパイルしてしまってそれを eval する、みたいな感じだと思うんですよ。多分 HTML::Template がそんな感じだったと思うんだけど。
lestrrat: だと思います。
miyagawa: で、それに対して TT とかもそんな感じで、Xslate の場合はそれ用の VM があるっていうことですよね。
lestrrat: ですね。
miyagawa: 一方、Go でいうと runtime に eval することが難しい、というかできないと思うので、そういうアプローチを採らざるを得ないってことだよね。
lestrrat: そうそう。で、そういうのができてきたんで、もう少しフロントに近い部分も Go でやってもいいかなぁ、とは思ってますけど。
42:16
miyagawa: Martini の人が話してたときに、なんてライブラリだったか忘れちゃったけど、Go で Web サーバーを作ったときのスタティックファイルの扱いの話で。普通 Web サーバー書いたらスタティックファイルはディスクの上にあるじゃないですか。だけど Go でデプロイしたときにそのファイルをデプロイするの面倒だから、どうしたかっていうとバイナリのなかにそのスタティックファイル全部コンパイルしちゃって、オンメモリにのせてそこから serve するようにしたっていうのがあって。それはデプロイするときにいいな、と思ったんですよね。
lestrrat: うん。みんなやってるみたいですね、それ。特に one binary で済ませたい場合はみんな結構それをやってるみたいです。
miyagawa: 僕も1回本番環境で Go 関係のコマンドを動かしたことがあって。今は稼働してないんですけど。Ruby とかのデプロイに比べると超簡単なんですよ。
lestrrat: あー、確かに。
miyagawa: 本番に入って bundle install してキャッシュをクリアして……、とかなくて、ローカルのツールでクロスコンパイルしたバイナリを rsync でコピーして終わりっていう。そこら辺は気軽な感じがしますよね。
lestrrat: そうっすね、それは確かに。やっぱり、単純に考え方の問題だと思うんですよね。Perl や Ruby に慣れてる人がサッといったときにちゃんと頭の思考方法を変えられれば、よくよく見れば全然簡単なんですよね。だけど、そのままでいくと「あ、あれぇ?」ってなる。
miyagawa: (笑)
lestrrat: デプロイのところで1つだけ「なんでこれ元からないんだろ。あったらいいのに」って思ったのが、Server::Starter みたいなものとの連携で。Super deamon 作って、起動に失敗したときに前の世代が残ってるっていうのをやりたかったんですよ。特に最初 Go に自信がなかったから。結局それは Server::Starter の作り込みを自分で作っちゃったけど。あれがあったらいいな、と思いますね。
miyagawa: Server::Starter ってのは kazuho さんが書いた Hot Deploy のためのフロントエンド、super deamon みたいなので。後ろで何世代かあるバックエンドのサーバーを graceful にシャットダウンしながら新しいほうに徐々に切り替えていく、みたいなことができるやつですよね。
lestrrat: Go で Graceful Deploy みたいなのはあるんだけど、Hot Deploy は Go そのものでは多分ないんじゃないかなぁ。当時はなかった気がします。Graceful Deploy はね、なんかライブラリがあるんだけど、それで「いま serve してるリクエストが終わったらちゃんと落ちてくれる」っていうところなんですよね。その辺が最初から揃ってたらいいなぁ、と思います。
45:25
miyagawa: なるほど。
あと、メモ帳見ると GoConvey っていうネタがありますけど。
lestrrat: あー、GoConvey はね、Meetup で出た「みんなが実装してるもの」の1つで、勝手にファイル変更の検知をしてくれてテストを走らせてくれるってやつなんですよね。使ってみたらすごくいいんですけど、こないだ話を聞いたら、僕を含めて4人話したんですけど、そのうちスピーカーが2人と外野にいた1人が全く同じようなもの作ってて。みんな GoConvey って一言を言わないから「みんな知らねえのかな?」っていう感じで。
miyagawa: あ、そうなんすか。それとも GoConvey に不満があるとかではなくて?
lestrrat: 不満があったらそう言うと思うんですけど、誰も Convey の「こ」の字も言わなかったから、これはひょっとして、と思ったんですよね。
miyagawa: GoConvey ってのは built-in のもの?
lestrrat: 違います、残念ながら。ただ、ML で見てると割とみんなそれを使ってるように見えたんですけど。
miyagawa: 逆に言うと、どういうものが流行っていて、っていうのがまだまだ差があるってことなんですかね?
lestrrat: 差があるでしょうね。あとは、集中したリソースがないから、みんな「ここ見ろ!」っていうデファクトが作られにくいですね。
miyagawa: なるほど。僕は最近、Martini の人がやってる GopherCasts っていう Screencast をみつけて。この Podcast でも何回か言ってますけど、僕 Screencast が結構好きで。自分でコード書かないでも書いた気になるっていうところがあって。いくつか新しいエピソードとかがあがっていて見てみたら結構よかったですね。しかも、1回が5分以内とかなんで、割とサクッと見れてよかったです。あとで Show Notes のほうにリンク貼っておきます。
今の Go のバージョンっていくつなんだっけ?
47:28
lestrrat: 1.2.1かな?で、1.3が結構できあがりつつあるんで。いつ出るのか知らないけど、割とすぐ出る気がします。
miyagawa: どういうところが新しくなるっていう発表はもうあったんですか?
lestrrat: 僕が見てるなかでは、パフォーマンスがすごいよくなってるような。3〜4倍よくなってる感じっぽいですけど。
miyagawa: さらに速くなるってこと?
lestrrat: ですね。
miyagawa: 言語的な拡張はそんなにもうないのかな?
lestrrat: Go は確か backward compatibility guarantee みたいなのがあって。確かメジャーバージョンが変わらない間は全部動くするようにするとかいう感じだと思うんですけど。だから割と Perl の考え方に近くて。ただその代わり、明示的に「このバージョン番号上がったらそのあとは知らないよ」っていうのは言ってるんで。
miyagawa: それはいいですね。安心して使えるというか。でも、Perl みたいにバージョン番号宣言するとそこだけシンタックスが変わるとか、そういうのないよね?
lestrrat: (笑)ないはず。
miyagawa: (笑)
lestrrat: Go だからコンパイルできなくておしまいでしょうけど。
miyagawa: そんな気持ち悪いのはないと思うけど。
言い残したことありますか?
48:37
lestrrat: 名前を言ってなかったのが、gopkg.in っていうサイトがあって。そこがバージョン問題に絡んで、同じライブラリの違うバージョン読み込むときにどの URL から git clone したほうがいいとかがわかりにくい問題をルールを作って解決しようとしてますね。たとえば YAML とかあるんですけど。
miyagawa: いま見てますけど、go get gopkg.in/yaml.v1 とかやると、YAML のバージョン1を取ってきてくれる?
lestrrat: そうそう。要は裏でリダイレクトしてるだけなんですけど、その辺の仕組み、URL を正規化する仕組みをいま作ってて、これがデファクトになってきたら割とわかりやすくルール化されるんじゃないかな、って気がします。
miyagawa: ちょっと CPAN っぽいというか、名前空間があってリダイレクトするっていうね。でもなんか、リダイレクトだとリダイレクト先が消えちゃう危険性がないですか?
lestrrat: それはしょうがないんじゃないですか(笑)
miyagawa: (笑)でも、Python のPyPI が昔そうだったんですよ。CPAN のいいところはファイル自体がホストされてるから、作者のサーバーが消えても大丈夫みたいなとこあるじゃないですか。
lestrrat: そこはでも Git とかだから、gopkg.in がちゃんと take-off したら登録された瞬間に clone しとけばいいんですよ。
miyagawa: そういうのもあって、いま言語としてサポートしてるのは GitHub、Launchpad、Google Code とかなってるから。あまり個人サイト、URL が消滅とかいうのは考えなくていいかな、という感じですね。GitHub のアカウント消えたら消えちゃうけどな。
lestrrat: まあそうですね。
miyagawa: (笑)
はい、ではちょうど時間もいい感じなんで、そんなところで。Show Notes は多分ですけど rebuild.fm/42 になります。ではそんな感じで。
lestrrat: はい。
miyagawa: lestrrat さんでした。
lestrrat: ありがとうございました。
miyagawa: ありがとうございましたー。
Transcribed by @harupong http://blog.harupong.com/