Goだからこそ許される3つの作法


この記事は[Go その3 Advent Calendar 2015](http://qiita.com/advent-calendar/2015/go3)の18日目です。

***

仕事の関係でGoを使い始めて気付けば9ヶ月。今ではすっかり慣れましたが、始めた当初はそれまでC言語・Java中心で仕事をしてきた自分にとってGoの文化はかなり異質に映ったのを覚えています。

せっかくなので、他言語経験者でこれからGoを始めますよという方向けに、「Goではこんなことしても許されるよ」みたいなポイントを挙げてみたいと思います。


# 1文字の変数名

昔のプログラミングの入門書のコード例なんかだと、

```C
int a, b, c;
```

というように1文字の変数名が多用されてたりして、それを引きずったまま職業プログラマになってコードレビューで可読性警察に逮捕される、なんてことは良くあったのではないでしょうか。

最近は「リーダブルコード」などの良い書籍が普及したのもあり、変数名は多少長くとも意味が判るものが良い、という文化が一般的なのではないかな、と思います。例えばこんな感じ。

```C
int theAnswerToTheUltimateQuestionOfLife = 42;
```

ところがGoのソースコードを読んでみると1文字の変数名がバリバリ使われてます。

```go
// strings.Join関数のコードを抜粋
func Join(a []string, sep string) string {
    if len(a) == 0 {
        return ""
    }
    if len(a) == 1 {
        return a[0]
    }
    n := len(sep) * (len(a) - 1)
    for i := 0; i < len(a); i++ {
        n += len(a[i])
    }

    b := make([]byte, n)
    bp := copy(b, a[0])
    for _, s := range a[1:] {
        bp += copy(b[bp:], sep)
        bp += copy(b[bp:], s)
    }
    return string(b)
}
```

この辺はGoの公式ドキュメントの一端でもきちんと触れられていて

> Variable names in Go should be short rather than long. This is especially true for local variables with limited scope. Prefer c to lineCount. Prefer i to sliceIndex.

（[GoCodeReviewCommentsのVariable Names](https://github.com/golang/go/wiki/CodeReviewComments#variable-names)より抜粋）

と、「スコープが限られたローカル変数に限り」短い変数名を推奨しているんですね。確かに、先述のコード内のnやbといった変数も数行しか使われていないので、あまり読みにくいと感じることはありません。

シンプルさを尊重するGoの文化が良く表れてますね。

# グローバル変数

グローバル変数って今では親の仇のように嫌われてますよね。自分から使う人はもうあまりいないと思いますが、JavaScriptでうっかりvarつけ忘れてコードレビューでけちょんけちょんにされるなんてことは未だにあると思います。少なくとも僕が見つけたらそうします。

```JavaScript
function add(left, right) {
    result = left + right;
    return result;
}
```

でもGoだと気にせずガンガン使います。ガンガンは言い過ぎだけど割と使っても平気です。パッケージ名で綺麗に名前空間が区切られますものね。

クラスの概念がないGoだとパッケージ全体を静的クラスと同等のものとみなして、グローバル変数を静的フィールドのように使うこともあります。例えばシングルトンパターンを実現しようとすると以下のようなものになります。

（[Singleton Pattern in Go](http://marcio.io/2015/07/singleton-pattern-in-go/)より抜粋）

```go
package singleton

import (
    "sync"
)

type singleton struct {
}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}
```

うん、これグローバル変数というよりただのパッケージプライベートな変数だ！
許してください、なんでもしますから・・・

パブリックな例はosパッケージとか見れば結構見つかるんじゃないですかね（投げやり）


# 1テストメソッド複数アサーション

多くの言語のテストメソッドで良く言われるアンチパターンとして、1メソッドに複数のassertを書いてしまう、というものがあります。

```Java
@Test
public void testXXX() {
    hoge = new Hoge();
    assertThat(hoge.getName(), is("ほげ"));
    assertThat(hoge.getWife(), nullValue());
    //・・・
}
```

これが嫌われる理由は以下のような点にあります。

* 途中のassertで失敗すると、以降のassertが行われない
* テストメソッドが単一責務の原則に違反する可能性がある

まあ後者に該当するようなケースは素直にメソッド分けした方が良いと思いますが、少なくとも先述のコードはオブジェクトのプロパティの初期値のassertをしているに過ぎず、複数メソッドに分ける価値は薄いように見えます。かといって一々特化したassertメソッドを作るのはめんどくさい。

でも、Goなら気にせず以下のように書いてしまえばいいんですね。

```Go
func TestXXX(t *testing.T) {
    hoge := hoge.New()
    if hoge == nil {
    	t.Fatal("Failed to create hoge.")
    }
    if hoge.Name != "ほげ" {
    	t.Errorf("hoge.Name => %s, wants %s", hoge.Name, "ほげ")
    }
    if hoge.Wife != nil {
    	t.Errorf("hoge.Wife => %v, must be nil", hoge.Wife)
    }
}
```

テストメソッドを中断しないError系のメソッドと、中断するFatal系のメソッドを使い分けることで実に気楽にテストが書けます。testingパッケージ最強や！

JavaならHogeクラスのequalsメソッドをオーバーライドしとけ？
C言語ならGoogle C++ Testing Frameworkでも出来る？
はて・・・


***

もっとあったと思いますが、いざ考えるとなかなか挙げられないものです・・・。
思い出したらまた増やします。