個人開発で Go を使って開発を進めている。
Linter として golangci-lint を使っている。
設定内容の理解を深めるために、施している設定の解説をしてみる。
golangci-lint は Go 言語用の高速な静的解析ツール。
単体の Linter と異なり、複数の Linter を統合して解析することができる。
Go 言語にはそれぞれ特色が異なる Linter が複数存在している。
それらを1つずつ導入・実行するのは手間がかかるため、設定ファイル一つで一元管理できるツールとして多くのプロジェクトや OSS で活躍中。
golangci-lint は現在 v2.11.4 を使っている。
これは今後 Renovate などを使って随時更新してく予定。
v2.11.4 において自分が今回施した golangci-lint の設定は以下の通り。
version: "2"
run:
timeout: 5m
modules-download-mode: readonly
linters:
enable:
- errcheck
- govet
- staticcheck
- unused
- gosec
- depguard
- errorlint
- revive
- gocritic
- cyclop
- nolintlint
settings:
cyclop:
max-complexity: 10
nolintlint:
require-explanation: true
depguard:
rules:
domain-no-outward-deps:
files:
- "**/internal/domain/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/application
desc: "domain層はapplication層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "domain層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "domain層はinfrastructure層に依存禁止"
usecase-no-outward-deps:
files:
- "**/internal/application/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "application層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "application層はinfrastructure層に依存禁止"
presentation-no-infra-deps:
files:
- "**/internal/presentation/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/domain
desc: "presentation層はdomain層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "presentation層はinfrastructure層に依存禁止"
formatters:
enable:
- gofmt
- goimports
settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/Soh1121/tlane
issues:
max-issues-per-linter: 50
max-same-issues: 3version: "2"設定バージョンを指定する。
指定可能な値は 2 のみである。
run:
timeout: 5m
modules-download-mode: readonlytimeout は静的解析のタイムアウト時間。
デフォルトは 0 でタイムアウト無しとなっている。
おかしな挙動をしてても止まらないのは嫌なので5分を設定。
modules-download-mode: readonly: go.mod / go.sum
を実行中に書き換えさせない設定。CI等でのモジュール整合性担保に効きます
modules-download-mode が設定されている場合、その値が go list -mod={option} に渡される。readonly を指定することで、go.mod が更新されないようにしている。
他の選択肢として、以下が設定可能。
vendor:vendor/ディレクトリに依存関係のコピーが保持されているとしてgo.modを無視するmod:go.modを自動更新して実行する
linters:
enable:
- errcheck
- govet
- staticcheck
- unused
- gosec
- depguard
- errorlint
- revive
- gocritic
- cyclop
- nolintlint
settings:
cyclop:
max-complexity: 10
nolintlint:
require-explanation: true
depguard:
rules:
domain-no-outward-deps:
files:
- "**/internal/domain/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/application
desc: "domain層はapplication層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "domain層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "domain層はinfrastructure層に依存禁止"
usecase-no-outward-deps:
files:
- "**/internal/application/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "application層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "application層はinfrastructure層に依存禁止"
presentation-no-infra-deps:
files:
- "**/internal/presentation/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/domain
desc: "presentation層はdomain層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "presentation層はinfrastructure層に依存禁止"5.1. linters.enable
有効化されている Linter 一覧。
| Linter | 役割 |
|---|---|
| errcheck | エラーの戻り値を握りつぶしていないか確認する。 |
| govet | Go 公式の静的解析。 フォーマット文字列の型不一致など。 |
| staticcheck | バグの温床になりがちなコードパターンを検出。 |
| unused | 未使用の変数・関数・import を検出。 |
| gosec | セキュリティ的に危険なコードを検出。 |
| depguard | 特定パッケージへの依存を禁止する。 オニオンアーキテクチャのために導入。 |
| errorlint | errors.Is/As を使うべきところで == 比較していないか確認。 |
| revive | golint の後継。 命名規則やコードスタイルをチェック。 |
| gocritic | 診断ルールが豊富なメタリンター。 |
| cyclop | 循環的複雑度のチェック。 |
| nolintlint | // nolint コメントの書き方をチェック。 |
5.2. linters.settings
settings:
cyclop:
max-complexity: 10
nolintlint:
require-explanation: true
depguard:
rules:
domain-no-outward-deps:
files:
- "**/internal/domain/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/application
desc: "domain層はapplication層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "domain層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "domain層はinfrastructure層に依存禁止"
usecase-no-outward-deps:
files:
- "**/internal/application/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "application層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "application層はinfrastructure層に依存禁止"
presentation-no-infra-deps:
files:
- "**/internal/presentation/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/domain
desc: "presentation層はdomain層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "presentation層はinfrastructure層に依存禁止" cyclop:
max-complexity: 10関数の循環的複雑度が10を超えるとエラーとなるようにする設定。
デフォルトで10だが明示しておく。
nolintlint:
require-explanation: true// nolint を使用するときに説明を必須とする設定。
デフォルトで false なので、 true で有効化しておく。
「なぜ」をコメントで残しておくのは大事。
depguard:
rules:
domain-no-outward-deps:
files:
- "**/internal/domain/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/application
desc: "domain層はapplication層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "domain層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "domain層はinfrastructure層に依存禁止"
usecase-no-outward-deps:
files:
- "**/internal/application/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/presentation
desc: "application層はpresentation層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "application層はinfrastructure層に依存禁止"
presentation-no-infra-deps:
files:
- "**/internal/presentation/**"
deny:
- pkg: github.com/Soh1121/tlane/internal/domain
desc: "presentation層はdomain層に依存禁止"
- pkg: github.com/Soh1121/tlane/internal/infrastructure
desc: "presentation層はinfrastructure層に依存禁止"オニオンアーキテクチャを静的解析で守るための設定。
ドメイン層は他の層に依存禁止だし、アプリケーション層はプレゼンテーション層・インフラ層に依存禁止、プレゼンテーション層はインフラ層・ドメイン層に依存禁止という設定。
気を抜くとうっかり依存しかねないし、AI に実装を頼むと違反しかねないので、こういう静的解析でガードレールが敷かれていると安心できる。
formatters:
enable:
- gofmt
- goimports
settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/Soh1121/tlanev2 から formatters は linters とは別のセクションに分離されたらしい。
6.1. formatters.enable
enable:
- gofmt
- goimports有効化しているフォーマッターは gofmt と goimports の2つ。gofmt は Go 公式のフォーマッターで、インデント・スペース・改行位置など、コードの「見た目」を Go 標準に揃えてくれる。goimports は import 文の自動整形をしてくれるツール。
具体的には以下のようなことを行う。
- 使われていない import 文を削除
- 使っているのに import し忘れているパッケージを自動追加
- import をグループ分けしてアルファベット順に並び替え
6.2. formatters.settings
settings:
gofmt:
simplify: true
goimports:
local-prefixes: github.com/Soh1121/tlanesettings は有効化しているフォマッターの設定を行う部分。
gofmt.simplify: true は冗長な書き方を、より簡潔な等価なコードに変換してくれるようにする。
goimports.local-prefixes: github.com/Soh1121/tlane は import 文をグループ分けする際に基準となる設定。
これを指定すると、import 文が標準ライブラリ・外部パッケージ・自プロジェクトの3つのグループに分けられて整形される。
issues:
max-issues-per-linter: 50
max-same-issues: 3issues は Linter の出力結果を制御するパート。
max-issues-per-linter では Linter ごとに最大いくつ issue を出力するかを設定する。
デフォルトで50となっているが、明示することでわかりやすくしておく。
max-same-issues は同種の issue を何件まで表示するかの設定。
ここでもデフォルト通り3件に設定しておく。
この記事では個人開発を行っている Go プロダクトの golangci-lint の設定を紹介した。
まだ機能するところまでは進められていないが、この設定をベースに開発を進めていきたい。
AI エージェントを活用しながら進める予定なので、Linter などのガードレールを活用しながら時間をかけずに進められるよう工夫していきたい。
