go-spec-reviewer について
go-spec-reviewerは、実装計画の前にGoの設計ドキュメントを確認するスキルです。完全性や一貫性、Goの慣用設計、リポジトリの規約、CLI固有のパターンを検証し、問題点や質問、承認を示します。
主な機能
- 01仕様の完全性と一貫性の確認
- 02リポジトリ規約に沿ったレビュー
- 03Goの慣用設計とエラー処理の評価
- 04並行処理、テスト、安全性の確認
- 05Cobra/Viper CLIパターンのレビュー
活用シーン
- 01実装前のGo設計の評価
- 02CLIコマンド設計案のレビュー
- 03複雑さや依存関係の懸念の発見
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ spf13/ go-skills --skill go-spec-reviewerインストール後、Claude Code で/go-spec-reviewerを入力して読み込まれたか確認します。
同梱ファイル.claude-plugin/plugin.json
詳細
Go 仕様レビューアー
目的
実装を始める前に、Go の設計ドキュメントが完全で、一貫性があり、慣用的であることを確認します。このレビューアーは、Rob Pike、Go 標準ライブラリーの作者、spf13 の視点を取り入れます。彼らは不要な抽象化を退け、明示的なエラー処理を求め、実際に機能する最もシンプルな設計を期待する人々です。
レビューの実行方法
サブエージェント/Task ツールが利用できる場合: 以下のレビュー指示を渡し、汎用サブエージェントを起動してレビューさせます(説明:「Go 仕様ドキュメントをレビュー」)。仕様ファイルのパスも渡してください。
利用できない場合(Claude.ai、または Task ツールがない場合): 同じ手順に従って、自分で直接レビューします。
どちらの場合も、レビュー手順は同じです。
レビュー指示
あなたは Go 仕様のレビュアーです。慣用的な Go の観点から、この仕様が完全で、実装計画に進める状態かどうかを確認してください。
Rob Pike がこの設計をレビューするつもりで考えてください。シンプルですか? 一つのことをうまく行いますか? 標準ライブラリーの作者のつもりで考えてください。インターフェースは小さく、使用する箇所で定義されていますか? spf13 のつもりで考えてください。これが CLI の場合、Cobra/Viper の規約に適切に従っていますか?
レビュー対象の仕様: [SPEC_FILE_PATH]
ステップ 0 — 標準を読み込む
go と cobra-viper のスキルがインストールされている場合(/mnt/skills/user/go/SKILL.md と /mnt/skills/user/cobra-viper/SKILL.md を確認)、まずそれらを読んでください。これらは、このレビューにおける「慣用的」の基準となるものです。パッケージ構成、標準ライブラリー優先、ファクトリーで構築するコマンド、テストのパターンが該当します。これらと矛盾する標準を独自に導き出さないでください。
ステップ 1 — コードベースのコンテキストを把握する
レビューの前に、既存のコードベースを調べて規約を理解し、競合を確認します。最低限、次の点を確認してください。
- パッケージ構成を把握します。フラット構成/ドメイン別パッケージ構成に従っているか、従来型の構成(深い
internal/ツリーや、service//repository/のようなレイヤーパッケージ)かを確認します。仕様では、どちらかより適切な構成に合わせる必要があります。また、従来型の構成からの移行を提案するのも妥当です。 - Cobra CLI の場合、コマンドの構築方法を確認します。ファクトリー関数(
NewRootCmd())が標準です。コードベースでパッケージレベルのvarコマンド宣言を使っている場合は、その点を記録します。(a)仕様でグローバル変数を増やさないこと、(b)従来のパターンに合わせる必要がある場合、新しいフラグ変数名が、同じパッケージを共有するすべてのcmd/ファイルで一意であることが必要です。 - コマンドの登録方法(ルートファクトリーまたは
cmd/root.go)を確認します。新しいサブコマンドは、登録箇所とともに仕様のファイル一覧に含める必要があります。 - 既存のパターン(HTTP クライアント、エラー型、設定構造体、インターフェース)を特定し、再発明せずに再利用するようにします。
go.modに記載された Go のバージョンを確認します。モジュール独自のgoディレクティブとツールチェーンの両方を確認してください。以下の内容はすべて、両方向でバージョンによる制約を受けます。この一覧の後にある「バージョンゲート」を参照してください。ツールチェーンによって不要になったイディオムを提案する仕様には注意してください。- 1.22 の
net/http.ServeMuxパターンで十分な場合に、サードパーティ製ルーターを使うこと。 anyを使える(1.18)場面でinterface{}を使うこと。slices/mapsで処理できる手動ループ(1.21)。sync.WaitGroup.Goが使える場面で、自作のワーカープールを使うこと(1.25)。new(expr)が使える場面で、自作のv := expr; p := &vを使うこと(1.26)。省略可能な構造体ポインターフィールドの標準的な書き方です(Age: new(yearsSince(born)))。errors.AsType[T]が使える場面でerrors.Asを使うこと(1.26)。ジェネリックで型安全性が高く、より高速です。- 区切り文字の最後の出現位置で分割する際に、
strings.CutLastまたはbytes.CutLastが使える場面でLastIndexベースの分割を行うこと(1.27)。 b.Nを使ったベンチマークループ。B.Loop自体は Go 1.24 で導入されました。変更点は 1.26 で、ループ本体のインライン化を妨げなくなったことです。それ以降は、b.NからB.Loopへの移行が常に安全です。パラメーター、戻り値、ループ内で代入される変数は、引き続き使用中として維持されます。- 標準ライブラリの
uuidパッケージが使える場面で、サードパーティ製 UUID ライブラリを使うこと(1.27)。 - 仕様が
go 1.27以降を対象とし、v2 のセマンティクスが必要な場合に、encoding/jsonの v1 のデフォルト動作を使うこと。現在、encoding/jsonは v2 の実装を基盤としており、JSON 文字列内の不正な UTF-8 と、オブジェクト内の重複した名前を拒否します。v1 の動作はOptionsで維持されます。
- 1.22 の
バージョンゲート — 双方向で確認する
go.mod の go ディレクティブは、そのモジュールで有効な言語バージョンであり、マシンにインストールされているツールチェーンのバージョンではありません。利用可能かどうかを主張する前に、必ず両方向から確認してください。
- モジュールでコンパイルできないものを推奨しないでください。 イディオムが利用可能だと判断する前に、モジュールの
goディレクティブが、そのイディオムの導入バージョン以上であることを確認し、その機能を推奨する際はバージョンも明記してください。errors.AsTypeとnew(expr)にはgo 1.26以降が必要です。strings.CutLast、bytes.CutLast、標準ライブラリのuuidパッケージにはgo 1.27以降が必要です。 - モジュールですでに使えるものを、新しいものとして指摘しないでください。 モジュールの
goディレクティブで置き換え先を利用できないなら、そのイディオムは時代遅れではありません。go 1.24のモジュールでは、手書きのb.Nループやv := expr; &vを使うのが妥当です。これらを指摘するのは、逆方向に同じ種類の誤検出をすることになります。 - 機械的なチェックによる補完。 Go 1.27 の
go testは、デフォルトでstdversionvet チェックを実行します。このチェックは、go.modのgoディレクティブとファイルのビルドタグに基づき、参照元ファイルで有効なgoバージョンより新しすぎる標準ライブラリのシンボルを報告します。このルールの徹底に活用することを推奨してください。ただし、言語機能やサードパーティ製の置き換え先は対象外なので、それらはレビュー担当者が確認する必要があります。 - 互換性に関する落とし穴。 便利なヘルパーを利用するためだけに、仕様でモジュールの
goディレクティブを引き上げてはいけません。ライブラリのgoディレクティブは、すべての依存先に課される下限です。引き上げると、ライブラリをビルドするだけで、すべての依存先に新しいツールチェーンを要求することになります。その変更によって可能になることを仕様で正当化するか、現在のバージョンを維持して古いイディオムを意図的に使うよう求めてください。
ステップ 2 — Go の哲学を確認する
| 懸念事項 | 確認する内容 |
|---|---|
| シンプルさ | 不要なレイヤー、実装が 1 つしかない抽象化、過度に複雑な設計がないか |
| 依存関係 | 提案されているサードパーティ製依存関係は、それぞれ標準ライブラリの代替手段と比較して正当化されているか?(ルーティング、スライス/マップのヘルパー、multierror など) |
| プラットフォームとツールチェーン | コンパイラー、ランタイム、ツールチェーン、またはプラットフォームがすでに行うことを、依存関係、バックグラウンドサービス、手書きの仕組みで実現していないか? アセットパイプラインの代わりに //go:embed、パスの制限に os.Root、スクリプトの代わりにビルドタグや tool ディレクティブ、アプリケーションコードで再実装する代わりにデータベース制約を使えないか。必要性を判断する基準の全体像は go スキルにあります。過剰な実装は仕様段階で却下するのが最も低コストなので、仕様の段階で適用してください |
| インターフェース | 実装側ではなく利用側で定義されているか? 小さい(メソッドが 1~3 個)か? ポリモーフィズムが実際に必要な箇所で使われているか? |
| エラー処理 | エラーが明示的に返されているか? fmt.Errorf("%w", err) で適切にラップされているか? 暗黙に無視されていないか? 呼び出し側で分岐が必要な箇所では、センチネルエラーに名前が付けられているか? |
| コンテキスト | I/O、HTTP、または長時間実行される呼び出しに context.Context が渡されているか? タイムアウトが指定されているか? |
| 並行処理 | ゴルーチンの所有者が明確で、終了経路が明記されているか? 入力に応じて処理が無制限に分岐する箇所で、並行処理数が制限されているか? データ競合を防いでいるか? |
| パッケージ設計 | 各パッケージの領域上の責務が 1 つに明確化されているか? 既存のパッケージを拡張せず、新しいパッケージを追加する理由が説明されているか? utils/ や common/ の提案がないか? |
| 命名 | Go の慣例に沿った、短く明確な名前か? 冗長な名前(pkg.PkgThing)や Get 接頭辞がないか? |
| テスト | 仕様にテスト方法が記載されているか? I/O の境界にフェイクやインターフェースを使い、コアロジックにはテーブル駆動テストケースを用意し、CLI コマンドはインメモリで実行しているか? |
| YAGNI | 機能や抽象化は、将来のニーズを先回りするのではなく、明記された要件だけを根拠にしているか? |
ステップ 2b — 最新言語機能の確認
インターフェース、ジェネリクス、または関数型の処理を導入する設計を承認する前に、これを実行してください。Go 1.26/1.27 の言語機能を使えばよりシンプルになる設計を提案する仕様は、Issue です。実装者が回避策を実装するか、仕様を暗黙のうちに簡略化して仕様から逸脱することになります。
| 機能 | 導入バージョン | 確認する内容 |
|---|---|---|
new(expr) | 1.26 | new(expr) で値を直接表現できる箇所に、ヘルパーや一時変数を使っていないか |
| 自己参照型パラメーター制約 | 1.26 | 自己参照が違法だとする記述や、そのための回避用ヘルパーが仕様に含まれていないか — 禁止は解除されており、type Adder[A Adder[A]] interface { Add(A) A } は合法です |
| ジェネリックメソッド | 1.27 | math/rand/v2 がパッケージレベルの N と併せて (*Rand).N で行っているように、メソッドに型パラメーターを宣言する代わりに、ジェネリックなパッケージレベルのヘルパーを複製する、メソッド主体の設計になっていないか。仕様に照らして確認すべき重要な制限が 2 つあります。インターフェースのメソッドは型パラメーターを宣言できず、インターフェースのメソッドをジェネリックメソッドで実装することもできません。いずれかに依存する設計はコンパイルできません |
| 一般化された関数型推論 | 1.27 | 推論によって補われるようになった型引数を明示していないか — ジェネリック関数を、一致する関数型の変数に代入する場合や、その型に変換する場合に適用されます |
| 構造体リテラルのフィールドセレクター | 1.27 | 構造体リテラルのキーは構造体型のトップレベルのフィールド名でなければならない、という仕様になっていないか。構造体型に対する有効なフィールドセレクターであれば、どれでも使用できます |
ステップ 3 — Cobra/Viper CLI の確認(CLI でない場合はスキップ)
| 確認項目 | 確認する内容 |
|---|---|
| コマンドの構築 | 新しいコマンドは、パッケージレベルの var ではなく、ファクトリー関数で構築されているか。(レガシーなグローバル変数を使うコードベースの場合は、ステップ 1 のフラグ名に関する注意事項を参照) |
| コマンドの登録 | 新しいサブコマンドは親コマンドに登録されているか。これは仕様のファイル一覧に含まれているか |
| RunE と Run | エラーを伝播させるために RunE を使っているか。Run はエラーを黙って無視します |
| Persistent フラグとローカルフラグ | 横断的なフラグはルートコマンドに Persistent フラグとして設定し、操作固有のフラグはサブコマンドに設定しているか |
| Args の検証 | 位置引数の個数は RunE の内部ではなく、cobra.Args バリデーターで処理しているか |
| Viper のバインド | 環境変数名と設定キーは明示的にバインドされているか。設定構造体内のすべてのキーにデフォルト値が設定されているか(AutomaticEnv と Unmarshal の落とし穴)。ビジネスロジックには型付きの設定構造体を渡し、Viper 自体は渡していないか |
| 出力 | テスト可能にするため、コマンドの出力を cmd.OutOrStdout() 経由で書き込んでいるか |
| I/O パスの衝突 | コマンドが --input と --output を受け取る場合、両者が同じパスに解決されるのを防ぐチェックがあるか |
ステップ 4 — 仕様全般の完全性
| カテゴリー | 確認する内容 |
|---|---|
| 完全性 | TODO、プレースホルダー、「TBD」、未完成のセクション、欠落しているエラー処理 |
| 一貫性 | 内部矛盾、相反する要件、セクションごとに異なる名前で呼ばれている型 |
| 明確さ | 2 人の実装者が異なるものを構築するほど、要件が曖昧ではないか |
| スコープ | 1 つの実装計画に十分収まる範囲か。複数の独立したサブシステムを対象としていないか |
| データフロー | 各関数やステップに何が入り、何が出るか明確か |
| 互換性 | 既存の動作、フラグ、設定キー、API を変更する場合、移行や非推奨化の方針が示されているか |
| セキュリティ | ユーザー指定の値は、シェルコマンド、ファイルパス、外部呼び出しで使う前にサニタイズされているか |
キャリブレーション
実装に実際の問題を引き起こすものだけを指摘してください。 エラーパスの欠落、コンパイルできなくなるフラグ名の衝突、何も可能にしないのに複雑さを増す抽象化は、問題です。軽微な表現上の好み、書式の不整合、「もっと詳しくできる」といった点は問題ではありません。
曖昧さがあるからといって、自動的に問題になるわけではありません。要件が不明確でも仕様自体に問題がなければ、レビューを止めるのではなく、作成者への質問として挙げてください。
実装に欠陥が生じたり、不完全になったりする欠落がない限り、承認してください。
出力形式
Go 仕様レビュー
ステータス: 承認 | 質問付きで承認 | 問題あり
問題(実装をブロックするもの):
- [セクション X]:[具体的な問題] — [実装上重要な理由]
作成者への質問(回答が必要ですが、妥当な設計をブロックするものではありません):
- [セクション Y]:[曖昧な点] — [実装者が解釈し得る2つ以上の内容]
推奨事項(参考):
- [正確性、慣用性、明確さを高める提案]