AIエージェント × knipで無駄コードを簡単に掃除等で紹介されているが、 TypeScriptであればknipのような便利ツールがある。Goだとdeadcodeがそれかなーと思いつつ、AI時代にデッドコードを削除したり、アーキテクチャの制約を機械的に検知したくなるのでメモ書き。
deadcodeでコード削除
皆さんお馴染みdeadcode は Go公式ツールの一部。コールグラフ解析で到達不可能な関数を検出する。
go run golang.org/x/tools/cmd/deadcode@latest -test ./...
-test つけるとテストから呼ばれてる関数は除外してくれる。
go-arch-lintでアーキテクチャを保つ
go-arch-lint は Go のパッケージ間依存を YAML で定義して違反を検出するツール。
存在はこれで知った。
.go-arch-lint.yml をリポジトリルートに置く:
(例)
version: 3 workdir: . components: # Domain 層 domain_user: in: internal/domain/user domain_order: in: internal/domain/order # UseCase 層 usecase: in: internal/usecase/** # Infrastructure 層 infra_repository: in: internal/infra/repository infra_repository_impl: in: internal/infra/repository/postgres infra_external: in: internal/infra/payment # 共通パッケージ pkg: in: pkg/** commonComponents: - pkg deps: domain_order: mayDependOn: - domain_user usecase: mayDependOn: - domain_user - domain_order - infra_repository - infra_external infra_repository_impl: mayDependOn: - domain_user - domain_order - infra_repository
mayDependOn はホワイトリスト方式。なので書いてないやつは全部違反になる。
golangci-lintで未使用コード検出
unused(未使用の宣言)、unparam(未使用の引数)、ineffassign、wastedassign あたりを有効化し、いらないものを検知できるようにする。
linters: enable: - unused - unparam - ineffassign - wastedassign
カスタムリンター
go-arch-lint で足りなければ go/ast でカスタムリンター書ける。例えば UseCase の公開メソッドにGoDocを強制するリンター
file, _ := parser.ParseFile(fset, path, nil, parser.ParseComments) for _, decl := range file.Decls { fn, ok := decl.(*ast.FuncDecl) if !ok || fn.Recv == nil || !ast.IsExported(fn.Name.Name) { continue } // レシーバの型名を取得(*OrderUseCase → "OrderUseCase") recvType := fn.Recv.List[0].Type if star, ok := recvType.(*ast.StarExpr); ok { recvType = star.X } ident, ok := recvType.(*ast.Ident) if !ok || !strings.HasSuffix(ident.Name, "UseCase") { continue } // GoDoc に必要な行があるかチェック if fn.Doc == nil { // GoDoc 自体がない → 違反 } else { found := false for _, c := range fn.Doc.List { if strings.Contains(c.Text, "....") { found = true } } if !found { // ... 行がない → 違反 } } }
parser.ParseFile して file.Decls をループ、条件に合う関数の fn.Doc を覗くだけ。100〜200行で書けるのでプロジェクト固有ルールの強制におすすめ。
試してないやつ
DatadogのHow we reduced the size of our Agent Go binaries by up to 77%が面白かった。
Datadogはdeadcodeでリンカーの最適化が無効化を特定し、reflect の呼び出しサイトをパッチ。さらに goda で依存グラフを可視化して不要なパッケージ依存を丸ごと削除。結果、バイナリサイズ最大77%削減したらしい。
自分のプロジェクトはそこまで巨大じゃないのでソースコードレベルで十分だけど、大規模になったらこのアプローチも試してみたいなーと思う。