34
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】デファクトなlinter staticcheckの設定方法

Last updated at Posted at 2021-06-27

はじめに

今回はGoのlinterとしてデファクトスタンダードになりつつあるstaticcheckの設定方法を解説していきたいと思います!
デフォルトで無効なチェック項目を有効にすべきかも検討していきます。

自分は普段VSCodeでGoを開発しており、linterに関しては特にこだわるわけでもなく、標準パッケージだったgolintを使っていました。
しかし、少し前にVSCodeのGo Extenstionのデフォルトがstaticcheckになったことに伴い、自分もこちらに移行しました。
その時検討したことをまとめようと思います。

staticcheckがデファクトなの?

Goには様々なlinterが存在しています。
メジャーどころでいうと、

あたりでしょうか。

しかし、標準ライブラリであるgolintは2018年あたりからメンテが行われておらず、リポジトリも凍結されました。
VSCodeのGo Extensionの標準linterも以前はgolintだったのですが、これを受け、2021/03/11のアップデートで標準linterがstaticcheckに変更されました。

VSCodeのGo ExtensionはGo開発チームが開発しているので、これはデファクトスタンダードと言っても良いのではないでしょうか!(適当)

初期設定

インストール

VSCodeのGo Extensionをインストールすれば、特にインストールは不要です。
CLIでインストールする場合は、以下のコマンドを実行します。

$ go install honnef.co/go/tools/cmd/staticcheck@latest

有効化

setting.jsonに以下を追記します。

"gopls": { "ui.diagnostic.staticcheck": true }

設定ファイル

デフォルト設定で良いままであれば、初期設定するだけでOKです。
好みに合わせてチェック内容を変更したい場合は、設定ファイルを記述する必要があります。

ファイル名、配置場所

開発ディレクトリのroot直下にstaticcheck.confをおき、そこに設定を記述します。
VSCodeではsetting.jsonでも設定できます。

【2024/08/13追記】
VSCode上で動作させるには、setting.jsonを編集する必要があるようです。
staticcheck ./...staticcheck.confを参照します。

【参考】公式 - configuration-files

【参考】VSCodeでの書き方

staticcheck.confの書き方

以下のように記述します。

staticcheck.conf
checks = ["inherit", "ST1003", "ST1016", "ST1020", "ST1021", "ST1022"]

checksという配列の中に有効にしたいチェックの番号を記述します。
inheritでデフォルトで有効なチェックを全て指定することができます。

基本的には、上記のように「inherit + デフォルトで無効だけど有効にしたいチェック」のような書き方になると思います。

checksの他にもいくつかの設定項目がありますが、個人的にはあまり使わなそうな印象です。

【参考】公式 - configuration

setting.jsonの書き方

以下のように記述します。

setting.json
{
    "gopls": {
        "ui.diagnostic.staticcheck": true,
        "analyses": {
            "ST1003": true,
            "ST1016": true,
            "ST1020": true,
            "ST1021": true,
            "ST1022": true
        }
    }
}

各チェック項目

以下の公式ページに一覧があります。

デフォルトで無効なチェック項目の精査

基本方針

デフォルトで有効なチェックは、理由がない限り有効のままで良いと思います。
開発を進めていくうちに、どうしても無効にしないといけない理由が出た時に無効にするくらいでしょうか。

なので、ここではデフォルトで無効なチェック項目を有効にした方が良いのか、1項目ずつ見ていきたいと思います。
といっても、7つしかないのでそんな労力ではないです。

有効・無効の検討は個人の偏見によるところが多いので、実際に案件に導入する際はチームで議論すべきだと思います。
正直、以前使っていたgolintに引きずられている部分もあります。

デフォルトで無効なチェック項目一覧

有効にするか検討

有効にする

  • ST1003 – Poorly chosen identifier
    • package名にキャメルケースやスネークケースを使ったり、命名でuserAPIuserApiにすると怒られる
      - 他にも細かな命名規則がある。詳細はリンク先
    • golintではチェックされていた項目
    • package名が読みづらくなるというつらみもある
      - kubernetesにもcredentialproviderのようなパッケージ名が存在する
      - https://github.com/kubernetes/kubernetes/tree/master/pkg/credentialprovider
    • 人によっては鬱陶しく感じる規則ですが、 自分はgolintの名残で有効にしました
    • 個人的にはこの規則のおかげで、やたらと長いパッケージ名を付けたりしないように意識できています
      - なるべくシンプルに、がGoですからね
  • ST1016 – Use consistent method receiver names
    • 同じ構造体のメソッドレシーバの名前が異なると怒られる
    • 統一した方がわかりやすいので有効にする。あえて別の名前を使う理由もない
    • 怒られる例
type UserRepository struct {
}

func (repo *UserRepository) Create{}
func (repository *UserRepository) Update{}

If every doc comment begins with the name of the item it describes, you can use the doc subcommand of the go tool and run the output through grep. Imagine you couldn't remember the name "Compile" but were looking for the parsing function for regular expressions, so you ran the command,
$ go doc -all regexp | grep -i parse

If all the doc comments in the package began, "This function...", grep wouldn't help you remember the name. But because the package starts each doc comment with the name, you'd see something like this, which recalls the word you're looking for.
$ go doc -all regexp | grep -i parse
  Compile parses a regular expression and returns, if successful, a Regexp
  MustCompile is like Compile but panics if the expression cannot be parsed.
  parsed. It simplifies safe initialization of global variables holding

無効のまま

type example struct{}

var ex example = example{}
var ex2 example = ex

感想

Effective GoやCodeReviewGuideを読み込む良い機会になりました。
Goに入門した時からなんども読んでいます。Goの思想に染まるには何回読んでもいいですからね!

あとは以下を強制するチェックがほしかったなーと思いました。

  • exportedな関数へのコメント
  • 1行あたりの最大文字数
    • Goでは特に決まりはない
      • Effective Go - formatting
        • Go has no line length limit. Don't worry about overflowing a punched card. If a line feels too long, wrap it and indent with an extra tab.
    • golangci-lintには制限するチェックがありそう
      - https://golangci-lint.run/usage/configuration/
      - 「line length」で検索
    • ライブラリもあるが、ファイル保存時の動作が重くなるかも?
      - golines
  • 引数が複数ある場合の関数の宣言方法

特に引数が複数ある場合の関数の宣言方法は悩みます。。
どんな書き方がいいんでしょう。

func functionExample(args1 string, args2 int, args3 int) int{
}

func functionExample(
  args1 string, args2 int, args3 int) int{
}

func functionExample(
  args1 string,
  args2 int,
  args3 int,
) int{
}

さいごに

Twitterの方でも、モダンな技術習得やサービス開発の様子を発信したりしているので良かったらチェックしてみてください!

また、BOT開発を通じてGoとLINE BOTにまとめて入門する記事をZennに掲載していますので、良かったらそちらもご覧ください!

34
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?