定期的にブログ書いてないとなかなか書く気が起きなくなるので敷居が低そうだった Go の Linter について調べてみた。
書こうと思って調べた矢先、非常にまとまった良い記事を発見してしまったが気にせず書いてみる。

Linter の印象して、他の言語では大体の鉄板機能を網羅している大きな Linter が2, 3個あるのに対して
Go では機能毎に小さくパッケージ化されていて組み合せて Linter としての機能を実現してる印象がある。
この複数の Linter を組み合せた状態で Lint 実行できると有名なのが gometalinter
最大30以上の Linter を実行させるこができる。(もちろん有効/無効もできる)
ただ、全部が必須なわけでなく、どのゆう機能の Lint が走ってるかを把握していて
ブラックボックス状態でないことが重要と思ってるので自分では単体の Linter をそれぞれ実行してる。
ということ現状利用してる Linter を上げみる。

golint

https://github.com/golang/lint

Go のコーティングスタイルにあっているか確認してくれる Linter。

入れるとすべての関数にコメントをしなければならなくなる。
Lint の一部を無効にするような機能はなく、有効/無効 のどちらかの選択になる。
Issue を見ると、作者は Lint を一部無効するような機能を実装する気はなく
Go らしく書くか書かないかどちらかだみたいなこと言ってるので、grep でコメントは無効にしてる

1
$ golint `go list ./...` | grep -v " should have comment or be unexported"

go vet

Go の標準ツールの一つで、コンパイラで検知できないエラーをチェックしてくれる Linter。

Printf のコールで文字列フォーマットと値がアンマッチしてる場合や struct のタグの定義エラー、
他には、経験上から問題点と推測されるようなもを指摘してくれる。

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

type Fizz struct {
Buzz string `json: hoge`
}

func main() {
return
fmt.Printf("hoge %s", 1)
fmt.Printf("hoge %d", 1, 2)
}
1
2
3
4
5
6
$ go vet main.go
# command-line-arguments
./main.go:6: struct field tag `json: "hoge"` not compatible with reflect.StructTag.Get: bad syntax for struct tag value
./main.go:11: unreachable code
./main.go:11: Printf format %s has arg 1 of wrong type int
./main.go:12: Printf call needs 1 arg but has 2 args

unused

利用していないを定数や変数、型、関数を教えてくれる Linter。

変数とかはコンパイル時に not used としてチェックする機構はあるが
他はしてくれるないので助かってる

errcheck

https://github.com/dominikh/errcheck

戻り値の error のチェック抜けがないか検知してくれる Linter。

このチェックは、よく defer 時の error チェックの扱いで議論になる。
ファイルやネットワーク接続を閉じる際に defer client.Close() みたいにすると error チェック漏れ扱いになる。

この時、excludeオプションを使ってチェックを除外するか

1
$ errcheck -exclude .errcheck_excludes.txt main.go

きちんと error ハンドリングするかの選択になる。

1
2
3
4
5
6
7
8
9
10
11
func closer(c io.Closer) {
if err := c.Close(); err != nil {
log.Error("failed to close error.", err)
}
}

func main() {
...
defer closer(client)
...
}

自分としては、error をスルーしてコードスッキリさせるよりも検知したいので後者の選択を取るようにしてる。

go-staticcheck

https://github.com/dominikh/go-staticcheck

静的解析でさまざまな種類のクラッシュと不正な動作を検出できる Linter。

どうゆうパターンのチェックがあるかはここから確認できる。
https://staticcheck.io/docs/staticcheck#overview

go-simple

https://github.com/dominikh/go-simple

シンプルに書くことができる方法を教えてくれる Linter。

たとえば、main.go 中でこんな感じなコードがあると

1
2
3
for _, e := range y {
x = append(x, e)
}

append が良いよって教えてくれる。

1
2
$ gosimple main.go
main.go:15:2: should replace loop with x = append(x, y...) (S1011)

どうゆうパターンのチェックがあるかはここ確認できる
https://staticcheck.io/docs/gosimple

misspell

https://github.com/client9/misspell

英語のタイプミスを教えてくれる Linter。

misspell はエディタ上でも範囲選択してチェックできるようにして使ってる

1
2
3
4
5
6
7
$ misspell fujimisakari/
fujimisakari/go-crawler/Makefile:18:25: "infrastracture" is a misspelling of "infrastructure"
fujimisakari/go-crawler/backend/domain/crawlentry/dao.go:4:45: "infrastracture" is a misspelling of "infrastructure"
fujimisakari/go-crawler/backend/domain/hatenahotentry/dao.go:5:45: "infrastracture" is a misspelling of "infrastructure"
fujimisakari/go-crawler/backend/domain/qiitaentry/dao.go:5:45: "infrastracture" is a misspelling of "infrastructure"
fujimisakari/grpc-todo/api/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go:155:3: "permenant" is a misspelling of "permanent"
fujimisakari/grpc-todo/api/vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go:46:33: "seperator" is a misspelling of "separator"

X