tl;dr: 別にPerl捨ててないです。Perl大好き。俺はLLはPerlでいい。でも別ドメインの事もやってもいいよね!

Rebuild.fmに限らず、公の場でYAPC/Perl以外の話をする事があるとは正直思っていなかったが、このたびRebuild.fm ep 42に置いて1時間Goについてしゃべりまくってきた。1時間ぶっつけ本番でしゃべりたい事はだいたいしゃべってきたのだけど、その後のフィードバック等もふまえてまとめておきたいと思ったのでこのエントリでまとめてみます

Go事始め

そもそもなんでここまでGoをガリガリ書き出したのか。

正直親父ギャグとvimで有名なあの人が「Goいいよ!」と言い出したときにはGoに対してはうさんくさい印象しかなくて特に注意すらしてなかったんだけど、そろそろ違う言語とドメインに向いてみるかーと思って探していた時に「あ、俺もうLL系の言語別にいらないな」とふと思った事が大きな転機になった。もちろん極めるにはそれなりの努力が必要だろうけどRubyにしろPythonにしろ、LLという広義の枠の中ではそれほど違いが見受けられなくて二の足を踏んでいた。

そこで翻って、元々のバックボーンであるC/C++のほうに戻って、もっとビットの羅列と仲良くなろうかなーと思っていたところ、DockerがGoで書かれていた事に気づいたのだとおぼろげながら記憶している(このあたり、記憶が曖昧な割に特定の社名とか出てくるからRebuild.fmではあえて細かい事はしゃべっていない)。Dockerをかける言語ということは当然だいぶ下のレイヤーと結合できるわけだけど、これまでのそのレベルの製品のようにasmファイルとかなんか「えー、そこから勉強かよ」というレベルのものがソースコードに見当たらないので、これはいけるのか?と思ったわけです。

その時点でもまだ「ふーん」程度の認識だったけれども、その次のステップに行くのに大きかったのは"A Tour Of Go"というインタラクティブなチュートリアル。これがなかったらさらに詳しくやってみようとおもってはいなかったかもしれない。この辺り35歳オーバーの老害エンジニアとしては「Web上にその手のものがあるのが当たり前」という感覚が養えていなかったと猛省するしかない。

と、同時にこのインタラクティブなチュートリアルを体験した結果「この使い勝手・・・LLと同レベルのリズムでwrite/compile/executeを実行できるな?」と言う確信が得られた。これが大きい。C/C++でMakefileとか用意するの面倒だったし、コンパイルにぼちぼち時間はかかるし・・・それがこの言語を使うとどうやら回避できるのに、Cに近い事ができそうな予感がしたわけです。

そこからGoをちょっとまともに使ってやろうかと考え始めたわけです。

使い始めて

使い始めはとにかくコンベンションの意味がわからなかった。パッケージの仕組みもわからなかったし、どういうレベルで構造体をグルーピングすればいいのか、っていうかオブジェクトはどこだ!とか色々いらだった。

今から思うと、これは今年のGopherConのキーノートをコードを各前に聞けばよかった話だった

コーディングの細かいところははRebuild.fmでも言ったけど、他の言語から来ている人たちにとってGoを始める際重要なのポイントはいくつかある。Rebuild.fmで全部言ったかどうか記憶にないけど、とりあえず思いつく限り羅列してみます:

オブジェクト指向なんてドブに捨てちまえ
インターフェース定義でダックタイピング+同一インターフェースでちょっとずつ動作が違うものでラップするなどのcompositionこそが正義(これ重要)

io.Readerまわりの使い方を見るといいかも?ちなみに拙作のgo-apache-logformatもhttp.ResponseWriterに対してラッピングする手法でログ出力を乗っ取っている。

「マルチスレッド」「マルチプロセス」なんてドブに捨てちまえ
Goにはgoroutineという強力な平行処理用のイディオムがビルトインされているけれど、これをPOSIXっぽいスレッド/プロセスモデルで考えてコードを書こうとすると悲しい事になる。例えばgoroutineは殺せない。goroutineの固有IDは取得できない。それが欲しい気持ちはわかるが、そもそも違う考えの元に設計されているのだ。平行処理の知識は必要だけど、スレッド/プロセスというモデルは一旦忘れてchannelの特性を理解しないといけない。

例外は存在しない
言語仕様的には存在する。だけどプログラマー視点からは存在しない、と割り切るのがベストです。

Goでは例外をpanic()で投げる事ができるわけですが、これを使っていいのは「この条件が成立してしまった場合はそもそもプログラムの実行ができない」場合のみです。あとは全てerror型の戻り値として返します。

