mcpField
G
go-modernize

go-modernize

github.com/eduardo-sl開発83146 回インストール2 週間前に更新
リポジトリ

go-modernize について

Go モジュールの Go ディレクティブが許可する機能を使い、コードを段階的に更新するスキルです。言語や標準ライブラリーの移行とバージョンアップ手順を扱います。

主な機能

  1. 01段階的なモダナイズの作業モード
  2. 02Go バージョン別の機能リファレンス
  3. 03公式モダナイザーの利用ガイド
  4. 04標準ライブラリー API の移行例
  5. 05バージョン互換性の確認項目

活用シーン

  1. 01編集中のコードだけをモダナイズ
  2. 02Go ディレクティブの引き上げを計画
  3. 03非推奨または旧式の標準ライブラリー利用を更新
  4. 04パッケージやモジュール全体のモダナイズ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-modernize

インストール後、Claude Code で/go-modernizeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
generics.md
go1.27.md
stdlib-migrations.md
version-bump.md

詳細

Go のモダナイズ

Go は進化します。Go 1.16 向けに書かれたコードと、Go 1.27 を対象にしたコードは同じ見た目であるべきではありません。段階的にモダナイズしてください。まず go.mod を更新し、その後で新しいパターンを採用します。

go.mod の go ディレクティブで指定されたバージョンを超える機能は採用しないでください。ディレクティブは意図的に、独立したコミットで引き上げ、プロジェクトの CI とデプロイ用イメージで実際に実行されるバージョンに限ってください。

詳細なリファレンス資料は、必要に応じて読み込みます。

  • references/generics.md — interface{} を型パラメーターに置き換える方法、制約、ジェネリックコンテナー、ジェネリクスを使うべきでない場合。
  • references/stdlib-migrations.md — slog、errors.Join、slices/maps ヘルパー、整数範囲ループ、イテレーターの変更前後の例。
  • references/go1.27.md — ジェネリックメソッド、CutLast、URL/Values Clone、big.Int.Divide、標準ライブラリの uuid、json/v2 のセマンティクス、synctest と httptest の追加機能、ツールの変更。
  • references/version-bump.md — go ディレクティブを引き上げる際に発生しうる変更への手順と、リリースごとのチェックリスト(1.25-1.27)。

以下の概要で不十分な場合にのみ、リファレンスファイルを読んでください。

作業モード

  • インライン(デフォルト — 開発者が別の作業を進めている場合): すでに変更している行だけをモダナイズします。ほかの改善点は、得られる効果を添えて最後に一度だけ提案してください。関係のないファイルには触れないでください。依頼されていない一括変更は、本来の変更を大量の差分に埋もれさせてしまいます。提案が却下された場合、セッション中に再度持ち出さないでください。開発者がその意向を記録したい場合は、プロジェクトのエージェント設定ファイル(CLAUDE.md、AGENTS.md)に1行追加してください。
  • バージョン引き上げ(go ディレクティブを引き上げる場合):ソースを変更しなくても動作が変わります。機能を採用する前に、references/version-bump.md に従い、前提条件とリリースごとの変更チェックリストを確認してください。
  • 一括変更(パッケージまたはモジュールのモダナイズを依頼された場合):以下の手順を実行し、カテゴリごとに1つのコミットを作成します。カテゴリは go fix の出力、非推奨 API、言語機能、標準ライブラリのヘルパー、テストです。それぞれビルドとテストに成功する状態にしてください。各カテゴリは独立しています。環境が並列サブエージェントに対応している場合は、それぞれにカテゴリを割り当て、別々のブランチまたはワークツリーで作業させてください。

優先順位

時間が限られている場合は、次の順に適用してください。

  1. 正確性とセキュリティ — == の代わりに errors.Is/As を使う、http.NewRequestWithContext、ユーザー指定のパスには os.Root を使う、乱数が何かを保護する箇所では crypto/rand を使う、非推奨の x/crypto パッケージを標準ライブラリの同等パッケージに置き換える。
  2. 可読性 — any、min/max、整数範囲ループ、slices/maps、cmp.Or、sync.OnceValue、wg.Go、errors.AsType。
  3. 段階的な移行 — イテレーター、ロガーの slog への移行、go.mod のツールディレクティブ、標準ライブラリで対応できるようになった依存関係の削除。

モダナイズの手順

  1. go.mod の go ディレクティブを確認します。使用できる機能は、このディレクティブのバージョンで制限されます。バージョンの引き上げはバージョン引き上げモードの作業であり、機能変更に伴う副次的な変更として行ってはなりません。

  2. まず公式のモダナイザーを実行します。機械的な移行を自動で見つけて修正できます。

    # Go 1.26+ — the modernizers now live in go fix
    go fix ./...
    
    # Go 1.25 and earlier, or a modernizer newer than your toolchain
    go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...
    

    どちらのコマンドもソースを直接書き換えます。実行前にコミットし、差分を確認してください。どちらのコマンドも使用できない場合は、以下の表を手動で適用してください。

  3. アナライザーが対象としない、判断が必要な移行(ジェネリクス、イテレーター、ロガーの置き換え)について、以下の表を確認し、個別に適用します。

  4. 変更のグループごとに go build ./... とテストスイートを実行します。

Go バージョン別機能一覧

