Go触った所感

以前からGoは気になってたので、複数のファイル名を一括置換するrnmというCLIツールをGoで書いてみた。 自分にはあまり馴染みのない文化が結構あって良かった。

gofmtが最高

言語に直接関係ないとこだけど、gofmtが便利!
自分は普段JSを触る事が多いが、GitHubのJSリポジトリをいくつか見るだけでもわかるように、 とにかく記述スタイルの文化が人によって違う。 だからGoがその手のコードスタイルの一切を公式で決めてくれてるのはすごく良いと思った。 インデントがタブなのはイヤだという人もいるけど、個人的にはインデントにせよクォートにせよ、 プロジェクト内で統一されてさえいれば何でもいいというスタンスなので、 リントツールの設定にいちいち気を使わずに済む方がよっぽどうれしい。 Go以降に生まれてくる全ての言語は同じように公式のフォーマッタをデフォルトで備えててほしい..!

テストの仕組み

組み込みのテスト機構はあるのにAssertionがないのはビビったけど、ちゃんとエラーメッセージを書こうという思想は理解できる。 一般的なassert.equalみたいに失敗があったら例外を投げる方式ではなく、好きなタイミングでエラーログを吐くような感じ。 これだと途中でテストが失敗してもそこで中断されないから、「1つのテストケースにはなるべくAssersion1つ」みたいな事を考えなくて済むし、 parameterized testも普通のループで書ける。
テストファイルをテスト対象ファイルのすぐそばに置く文化はGoで初めて知った気がするけど、 両ファイルを行き来しやすいし、テストファイルを全て別ディレクトリにまとめるよりやりやすかった。 JSでももちろんできるけど、例えばテストファイルにだけ適用したいESLintのルールがあると面倒そう。 2016-08時点ではファイル名のパターンでルールを切り替える方法がないし、個々にテストディレクトリを切って.eslintrcを置くのもダルい。

ダックタイピングなInterface

Goは静的型付言語だが、インターフェイスにちょっと特徴がある。Goではインターフェイスを明示的にimplementsする構文がなく、 structがインターフェイスを持つためには、そのインターフェイスが定義するメソッドを全て実装すれば良いだけ。 つまり呼び出し可能なメソッドのシグネチャによって、あるstructがあるインターフェイスを持つかどうかが決まる。 まさしくダックタイピング。テストの時は重宝しそうだけど、逆にいうとメソッドのシグネチャでしかインターフェイスを定義できないから、 メソッドは同じだけど意味的には異なるインターフェイスを定義する、といった事はできない。

Misc

  • 構文がシンプルでコレクションのライブラリも少なく、書けるコードの選択肢が限られている。それが不思議と安心感につながる。 コードの抽象化が得意な言語だと設計に腐心する楽しみがあると思うけど、Goではその手の迷いが生じづらいので、 とにかくばんばんコードを書いて形にしたい、という時に向いてるかも (でも大規模になってくるとどうなんだろう?)。
  • エラーを原則例外として扱わず、ただの値として戻り値で表現するのは好み。でも呼び出し側で毎回err != nilをチェックするのがめんどくないとは言えない。
  • 「大文字始まりかどうか」でメソッドやフィールドのスコープを定義するのはナイスアイディアだと思う。 privateとか書く手間省けるし、定義元を見なくても、使われているメソッドの名前を見るだけでスコープがわかる。
  • ジェネリクスがないのは不便だけど、それが本当に必要な時はGo以外の言語を使えばいい気がする。 Goにはむしろ今のシンプルさを保って欲しい。 ただコレクションのマップやフィルタくらいはもっと簡単に書けたらいいなと思う。 forが式になってその辺上手く解決してくれる構文があれば良いかも?
  • 肝心のGoroutineはまだ触れてない。。

疑問点

go getでの依存ライブラリダウンロードは安全?

Goのimport文では、プロトコル部分を除いたURLを記述する事ができ、 go getするとそのコードが依存しているライブラリも一緒にダウンロードするっぽい。 これが常にマスターブランチのHEADを取得するなら、開発時とgo get時で依存関係のバージョンが変わってしまいうるのでは?
1.5で試験導入されたvendoringを使って依存関係を管理するツールはいくつもあるが、 npm のようにバージョン管理を組み込んだパッケージ管理の仕組みを持ってるわけじゃないから、 開発時に使っていたバージョンをgo get時にもインストールする事はできなさそう。
そのせいなのか、GitHubを見ているとvendor以下の依存ライブラリを全部コミットしてるリポジトリを結構見かける。

main.goの置き場所

ルートディレクトリに置いてるリポジトリもあるけど、cmd/repoName/main.goという位置に置いてるリポジトリをよく見る。なぜ?
直感的には、main.goがルートにいてサブディレクトリに各種コードが置かれるツリー状の構成の方がきれいそうだけど。 ルートにGoファイルを置いとけば、go testだけでテストできるから..? (サブディレクトリを含めるにはgo test ./...と打つ必要がある)