codeprobe-patterns について
具体的な設計上の問題を解決するパターン候補と、複雑さを増すだけの誤用を見つけるcodeprobeのサブスキルです。パターンを無条件に推奨せず、根拠のあるコードレビューに向いています。
主な機能
- 01根拠のあるパターン候補を検出
- 02パターンの誤用を検出
- 03他のcodeprobeスキルとの重複を回避
- 04複雑さとコードの文脈を考慮
活用シーン
- 01複雑なオブジェクト構築の評価
- 02条件分岐による重複生成のレビュー
- 03メソッド間で繰り返す横断的処理の発見
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ machineroom-dev/ codeprobe --skill codeprobe-patternsインストール後、Claude Code で/codeprobe-patternsを入力して読み込まれたか確認します。
詳細
スタンドアロンモード
オーケストレーター経由ではなく直接呼び出された場合、まず次のことを行う必要があります。
- 出力仕様、実行モード、制約を確認するため、
../codeprobe/shared-preamble.mdを読み込みます(ユーザーのプロジェクトではなく、この SKILL.md の場所を基準に、兄弟ディレクトリのcodeprobeスキルディレクトリを参照します)。 - プロジェクトの技術スタックに応じて、
../codeprobe/references/から該当するリファレンスファイルを読み込みます(同じ場所を基準に参照します)。 - ユーザーから別の指定がない限り、
fullモードをデフォルトにします。
デザインパターンアドバイザー
対象領域
パターンを使うこと自体を目的として、パターンを決して推奨しないでください。パターンで解決できる具体的な問題がコードに存在する場合に限り、パターンを適用できる箇所を指摘してください。パターンを使わなくてもコードが機能し、読みやすく、保守しやすい場合は、パターンを提案しないでください。
このサブスキルでは、次の2種類のデザインパターンに関する問題を検出します。
- パターンを適用できる箇所 — コード内で確認できる問題(複雑さ、重複、柔軟性の欠如、隠れた依存関係)を、特定の GoF パターンまたはアーキテクチャパターンで解決できる箇所。
- アンチパターン — 測定可能なメリットをもたらさずに、複雑さ、間接化、または抽象化レイヤーを増やす、誤って適用されたパターン。
検出しないもの
-
型やステータスに応じた
switch文は、すでにcodeprobe-solid(OCP-xxx)で検出されています。 このサブスキルでは、現在の実装に対する具体的なメリットとともに、特定の名前付きパターン(例:Strategy、State)を推奨できる場合に限り検出します。パターン名を挙げずに「ここでパターンを検討してください」といった一般的な指摘になる場合は、SOLID 監査に委ねてください。指摘の重複を避けるため、同じswitch/if-elseブロックが OCP 違反としてすでに検出されるか確認してください。codeprobe-solidが検出し、推奨内容が単に「ポリモーフィズムを使う」だけであれば、指摘を出さないでください。 判断基準: パターン名を挙げ、インターフェースを示し、具体的な実装を列挙できる場合は、PATTERN-の指摘を出してください。「これは OCP に違反しています」としか言えない場合は、codeprobe-solidに委ねてください。 -
God クラスは、すでに
codeprobe-architecture(ARCH-xxx)で検出されています。 このサブスキルでは、特定のパターン(例:Facade、Mediator)が推奨される分割方法となる場合に限り検出します。推奨内容が単に「このクラスを分割する」だけであれば、アーキテクチャ監査に委ねてください。一般的な分割よりも特定のパターンが適している理由を説明し、正確なパターン名を挙げられる場合にのみ、指摘を出してください。 判断基準: 修正案が「これらのメソッドを持つ Facade に切り出す」であれば、PATTERN-の指摘を出してください。「これをより小さなクラスに分割する」であれば、codeprobe-architectureに委ねてください。 -
codeprobe-code-smells(SMELL-xxx)で検出される横断的関心事。 ロギング、キャッシュ、認可のコード重複は、すでにコードの重複として検出されている可能性があります。解決策として特定のパターン(Decorator、Middleware)を推奨する場合に限り、PATTERN-の指摘を出してください。主な問題が重複であれば、コードスメル監査に委ねてください。 -
パターンを適用すると過剰設計になるような、単純なスクリプトや小規模なアプリケーション。50 行の CLI スクリプトに Strategy パターンは不要です。単一ファイルのユーティリティに Factory は不要です。複雑さを管理するためのツールとしてパターンを使い、パターンそのものを目的にしないよう、適切な設計判断をしてください。
-
すでにパターンを正しく実装しているコード。正しいパターンを別の正しいパターンに置き換える提案はしないでください。Factory が適切に機能しているなら、具体的な問題がない限り Builder への切り替えを提案しないでください。クラスが Observer を正しく使っているなら、Mediator への切り替えを提案しないでください。
-
テストファイル — テスト用のユーティリティやヘルパーには、異なる設計上の制約があります。テストのセットアップクラス、フィクスチャビルダー、モックファクトリーには、本番コードと同じパターンの要件は適用されません。テストダブル、テストデータビルダー、テストのオーケストレーション用ヘルパーは検出対象にしないでください。
-
確信度の低いパターンの該当(例:Prototype パターン)。ただし、複製動作を示す強い証拠がある場合を除きます。出す場合でも、重要度は Suggestion までにしてください。判断に迷う場合は、指摘を出さないでください。
検出手順
パターンの適用候補
| 観察された問題 | 候補となるパターン | 検出方法 | 確信度 | 深刻度 |
|---|---|---|---|---|
| 4 つ以上の任意パラメーターを使った複雑なオブジェクトの構築 | Builder | 4 つ以上の任意/nullable パラメーターを持つコンストラクターまたはファクトリーメソッドを確認します。セッターを使って段階的にオブジェクトを構築し、その後 build() を呼び出すメソッドは、より明確になる可能性があります。 | 高 | 軽微 |
コードベース内のあちこちで条件分岐を伴う new X() が重複している | Factory | 同じクラス群のインスタンスを生成する new ClassName() が 3 か所以上にあり、生成するクラスを決定するための if/switch ロジックが周辺にあるか検索します。 | 高 | 重大 |
| 特定のパターンが適用される場合に、型によって動作を選択する switch | Strategy | 各分岐が値を返すだけでなく、異なるアルゴリズムまたは動作を実行する switch/if-else チェーンです。分岐が 3 つ以上あり、バリエーションが増える可能性が高い場合に限ります。OCP に関する指摘で既に扱われている場合は報告しません。 | 高 | 重大 |
| 内部状態フィールドに応じてオブジェクトの動作が変わる | State | $this->status または this.state に対する if/switch を含むメソッドがあり、同じフィールドが 3 つ以上のメソッドの動作を制御しているクラスを確認します。状態遷移がクラス内のあちこちに散在しています。 | 中 | 軽微 |
| 複数のリスナーが変更に反応する必要がある | Observer / Event Dispatcher | 状態変更後に 3 つ以上のサービス/ハンドラーを直接呼び出すメソッドを確認します(例:注文の作成後にメール送信、在庫更新、倉庫への通知、監査ログの記録を行う)。イベントを使うべきです。 | 高 | 軽微 |
| 横断的なロジックがビジネスロジックに混在している | Decorator / Middleware | ログ記録、キャッシュ、認可、処理時間の計測コードがビジネスロジックのメソッドに混在している状態です。同じ横断的関心事が 3 つ以上のメソッドにコピー&ペーストされています。 | 高 | 重大 |
| 複雑なサブシステムを包み込む God クラス | Facade | 複数のサブシステムを調整する大規模なクラス(300 行以上)です。クライアントには簡素化されたインターフェースだけが必要です。probe-architecture が God オブジェクトとして既に報告している場合は報告しません。 | 中 | 軽微 |
| Undo/redo またはコマンドキューが必要 | Command | 現在はインラインで実行している操作をキューに入れる、ログに記録する、または元に戻す必要があるコードです。 | 中 | 提案 |
| 条件付きの変換ステップを通じてデータが流れる | Pipeline / Chain of Responsibility | データが、各ステップを条件付きで適用する 3 つ以上の連続した if/else 変換ステップで処理されます。合成可能なステージからなるパイプラインにできる可能性があります。 | 中 | 軽微 |
| いくつかのフィールドだけが異なる、類似したオブジェクトが複数ある | Prototype | わずかな違いを付けたオブジェクトのコピーを作成する、ファクトリーに似たコードです。 | 低 | 提案 |
アンチパターン(誤って適用されたパターン)
| アンチパターン | 検出対象 | 検出方法 | 重大度 |
|---|---|---|---|
| 依存関係を隠すためのシングルトン | コンストラクター経由で注入すべき依存関係にアクセスするために、クラスが getInstance()、static::$instance、またはモジュールレベルのシングルトンを使用しています。シングルトンパターンは依存関係を隠し、テストを困難にします。 | ビジネスロジッククラス内で、getInstance()、static::$instance、self::$instance、モジュールレベルのシングルトンアクセスパターンを検索します。これらの依存関係を代わりにコンストラクター経由で注入できるか確認します。 | 重大 |
| パススルーリポジトリ | ORM(Eloquent、Doctrine、Prisma)をラップするリポジトリクラスで、すべてのメソッドが抽象化、キャッシュ、クエリロジックを一切追加せず、1 行の委譲のみを行います。このリポジトリは価値のないレイヤーを追加しています。 | リポジトリクラスを見つけ、各 public メソッドの本体を確認します。すべてのメソッドが追加ロジックなしに、基盤となる ORM モデルを 1 行で呼び出している場合、そのリポジトリはパススルーです。 | 軽微 |
| 名前を変えただけのコントローラーアクションであるサービスクラス | public メソッドが 1 つだけのサービスクラスで、そのメソッドがコントローラーアクションとまったく同じパラメーターとロジックを持ち、別のファイルに移しただけです。再利用性がないまま、間接層を追加しています。 | public メソッドが 1 つだけのサービスクラスを見つけます。そのメソッドのシグネチャとロジックが、対応するコントローラーアクションとよく似ているか確認します。コードベース内で再利用されていないこと(呼び出し元が 1 つだけ)も確認します。 | 軽微 |
| 1 つのファミリーしかない抽象ファクトリー | 具象ファクトリーの実装が 1 つだけで、2 つ目の実装が予定されていない抽象ファクトリーインターフェースです。過剰な抽象化です。 | 抽象ファクトリーのインターフェース/クラスを見つけ、具象実装の数を数えます。実装が 1 つだけで、将来的な拡張の予定を示す要素(TODO コメントや、今後のバリエーションに言及するドキュメント)がない場合、指摘対象とします。 | 提案 |
ID のプレフィックスと修正プロンプトの例
すべての指摘には PATTERN- のプレフィックスを付け、PATTERN-001、PATTERN-002 のように連番にします。
修正プロンプトの例
- 「
NotificationSenderの$typeに対するswitch(30〜65 行目)を Strategy パターンに置き換えてください。send(Message $message)メソッドを持つNotificationChannelインターフェースを作成します。EmailChannel、SmsChannel、PushChannelの各実装を作成します。NotificationChannelFactoryを使用して、タイプに応じた適切なチャネルを解決してください。」 - 「
ReportBuilderのコンストラクター(15 行目)は、7 つのオプションパラメーター($title、$subtitle、$dateRange、$format、$includeCharts、$paperSize、$orientation)を受け取ります。これを Builder パターンにリファクタリングしてください。流暢なセッターメソッドとbuild()メソッドを持つReportBuilderConfigを作成してください。」 - 「
app/Services/AuditLogger.phpのAuditLoggerは、シングルトンとしてAuditLogger::getInstance()(5 行目)を使用しています。コンストラクターインジェクションに置き換えてください。DI コンテナーにAuditLoggerをシングルトンバインディングとして登録し、現在::getInstance()を呼び出している 4 つのクラスに、コンストラクター経由で注入してください。」 - 「
app/Repositories/のUserRepositoryInterfaceとUserRepositoryラッパーを削除してください。すべてのメソッド(find、create、update、delete)が、ロジックを一切追加せず Eloquent に 1 行で委譲しています。抽象化が必要となる具体的な理由ができるまでは、Eloquent モデルを直接使用してください。」