2014年3月9日日曜日

Golang Cafe #20を開催しました。

Golang Cafe #20を開催しました。

今回は、前回に引き続き、Twelve Go Best Practicesの13ページから読み進めました。
プラクティスのメモはgithubにありますので、ごらんください。
(今回は、新しいコードを書くことはしていないので、メモが追記されただけです)

以下、今日のまとめです。資料を見ながら読み進めてみてください。

その7

重要なコードは先頭に書くこと!


  1. ライセンス情報、ビルドタグ、パッケージドキュメントを記載する。
  2. import文は、(gofmtコマンドを実行すればいい気がするが…。)標準パッケージを最初に記述し、1行開けて、go getで取得したパッケージを記述する。
    1. gofmtは自動的にアルファベット順に並べてくれるが、1行あけると、並べ替えの適用を受けなくなります。
    2. gofmt sample.goだと、標準出力に出力されてファイルが書き換わらないので、gofmt -w sample.goと-wオプションをつけよう!
  3. 重要な型から始まり、ヘルパー関数などで終わるようにする。
  4. ファイル名は型に合わせたものにした方が良い!
    1. という結論に至りました。goの標準ライブラリのソースコードを見る限りだと、最初にtypeの宣言があり、typeの名前とファイル名が一致していたので。
    2. 機能ごとにファイルを分けて、わかりやすくするべきなんだろう。

その8

パッケージ名の前に連想させるようなドキュメントを書くこと!

godocに出力されるものは、ドキュメントを書きましょう!

その9

短い事はいいこと。


  1. 意味がわかって、できるだけ短い名前をつけるようにしましょう!
    1. "MarshalWithIndentation"よりも"MarshalIndent"という名前が好ましい。
  2. 識別子にパッケージ名が含まれる場合は、つける必要はない!
    1. encoding/jsonにEncoderがあるが、JSONEncoderではない。
    2. 参照される時は、json.Encoderとなるから、必要ないでしょう?
      1. 確かに、Goでパッケージのコードを書く時は、json.JSONEncoderだと命名としてブサイクなのかな…?

その10

1つのパッケージを複数に分けるべきか?


  1. コードの長いファイルは避けよう。
    1. net/httpパッケージは15734行を47ファイルに分けている。
  2. コードとテストは分けよう。
    1. net/http/cookie.goとcookie_test.goみたいに。
    2. そもそも、go testが動かないはずなので、ほぼ強制的にそうなるではないかと思われる。(go testは**_test.goを実行するので)
  3. パッケージドキュメントをdoc.goに分けておくといい。
    1. 複数のファイルがある時に、どこにパッケージドキュメントを書くか迷うので、わかるようにdoc.goを作り、そこに書く。標準のパッケージもdoc.goはpackageの宣言と、ドキュメントの記述しかない。
    2. ファイルが1つの時はそのファイルの先頭に書けばいい。


その11

go getができるようなパッケージを作りましょう。

ネットワークプロトコルを定義するようなパッケージは使われるかもしれない。
mainから始まるコマンドは再利用されないかもしれない。


その12

必要なものだけを求める。

Gopher型を使います。
    
以下のメソッドを定義した。
func (g *Gopher) WriteToFile(f *os.File) (int64, error) {

しかし、テストがしにくい!そこで、インターフェイスに書きなおした。
func (g *Gopher) WriteToReadWriter(rw io.ReadWriter) (int64, error) {

必要最低限のインターフェイスを使ってメソッドを定義すべきだ。
このメソッドは、ファイルへの書き出し機能だけなので、Readerの機能は必要がない。したがって、必要なものを引数に渡すように求めること!
func (g *Gopher) WriteToWriter(f io.Writer) (int64, error) {

ここでは、余計なものを指定できると、よくわかっていない人が想定外の引数を指定してしまうのを防ぐためにもこのプラクティスは必要!という結論になりました。
(が、それぞれ流儀があると思うので…。と議論がおかしい方向になる前にやめました)

その13

独立を保つ!パッケージごとに独立させておく。


  1. parserは解析のみ。drawerは描画のみ。pngへのエンコードはエンコードのみにする。など。
  2. 依存するパッケージをimportするのではなくて、interfaceを使って、Parse機能を持った関数を受け取り、呼び出すようにしよう!
  3. 具体的な型を使うよりも、インターフェイスを使った方がテストが簡単に作れる。
  4. TestFunc型はEval()を実装しているので、interfaceを実装していることになる。

この時点で12個じゃない!と思いましたが、資料の最後に12個のリストがあるようです
…。が、12個じゃないよな…?という気がします。

引数で受け取った関数を呼び出す形にして、他パッケージの依存を防ぐというのは良いのだけど、引数で指定する関数の中身は呼び出し側が実装するわけなので、「誰でも新たな処理を追加できる」というのが良いのか悪いのか…。という意見が出ました。
これも奥が深い話になる(というか、プロジェクトのメンバー間の意識統一かな?)と思ったので、やめておくことにしました。

ということで、次は、並列処理などのパターンが記述された、25ページ以降を読み進める予定です。