- Go 1.26 では、全面的に書き直された
go fix コマンドが導入され、最新の言語機能やライブラリ機能を活用してコードを自動的に改善できる
- このツールは 数十種類のアナライザ analyzer によってコードパターンを検出し、
minmax、rangeint、stringscut などさまざまな モダナイザー modernizer を適用して、反復的または古いコードを最新の形へ変換する
- 新機能である
new(expr) のサポートのために、newexpr アナライザが追加され、newInt のようなヘルパー関数を自動的に単純化できる
go fix は 複数回実行すると相乗効果を発揮し、異なるアナライザが連続して改善を提案でき、競合時には自動マージや不要な import の削除機能も含む
- Go チームは今後、Self-service 分析パラダイムを通じて、開発者が独自 API 向けのモダナイザーを定義して配布できるように拡張する計画
go fix コマンドの概要
- Go 1.26 で
go fix が 全面的に再実装され、コードベースを最新の Go スタイルへ自動変換する機能を提供
go fix ./... コマンドで現在のディレクトリ以下のすべてのパッケージを修正
-diff オプションで変更内容を事前に確認可能
- 登録済みアナライザの一覧は
go tool fix help で確認でき、any、forvar、mapsloop、minmax など多様な変換ルールを含む
- 特定のアナライザだけを実行するには
-any のようなフラグを使い、除外するには -any=false を指定
- プラットフォームごとのコード差異を考慮して、
GOOS、GOARCH の組み合わせごとに複数回実行可能
Modernizers — コードモダナイズツール
- Go 1.18 以降、ジェネリクスの導入によってコードを単純化できる可能性が大きくなった
- 例:
maps.Keys による map キー収集、strings.Cut による文字列分割
- LLM ベースのコード生成ツールが古いパターンを維持してしまう問題を解決するため、最新の Go イディオムを反映したオープンソースコード更新の必要性を強調
go fix と gopls に含まれるモダナイザーは、コードの可読性と学習効果を高める
- モダナイザーの例:
- minmax:
if 文を min / max 関数に置き換える
- rangeint: 3 項
for 文を range-over-int に変換
- stringscut:
strings.Index ベースのコードを strings.Cut で単純化
Go 1.26 の new(expr) 機能
new 関数が 値引数を受け取れるように拡張され、new("go1.26") の形で初期化可能
newexpr アナライザは newInt のようなヘルパー関数を見つけて return new(x) に単純化し、呼び出し側を new(expr) に置き換える
- 最小 Go バージョン要件(例:
go 1.26 ディレクティブ)を満たす場合にのみ適用
$ go fix -newexpr ./... コマンドでコードベース全体に適用可能
- 使用後に不要になったヘルパー関数は
deadcode ツールで特定可能
相乗効果と競合処理
- 1 回の修正が別の修正機会を生む 相乗効果がある
- 例:
minmax 適用後に追加の変換提案が生まれる
stringsbuilder → fmt.Fprintf へと続く連続最適化も可能
go fix は 3-way merge アルゴリズムで修正競合を自動マージする
- 構文上の競合がある場合はその修正をスキップし、警告を表示
- 意味的な競合(例: 変数削除、未使用 import)は手動調整が必要
- 不要な import は自動削除
Go 分析フレームワークとの統合
go vet と go fix は 共通の分析フレームワークを共有するよう統合
vet はエラー検出重視、fix は安全な自動修正重視
- アナライザは
unitchecker、multichecker、gopls、staticcheck、Tricorder などさまざまなドライバで実行可能
- fact システムにより、パッケージ間で情報共有が可能
- 例:
log.Printf が fmt.Printf のラッパーであると推論できる
gopls はリアルタイム診断と自動修正提案機能を提供
分析インフラの改善
- inspector パッケージの拡張により AST 探索の効率が向上し、
Cursor 型で上下左右への探索をサポート
- typeindex による関数呼び出しインデックス化で、分析速度が最大 1000 倍向上
- その他の改善点:
- 標準ライブラリの 依存グラフを提供
- ファイルごとの Go バージョンクエリをサポート
- リファクタリングプリミティブの拡充により、コメントアウトなど安全なコード修正が可能
- 一部のモダナイザーは微妙な挙動変化のため除外された(
append([]string{}, slice...) → slices.Clone(slice) の事例)
- 今後は パターンマッチングエンジン、自動テストハーネス、正確な修正演算子ライブラリを開発予定
Self-service パラダイム
- Go 1.26 から Self-service 分析モデルの導入を予告
- 開発者が独自 API 向けモダナイザーを定義して配布可能
- 集中承認手続きなしで、プロジェクトレベルで実行可能
- 第一段階として、アノテーション駆動インライナー Annotation-driven inliner 機能がプレビューとして含まれる
- 今後の計画:
- 動的ロードによるユーザー定義アナライザの実行(
go fix または gopls 内)
- 制御フローベースのチェック一般化。例: 「open の後に close」、「lock の後に unlock」などの不変条件を検証
- 目標は、保守効率の向上と最新 Go 機能の迅速な導入支援
1件のコメント
Hacker Newsの意見
2024年末にLLMコードアシスタントが急速に普及したとき、こうしたツールが学習データ中の既存のGoコードスタイルをそのまま再現する傾向があるのは興味深かった
最新の構文を使うよう指示しても無視したり、存在しないとまで否定することさえあった
今後のモデルが最新のGo 1.25イディオムを反映するには、オープンソースコード全体がそのスタイルへ更新される必要がある
しかしLLMは一度誤ったデータが入ると修正がほとんど不可能だ
モデルがどんな根拠で結論を出したのか追跡しづらく、次世代モデルで修正されることを願うしかない
単純に見えるのでレビューを通過するが、実際にはエラー処理やエッジケースが抜け落ちている
レビュー後に再びLLMへ入れると、見た目には修正されたコードが出てくるものの、その中にデータレースやデッドロックが生じる
ほぼすべてのモデルで繰り返される問題だ
Goは後方互換性が高いのでコンパイルは通るが、コードスタイルがあまりにも違ってしまう
PythonではAPI変更によって実際の互換性破壊が起きる
それでもGoは言語の安定性と標準ライブラリのおかげで、コード生成向けの言語としては非常に優れている
Rob Pikeの警告どおり、こうした技術はソフトウェア生態系の汚染だ
多くの人は「便利さ」というスロップ(slop) を求めているが、それこそが問題の本質だ
ソースコードを自動で最新スタイルへ変換してくれるツールは本当に素晴らしい
JavaのOpenRewriteが代表例だが、他の言語では同様のものがあまり思い浮かばない
Goのようにこうした機能が言語に組み込まれているなら、言語の成熟度は大きく高まる
今後の新しい言語は、Goのこうした統合的アプローチを参考にしそうだ
JetBrainsのIDEは数百万行のコードを一度にリファクタリングしたり、新しい構文へ自動変換したりできる
ConvertToPrimaryConstructor のような機能もある
また、Structural Search and Replace は単なるテキストではなく言語構文レベルで動作する
.NETのRoslynアナライザーもIDEでコード修正提案を提供する
チュートリアルリンク
おかげでコードがずっときれいになった
concatとmapをconcatMapに変えたり、不要なif式を簡略化してくれるLSPサーバーは機能不足で、引数削除のような基本的なリファクタリングすらサポートしていない
jscodeshiftやClaudeを組み合わせれば可能なのか考えている
こうした自動修正ツール(go fix) のおかげで、Goは本当に優れた言語だ
新機能のrangeintもgo fixで自動反映される予定なので期待している
Goチームに賛辞を送りたい
コンパイル速度も信じられないほど速い
forループを探して修正していたが、今ではこのツールがずっと洗練された方法で処理してくれる記事では触れられていないが、私が一番気に入っている機能は
//go:fix inlineディレクティブだ1行関数を呼び出し元へインライン展開してくれる
ライブラリ作者が旧バージョンの関数を新バージョンへ自然に自動移行できるようにしてくれる
semverが変わっても
go fixで自動アップグレードが可能だ最近見たWes McKinneyのポッドキャストで、
Goは高速なコンパイル・実行サイクル、強い型システム、マルチスレッド安全性のおかげでコーディングエージェントに理想的だと言っていた
その話を聞いてGoにまた興味が湧いてきた
Goの確立されたツール体系と慣習はエージェントベース開発に大いに役立つ
go run main.goですぐに開発環境を立ち上げられ、複数のワークツリーや中央設定、マイグレーション済みDBまでサポートできるhousecat-inc/cheetahでこうしたツールを共有している
go generate,go build,go test,go vetまで含んだ高速ループにgo fixを追加するつもりだPythonを学んでいると、同じことをする方法が多すぎて一貫性がない
Cのように1つのやり方しかないほうがむしろ恋しくなる
Goはこの段階に達しているのだろうか
LLMの助けがなくてもベストプラクティスに従える言語なのか知りたい
複雑さを避けて単純さを保とうとする努力が印象的だ
Pythonの混乱に疲れた人には勧められる
セルフサービスアナライザーという概念が本当に興味深い
大規模ライブラリやインフラチームで積極的に活用されそうだ
こういうツールがあるなら、後方互換性のない言語も可能なのではないかという気がしてくる
TypeScriptの世界ではbiomeがこうした役割を果たしている
たとえば
forEachの代わりにfor...ofを推奨し、ultraciteと一緒に使うとワークフローがずっと滑らかになるagents.mdファイルに「修正後にbiome fixを実行」と明記してあり、そのおかげでコード品質が自動的に保たれているeslintよりずっと軽量で効率的な体験だ