if err != nilを書くのが面倒、というのはもうなんとも言えません。自分はタイピングが苦にならないたちなので正直全く問題がないのですが、確かに同じ事を何回も書いている気分にはさせられます。そのかわり自分はこの構文を見ると「ああ、ここがエラー処理のところだ」という視覚的なマーカーとして有効だな、と個人的には思っています。

チャンネルをきちんと理解せよ
最初チャンネルを見るとこれでデータのやりとりをするんだな、と思うと思います。それは正しいのですが、データのやり取りを複数goroutineで(無意識かつ安全に)やりとりできるというところがポイントで、これがチャンネルがただのメッセージキュー以上の役目を果たせる理由です。

チャンネルは基本的には同期処理を行うための制御構造だと考えるべきで、たまたまその際データのやりとりも行える、ととらえるべきだと思います。チャンネルはgoroutineを停止したり、状態を同期したりするために使うのです!あと、バッファリングを理解しないとすぐデッドロックになるので、make(chan bool, 1) のこの1がなんなのかをちゃんと理解しましょう。

同時にほとんどの場合sync.WaitGroup以外のsyncパッケージの中身を同期のために使うのは間違いで、基本チャンネルが正しい解法だと言えると思う。

コードの見た目はツールに任せろ
Rebuild.fmではインデントだけが気に入らないと言い切った自分ですが、その発言の裏側には「とりあえずそうするけど、どうせツールでコードの見た目は自動的に切り替えられるからとりあえずがんばらなくていいやー」という気持ちがあった。で、その後天啓があってインデントもgo流儀にそろえました。その際もgo fmtを実行してコミットするだけだったので何も考える必要はなかったので思っていた通りであった。

ちなみにgolintも必須ツールだと思ってる。ドキュメンテーションのチェック等をしてくれる。この際エクスポートされている関数、構造体にちゃんとドキュメントがついているかどうか確認をしてくれるので、それらが意図的にエクスポートされているのかどうかという確認を筆者に強いてくる。これはデザインの再確認のためにとても良いツールなので強く使用をお勧めします。 

Sliceを理解せよ
Perl/Cの世界からやってきて、配列をスタック上に明示的に配置してあるならまだしも、未定のサイズの配列をあちこちで使うと(あとでちゃんとfreeするにしても)メモリ的にひどい事になる事がありえます。Cレベルではまだキチンとしたコントロールが必要だからやらざるを得ないにしても、Perl等のもう一つ上のレベルだとそういう事は忘れがちになってしまう。

Goではひとまず配列用のメモリを確保した後、その配列の一部を使った際には基本的にメモリを再度確保することはない。元の配列を参照するだけになる。この動作についてはこのブログが詳しい。文字列操作などの配列にちまちまデータを入れて処理していくようなプログラムを書く場合、この特性が最大限生かされる。Goはこの手のローレベルな処理をメモリを無駄にする事なくLLっぽい書き方で書ける。

と、まぁ書き出していたったらキリがないのでこの辺りで締めておきます。

まとめ

というわけでRebuild.fm ep 42で語ったgolangの諸々についての補足でした。コンパイル速度、タグ付けによる環境ごとに特定のコードパスをコンパイルする機能、色々なツールがGoを現実的にとても魅力的で使いやすいオプションのひとつにしているとは思います。現時点ではやはりまだ大きめなWebUIの実装言語にするのはどうかなーとは思っていますが、ミドルウェアとかもうちょっとシステム寄りな部分に関しては相性の良い言語だと思います。

書く側としてはGoが一番響くのはこれまで色々な言語を使ってきた人たちな気がします。Goの作者たちは多分意図的にいろんなものを削ぎ落としているわけですが、そのおかげで僕のようなロートルはいろんな事を忘れて解こうとしている問題の本質を考え直す必要がありました。惰性で「あ、ここはforkする形だー」とか思っていたところが「ん、ここはつまり何をきっかけにスタートしてストップするんだ?」などと考えたり、構造体の定義も「ふつーは親子関係つくるよねー」というところを、機能(=インターフェース)ベースで考え直したり・・・自分があくまで「これはこういうものだよね」思っていた事をもう一度考え直すのがすごく新鮮で楽しい言語でした。

あとあくまで予想ですが、GoはPython/Perlの人たちにはとっつきやすく、Rubyの人たちにはとっつきにくい気がします。なんとなくそう思っているだけでまだ誰ともこの議論をしたことがないので、戯れ言と程度で。

今後もopsの人たちの目をかいくぐってちょこちょこGo製のツールを配置していってやろうと思っています。