Go バージョン機能対応
1.13+errors.Is, errors.Asエラー比較の == を置き換えます
1.13+http.NewRequestWithContexthttp.NewRequest を置き換えます
1.16+embedgo-bindata / packr を置き換えます
1.18+ジェネリクスinterface{} を使うユーティリティ関数を置き換えます
1.20+errors.Join手動でのエラー集約を置き換えます
1.21+log/slog構造化ログには log の代わりに使用します
1.21+slices, maps手書きのスライス/マップ用ユーティリティを置き換えます
1.21+min, max 組み込み関数math.Min/math.Max(float64 専用)を置き換えます
1.21+sync.OnceValue, sync.OnceFuncsync.Once とパッケージ変数の組み合わせを置き換えます
1.22+int に対する rangefor i := 0; i < n; i++ を置き換えます
1.22+ループごとの反復変数v := v のシャドーコピーを削除します(go.mod が 1.22+ を示す場合に限ります)
1.22+math/rand/v2math/rand を置き換え、rand.Seed を削除します
1.22+cmp.Or「最初のゼロ以外の値」を選ぶ if 連鎖を置き換えます
1.22+メソッドとワイルドカードパターンに対応した ServeMuxGET /users/{id} だけに使うルーター依存関係を置き換えます
1.23+func に対する rangeコールバックベースの反復処理を置き換えます
1.23+unique.Make手作りの文字列インターン化を置き換えます
1.24+for b.Loop()ベンチマークの for range b.N を置き換えます
1.24+t.Context()テストでの context.Background() を置き換えます
1.24+os.Root手動のパストラバーサルチェックを置き換えます
1.24+go.mod のツールディレクティブtools.go のブランクインポートファイルを置き換えます
1.24+runtime.AddCleanupruntime.SetFinalizer を置き換えます
1.24+omitzero 構造体タグGo のゼロ値(例:time.Time{})を省略する必要がある場合に、omitempty を置き換えます
1.24+strings.SplitSeq, strings.Lines, FieldsSeqスライスを range で反復するだけの場合に、Split を置き換えます
1.24+crypto/sha3, crypto/hkdf, crypto/pbkdf2golang.org/x/crypto の各機能を置き換えます
1.24+crypto/rand.Text手作りのランダムトークンエンコーダーを置き換えます
1.25+testing/synctest並行処理のテストでの time.Sleep を置き換えます
1.25+sync.WaitGroup.Gowg.Add(1) と go func(){defer wg.Done()} の組み合わせを置き換えます
1.25+reflect.TypeAssertv.Interface().(T) を置き換えます(割り当てなし)
1.25+コンテナーを考慮する GOMAXPROCSgo.uber.org/automaxprocs を削除します
1.26+errors.AsType宣言済みのターゲット変数を使う errors.As を置き換えます
1.26+slog.NewMultiHandler手書きのファンアウトハンドラーを置き換えます
1.26+new(expr)アドレスを取得するための一時変数を置き換えます
1.26+httputil.ReverseProxy.Rewrite非推奨で安全性に問題のある Director フックを置き換えます
1.27+ジェネリックメソッド1 つの型に属するパッケージレベルのジェネリックヘルパーを置き換えます(インターフェースで公開する必要がある場合を除く)
1.27+リテラルのキーとしての昇格フィールドOuter{Inner: Inner{ID: x}} のネストを置き換えます
1.27+strings.CutLast, bytes.CutLastLastIndex とスライス操作を置き換えます
1.27+url.URL.Clone, url.Values.Clone手書きのディープコピーを置き換えます
1.27+big.Int.DivideQuoRem と符号補正を置き換えます
1.27+標準ライブラリの uuidv4/v7 ID に google/uuid を使う代わりに採用します
1.27+encoding/json/v2呼び出し箇所ごとに採用します — セマンティクスがより厳格です。リファレンスを参照してください
1.27+synctest.Sleep, httptest.NewTestServertime.Sleep+Wait とソケットに依存するテストサーバーを置き換えます
1.27+testing/cryptotest.SetGlobalRandomテストでの tls.Config.Rand を置き換えます

移行例

上記の各行の変更前/変更後の例は、 references/stdlib-migrations.md(標準ライブラリと言語機能)および references/generics.md(型パラメーター)にあります。テスト固有の移行 — t.Context()、b.Loop()、synctest — は go-test-quality スキルが担当します。

確認チェックリスト

  1. go.mod のバージョンが、コードベースで使用している機能に合っている
  2. any や型パラメーターを使うほうが明確な箇所で、interface{} を使っていない
  3. 構造化ログには log.Printf ではなく log/slog を使っている
  4. エラー文字列を手動で連結するのではなく、errors.Join を使っている
  5. 手書きのループを slices.Contains、slices.SortFunc、maps.Clone に置き換えている
  6. 該当する箇所では、整数の範囲指定(for i := range n)を使っている
  7. http.NewRequest ではなく http.NewRequestWithContext を使っている
  8. sort.Slice を使わず、cmp.Compare と slices.SortFunc を使っている
  9. 型安全なコンテナーやユーティリティにはジェネリクスを使い、単純なケースでは使いすぎていない
  10. サードパーティー依存関係を、最近の Go バージョンで追加された標準ライブラリの代替手段と比較して評価している
  11. 手動の Add/Done ペアではなく、sync.WaitGroup.Go を使っている(Go 1.25 以降)
  12. テストで t.Context() と for b.Loop() を使っている(Go 1.24 以降)
  13. tools.go を go.mod の tool ディレクティブに置き換えている(Go 1.24 以降)

コメント