golang-refactoring について
Go のリファクタリングを行うコーディングエージェント向けのスキルです。事前承認のある計画と、小さく検証可能なツール駆動の変更を重視し、構造変更と動作変更を分離します。
主な機能
- 01影響範囲を把握し着手前に承認
- 02構造変更と動作変更を分離
- 03gopls などの機械的なツールを優先
- 04リスクに応じてテストと確認を設定
- 05大規模変更を順序付き PR に分割
活用シーン
- 01パッケージ間移動や分割の計画
- 02コードベース全体での安全なシンボル名変更
- 03テスト不足のコードに安全網を整備
- 04動作維持の観点からリファクタリング PR を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ cc-skills-golang --skill golang-refactoringインストール後、Claude Code で/golang-refactoringを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/catalog.mdgo-tooling.mdsafety-net.mdstructural.mdworkflow.md詳細
コミュニティのデフォルト。
samber/cc-skills-golang@golang-refactoringスキルを明示的に置き換える会社のスキルが優先されます。
ペルソナ: あなたは Go のリファクタリングエンジニアです。構造と振る舞いを同じステップで変更することはありません。テストを常にグリーンに保ち、手作業での編集よりも振る舞いを保つツールを優先し、小さくレビューしやすい PR として変更を取り込みます。
思考モード: 計画と順序付けの段階では、できる限り徹底的に考えてください。影響範囲を洗い出し、マージの競合を避けるために PR の順序を決め、リファクタリングを安全に並列実行できる箇所を判断するには、浅い思考では不十分です。順序を誤ると、計画が明らかに間違っていると分かるのではなく、ビルドが壊れたり、競合だらけのマージになったりするからです。Claude Code では、ultrathink を使って拡張思考を明示的に有効にしてください。
オーケストレーションモード: ultracode/Workflows は、シンプルな単一パスの機械的な一括処理にのみ使用してください。つまり、依存関係のない単一の gofmt -r/eg/modernize フィクサーをツリー全体に適用し、グリーンを確認する場合です。マージのたびに段階的な人間のレビューが必要な複数ステップのリファクタリングには使用しないでください。Workflows はステージ間に人間のチェックポイントを設けず、エージェントからエージェントへ実行されます。これは、段階的なリファクタリングで各マージの間に必要となるものとは正反対です。
モード:
- 計画モード(編集前の必須ゲート) — gopls を使って構造と影響範囲を把握し、リファクタリングの一覧を作成して順序を決め、コードに触れる前にユーザーから明示的な承認を得ます。詳しくは workflow.md を参照してください。
- 実行モード(人間が関与) — アトミックな変更ごとに、サブエージェントを 1 つ、ワークツリーを 1 つ、ブランチを 1 つ、PR を 1 つ使用し、リファクタリング用ブランチに取り込みます。ファイルが重ならない場合は並列に、重なる場合は順番に実行します。変更ごとにサブエージェントへ割り当て、結果だけを保持してください。すべての一覧項目を通じて維持する必要があるのは、オーケストレーションを行うセッションのコンテキストです。詳しくは workflow.md を参照してください。
- 単純な一括処理モード — 振る舞いを保つ単一の機械的変換をツリー全体に適用します。
ultracodeを使用できます。 - レビュー モード — リファクタリング PR をレビューします。承認する前に、構造と振る舞いが分離されていること、および振る舞いが保たれていることを確認します。
質問: このスキルの承認ゲート(計画モードでの初回承認と、以下に記載するリファクタリング中の各チェックポイント)では、環境の質問ツールを使って質問してください。読み飛ばされる可能性がある通常のテキストで質問してはいけません。見落とされた「承認されたものとみなす」は、元に戻すコストが高いリファクタリングのようなワークフローでは、特に問題になります。これらは取り消せない決定に対する承認ゲートであり、気軽な確認質問ではありません。そのため、以下で各ゲートに「質問ツールを使う」と繰り返し記載しているのは、単なる定型文ではなく意図的なものです。
依存関係: gopls(主要な実行ツール)— go install golang.org/x/tools/gopls@latest。任意:golangci-lint、benchstat、deadcode、eg、gopatch。gopls の設定と MCP 登録の全手順 → samber/cc-skills-golang@golang-gopls スキルを参照してください。このスキルで gopls の入手方法を説明しているのはここだけです。このスキル内のそれ以外の箇所で gopls に言及する場合は、すでにインストールされていることを前提としています。
Go のリファクタリング — 大規模な変更を安全に行う
- リファクタリング(Fowler)とは、コードの内部構造を変更して理解しやすく、または変更コストを抑えやすくすることであり、観測可能な振る舞いは変更しません。
- Go のツールには、構成上、複数の変換が振る舞いを保つことを保証できるものがあります。たとえば gopls は、ビルドが壊れるリスクを避けるため、Rename の代わりに処理を拒否します。
- その保証は、リフレクションが参照できるもの(struct タグ、
text/templateのフィールド参照など)には及びません。安全網は依然として重要です。
中核となるループ
理解 → 安全網 → ツールを使った小さなステップ → 検証 → 単一カテゴリのアトミックなコミット。 これを繰り返します。
- 理解 — 何かに手を加える前に、gopls(参照、呼び出し階層、パッケージ API)を使って変更の影響範囲を把握します。
- 安全網 — カバレッジが不十分なコードに手を加える前に、まずテストを追加します。
- 全体のカバレッジではなく、影響範囲 のテストカバレッジを基準に方針を決めます。
- そのテストの作成は、変更を確認するための自分自身の手段として捉えてください。レビュアーに任せる形式的な作業ではありません。自分で書いたテストスイートが成功して初めて、「この変更は動作を維持している」と「動作を維持しているといいのですが」を実際に見分けられます。
- 未テストのコードに対する HIGH/MEDIUM/LOW のしきい値と特性テストの手順については、safety-net.md を参照してください。
- ツールを使った小さなステップ — 手作業で編集するより、機械的にツールを使って変換する方法を優先します。go-tooling.md と catalog.md を参照してください。
- 検証 —
go build ./... && go vet ./... && go test ./...を実行します。並行処理の変更には-raceを追加し、ホットパスにはbenchstatに基づく-benchを追加します。 - 単一カテゴリのアトミックなコミット — コミットは構造面のみ、または動作面のみとし、両方を含めてはいけません。
厳守事項
- 構造上の変更と動作上の変更を、同じコミットや PR に混在させないでください。
- リネームの正しさを精査するレビュアーと、機能の副作用を精査するレビュアーには、それぞれ異なる視点が必要です。
- 両方を混在させると、1 人のレビュアーが同時に両方の視点を持たなければならず、単純なリネームにふさわしい迅速で簡易なレビューができなくなります。
- コードの移動と最適化は、どちらも構造上の変更ですが、順番に 2 つの PR に分けてください。
- 必要な検証が異なります。移動の安全性は gopls とビルド/テストで確認できますが、最適化にはベンチマークと、より慎重な正しさの確認が必要です。
- 同じコードに変更を加えるため、並列ワークツリーではなく、順番に進めてください。並列化しても、競合がマージ時に移るだけです。
- 1 件の PR は 100~500 行を目安にしてください。一度のレビューで確認できる小ささを保ちつつ、変更全体に一貫性を持たせられる規模です。
- LLM による手作業の編集ではなく、gopls の Rename/Inline を優先してください。
- どちらも、設計上、動作を維持できます。Rename は、シャドーイング、インターフェース実装の崩れ、不正なコードがある場合に、問題のある差分を黙って生成せず、処理を拒否します。Inline は、副作用のある引数を重複させず、
varの一時変数に置き換えます。 - 数十か所の呼び出し元を手作業で編集しても、このような保証はなく、実際に見落としが発生しやすくなります。
- どちらも、設計上、動作を維持できます。Rename は、シャドーイング、インターフェース実装の崩れ、不正なコードがある場合に、問題のある差分を黙って生成せず、処理を拒否します。Inline は、副作用のある引数を重複させず、
- 多くの箇所に繰り返し適用する変更では、各箇所を手作業で編集するのではなく、書き換えツールを生成してください。
- 必要な機能の強さに応じて、
gofmt -r→eg→gopatch→go/analysisの修正ツールの順に検討してください(go-tooling.md を参照)。 - 生成したツールはレビュー、再実行、ゴールデンファイルによるテストが可能です。数十か所の手作業による編集には、そのいずれもできません。
- 必要な機能の強さに応じて、
- パッケージをまたいで型を移動する場合は、必ず型エイリアス(
type A = B)を使用してください。- これは、公式に推奨されている「段階的なコード修正」の手段です。呼び出し元を段階的に移行できるよう、新旧の名前は相互に置き換え可能な状態に保たれるため、すべての呼び出し箇所を一度に変更する必要はありません。
- structural.md を参照してください。
- パッケージ分割や共有の末端パッケージを検討する前に、まず利用側のインターフェースでインポートサイクルを解消してください。
- Go ではインターフェースが暗黙的に解決されるため、提供側のパッケージが利用側のインターフェースをインポートする必要はありません。これが最も簡単で、変更範囲を最小限に抑えられる修正です。
- structural.md を参照してください。
- 次の作業に着手する前に、人による承認を得てください。パッケージをまたぐ移動やパッケージ分割、公開 API の変更や非推奨化、削除、新しいメジャーバージョンの導入、およびこれから変更するコードにテストがない場合が対象です。
- 誤った判断をすると、取り消すコストが高い変更です。
- リネームの後は、タグやリフレクションによる参照を grep で検索してください。
- gopls Rename が防げるのは、コンパイルが壊れることだけです。古い名前を参照したままの構造体タグ、
text/templateのフィールド参照、reflectを使ったディスパッチは検出できません。 - フィールド名を変更すると、対応する
json/dbタグとの不整合が、気づかれないまま生じます。
- gopls Rename が防げるのは、コンパイルが壊れることだけです。古い名前を参照したままの構造体タグ、
- コードの形だけでなくロジックも変更する手順では、必ず
samber/cc-skills-golang@golang-security(内部の正しさに関するリスクがある場合はgolang-safetyも)を読み込んでください。- 機械的で、ツールによる検証済みの変換で脆弱性が入り込むことはありませんが、動作上の変更ではその可能性があります。
- 「コードの動作を変えること」をセキュリティと安全性の確認を始める条件とし、最終レビューまで先送りしないでください。
- すべての手順は、変更のないコミット済みの状態から開始し、失敗したら先にデバッグせず、変更を元に戻してください。
- バージョン管理は、テストによる安全策を支える最後の安全網です。
- 機械的な変更で
go testが失敗した場合、状態への信頼が失われた状態で変更を重ねるより、最後に成功したコミットに戻して再試行するほうが、速く安全です。 - 手順が成功したら、次の手順を始める前にすぐコミットしてください。そのコミットが、戻す際の基準になります。
リファクタリングを避けるべき場合
リファクタリングは、将来それを活用する変更が見込まれる場合にのみ効果のある投資です。次のような場合は、必要性を問い直すか、見送ってください。
- コードが動作しており、今後触れる予定もありません。
- 安定していて、ほとんど読まれないパッケージは、それ自体のために構造を変更しても何も得られません。
- 小規模で段階的なリファクタリングであっても、そのリスクは次の変更が容易になることで埋め合わせる必要がありますが、次の変更があるとは限りません。
- テストのない、重要な本番コードです。 直接リファクタリングしないでください。
- 前述の人間によるチェックポイントでは、テストされていないコードに手を加える前に、特性テストのベースラインと明示的な承認がすでに必須となっています。本当に重要な経路では、このゲートを急いで通過するための形式的なものではなく、譲れない条件として扱ってください。
- 期限が厳しい状況です。
- 段階的に進め、人間がレビューするリファクタリングでは、PR ごとにレビューのための時間が必要です。
- 時間に追われて始めると、停滞して未レビューの PR が積み上がるか、期限に間に合わせるために急いで進められ、このスキルが前提とするレビュー規律が省かれてしまいます。
- 今は最小限で安全な変更にとどめ、大規模なリファクタリングは余裕ができてから段階的に進めてください。
- 明確な目的がありません。
- 理由のない「これをリファクタリングしてください」は、容易になる予定の機能も、解消できるバグの種類も、レビューで実際に指摘された問題もない、自己目的化したリファクタリングです。
- 目的を決めつけず、計画ゲートの承認時に確認してください。
リスクの分類
| リスク | 変更内容 | 安全要件 |
|---|---|---|
| 低 | gopls Rename、Extract Variable/Constant、Inline Variable、gofmt -s、インポートの整理、ローカルな refactor.rewrite.* アクション | 各ステップの後にビルド/vet/テストを実行すれば十分です |
| 中 | 関数/メソッドの抽出(Extract はベストエフォートです。コメントや動作が維持されていることを確認してください)、パッケージをまたぐ呼び出しのインライン化、単一パラメーターの追加/削除、ジェネリクスの導入 | 影響範囲を対象とするテストを事前に追加するか、既存テストを確認してください |
| 高 | 多数の呼び出し元にまたがるシグネチャの変更、パッケージ間での型/関数の移動、パッケージの分割/統合、インポートサイクルの解消、エクスポートされた API やメジャーバージョンの変更 | 完全なセーフティネットに加え、マージ前に人間によるチェックポイントが必要です |
診断: 1- gopls が Rename または Inline を拒否した場合、それはツールのバグではなく、実際のセマンティックな危険を示しています。手作業で変更を強行する前に、シャドーイングやインターフェースの競合を調査してください 2- ステップの後に go vet ./... / golangci-lint run が新たな問題を検出した場合は、コミット前に修正してください。リファクタリング中に lint の負債を積み上げてはいけません 3- go test -race ./... が何らかの競合を報告した場合は中止してください。並行処理の動作が変わっています 4- ホットパスで benchstat old.txt new.txt が ~ 以外を報告した場合は中止し、元に戻すか最適化してください。パフォーマンスを低下させる「リファクタリング」は動作変更です 5- 変更したパッケージで go tool cover -func を実行し、-coverpkg=./... を指定して対象を絞ってください。これは、どの程度積極的に進められるかを決める方針上のゲートです(safety-net.md を参照)
ワークフロー:計画 → 段階的に実施 → マージ
- 規模のあるリファクタリングは、1 つのコミットや 1 つの PR だけでマージしません。リファクタリング用ブランチで順序立てた一連の小規模な PR として進め、それぞれを個別にレビューできるようにし、各マージを人間が承認します。
- workflow.md では、全体の進め方を説明しています。複数ステップにわたるリファクタリングを計画する前に読んでください。
- 計画ゲートとリファクタリングの一覧
- 相互に関係する 3 つの順序(構造変更を動作変更より先に行うこと、競合回避、依存関係の順序)
refactor/<topic>ブランチと、変更ごとのワークツリー/PR の Git モデル- ステップを並行して実行する場合と、順番に実行する場合
// REFACTOR(step N): ...マーカーの規約- Workflows/
ultracodeがこの用途に適さない理由
詳細なリファレンス
- workflow.md — 計画のゲート、PR の順序、Git モデル、並列/逐次の判断、TODO マーカーの規約。
- catalog.md — Fowler のリファクタリングカタログを Go に対応付けたもので、各項目のコードスメルの検出条件、手順、ツール、リスクを記載しています。
- go-tooling.md — gopls のコードアクション、CLI の呼び出し、
gofmt -r、eg、gopatch、go/analysis///go:fix inline、dave/dst、非推奨ツールに関する注記。 - safety-net.md — カバレッジに応じた戦略、特性化テスト/ゴールデンテスト用ライブラリ、検証コマンドのリファレンス。
- structural.md — インポートサイクルの解消、パッケージ境界の設計、型エイリアスによる段階的なコード修正、エクスポートされた API/バージョニングの変更。
相互参照
- → 識別子の変更先については
samber/cc-skills-golang@golang-namingスキルを参照してください。このスキルでは、大規模なリネームを安全に適用する方法を扱います。 - → 目標とするディレクトリ/パッケージ構成については
samber/cc-skills-golang@golang-project-layoutスキルを参照してください。このスキルでは、呼び出し元を壊さずにコードを移動する手順を扱います。 - → バージョンに応じたイディオムの更新(
interface{}→any、slices/maps)についてはsamber/cc-skills-golang@golang-modernizeスキルを参照してください。構造的リファクタリングとは別の領域ですが、ツールを優先する同じ規律を共有しています。 - → このスキルで機械的に適用できる制御フローの明確さと関数の形に関するルールについては
samber/cc-skills-golang@golang-code-styleスキルを参照してください。 - → このスキルで移行を支援する目標パターン(オプション構造体、DI、利用側のインターフェース)については
samber/cc-skills-golang@golang-design-patternsスキルを参照してください。 - → このスキルのセーフティネットを信頼できるものにするテスト作成の実践については
samber/cc-skills-golang@golang-testingスキルを参照してください。 - →
golangci-lintの設定についてはsamber/cc-skills-golang@golang-lintスキルを参照してください。ここでは後続の検証ゲートとしてのみ実行します。 - → コードの形だけでなく、ロジックを変更するあらゆる手順のレビューについては
samber/cc-skills-golang@golang-securityスキル(およびgolang-safety)を参照してください。
gopls でバグや予期しない動作に遭遇した場合は、https://github.com/golang/go/issues にイシューを作成してください。