私の役割
オーケストレーターが新機能を作成する(既存のものを変更するのではなく)際に、再利用性、設定、互換性を事前に分析して導きます。リファクタリングとは異なり、ここでは保存すべき既存コードはありません。設計はユーザーの要件から始まります。
このスキルを使用するタイミング(refactor-protocol の代わりに):
- ユーザーが存在しないエンドポイント、サービス、ジョブ、ハンドラー、イベント、または設定を要求した場合
- タスクが純粋な作成であり、既存の動作の変更ではない場合
- 結果としてリポジトリにファイルが追加され、既存のファイルのシグネチャは変更されない場合
このスキルを使用しないタイミング(代わりに refactor-protocol を使用):
- 既存のサービスのシグネチャを変更する場合
- 既存のエンドポイントの動作を変更する場合
- コードの名前変更、抽出、移動を行う場合
フェーズ 0 — 構造検証(常に最初)
project-structureスキルをロードし、完全な検証を実行する- ホストタイプを検出する:
FUNCTIONS|WEBAPP|NUGET_LIBRARY - 結果に応じて行動する:
| 状態 | アクション |
|---|---|
HARD_BLOCK | 停止。ユーザーに通知する。 |
NUGET_LIBRARY | HTTP エンドポイントの作成は予期しないものです。確認する: 「ライブラリに公開操作を追加しますか、それとも実際には検出できなかったホストがありますか?」 |
PREGUNTA | 続行する前に質問を解決する |
OK / WARNING | フェーズ 1 に進む |
フェーズ 1 — 要件収集
オーケストレーターはユーザーの説明($ARGUMENTS)から推測できるものは推測し、明確でないことだけを質問します。説明に既に含まれている答えを質問しないでください。
1.1 名前、目的、機能のタイプ
- HTTP エンドポイント(Function/Controller):
[VERB] /パス — 説明 - ドメインサービス: サービス名と責任
- ジョブ/イベントハンドラー: トリガー + アクション
- 設定オプション: オプション名とその目的
1.2 READ vs MUTATION の分類
機能が状態を変更するか、読み取り専用かを判断します。これは以下に影響します:
- レスポンス DTO の配置場所
- トランザクション/冪等性が必要かどうか
- 必要なテストの種類
| タイプ | 特性 | 影響 |
|---|---|---|
| READ-ONLY | GET、既存データを返す、書き込みなし | 一時的な DTO、最小限のテスト |
| MUTATION | POST/PUT/DELETE、状態を書き込むか変更する | 成功テスト + エラーテストが必要 |
1.3 期待される入力/出力の収集
- リクエスト: ボディまたはクエリパラメータの構造
- レスポンス: レスポンスボディの構造、ステータスコード
- エラー: どのエラーをどのステータスコードにマッピングするか
フェーズ 1.5 — 再利用分析(重要、スキップ不可)
目的: 何かを作成する前に、機能が部分的または完全に既に存在するかどうかを検出する。
手順
- 既存のサービスを検索
*.Impl/内を@exploreで機能のドメインを使用して検索 - 候補メソッドを検索 必要な動作の 80% 以上をカバーするもの:
- 単純なフィルタで必要なデータを既に返すメソッドはあるか?
- オーバーロードしてユースケースを追加できるメソッドはあるか?
- 類似のエンドポイントを検索
*.API/内で同じリクエスト/レスポンス形式のもの
決定木
ケースを 100% カバーするメソッドが存在するか?
├── はい → 新しいメソッドを作成しない。以下のみ作成:
│ ・ *.API/ 内のエンドポイント (Function/Controller)
│ ・ *.API/ 内の専用の Request/Response DTO
│ ・ レスポンスの形状のテスト
│
ほぼ適切なメソッドが存在するか (フィルタ、ページネーション、順序)?
├── はい → 以下を検討:
│ ├── 既存のメソッドにオプションパラメータを追加 (デフォルト値付き)
│ ├── より具体的なシグネチャを持つオーバーロードを作成
│ └── 既存のメソッドをラップする拡張メソッドを作成
└── いいえ → 新しいメソッドの作成に進む
関連するが異なるサービスが存在するか (例: 同様の責任)?
├── はい → ユーザーに確認: 「[CSXxxService] を拡張しますか、それとも新しい [CSYyyService] を作成しますか?」
└── いいえ → 新しいサービスを作成
このフェーズの期待される出力
以下の 3 つの決定のうちの 1 つを続行する前にユーザーに提示します:
- 純粋な再利用: 機能は既存のメソッドのラッパーとして実装される
- 拡張: 既存のサービスにオーバーロード/メソッドを追加する
- 新規作成: 新しいサービスとメソッド (なぜ再利用できないのかを正当化する)
フェーズ 1.6 — 設定分析 (新規)
目的: 機能に設定可能なパラメータが必要かどうかを検出し、必要な場合はどこで定義するかを決定する。
重要な質問
- 機能に外部設定なしでも妥当なデフォルト値はあるか?
- 環境ごとに設定可能にするべきしきい値、ページネーション、タイムアウト、フラグはあるか?
- URL/キー/シークレットを持つ外部システムに接続するか?
- 段階的なロールアウトのために機能フラグが必要か?
決定木
機能に設定が必要か?
├── いいえ → IXxxOptions を作成しない、AddCustomConfiguration を触らない
└── はい → 続行
どのようなタイプの設定か?
├── 接続文字列またはシークレット
│ └── appsettings.json の名前で IConfiguration を使用 (AddCustomConfiguration が管理)
├── 単一の値 (しきい値、タイムアウト、フラグ)
│ └── *.Impl/ に IXxxOptions (インターフェース)を作成 + AddCustomConfiguration<T>("キー") に追加
└── 値のリスト (許可されたオリジン、マッピング)
└── IEnumerable<T> タイプのプロパティを持つ IXxxOptions を作成
プロジェクトの慣例
プロジェクトは IoCExtensions.cs 内で AddCustomConfiguration<IXxxOptions>("config-section") を使用します(現在のプロジェクトの 43-45 行目)。インターフェースは *.Impl/ にあり、*.Impl/Services/ から参照されます。
期待される出力
機能に設定が必要な場合、ユーザーに以下を提示:
- インターフェース名 (例:
IPendingPaymentOptions) - デフォルト値を持つプロパティとその型
appsettings.jsonのセクション (例:"RAMBLA.PendingPayment")IoCExtensions.AddCSLevelBooking()の変更
必要ない場合は、計画に明示的にその旨を記載する。
フェーズ 1.7 — 公開 API への影響分析
目的: 既存のコンシューマーを壊さないようにする。
機能が既存のメソッドを再利用する場合
- メソッドは同じシグネチャを維持するか?→ 影響なし
- オプションパラメータが追加されるか?→ どの呼び出しサイトも壊れないことを確認
- オーバーロードが追加されるか?→ コンパイラがあいまいさなく解決することを確認
- 名前が変更されるか?→
grepですべての呼び出しサイトを検索して移行
機能が新しいサービスを追加する場合
- サービスは DI に登録されるか?→
IoCExtensionsでの登録を確認 - 既存のサービスに循環依存の可能性があるか?→ 確認
機能が新しいエンドポイントを追加する場合
- パスが既存のルートと衝突するか?→ 確認
- HTTP メソッドは REST と整合しているか?(GET は読み取り、POST は変更)
フェーズ 1.8 — 回帰テストの事前確認 (必須)
目的: 新しいコードを生成したり既存のコードを変更したりする前に、影響を受ける(たとえ間接的であっても)コンポーネントにテストカバレッジがあることを確認する。カバレッジがない場合は、実装を開始する前にテストを作成して実行する。
手順
-
間接的な影響範囲を特定: フェーズ 1.5 (再利用 vs 拡張 vs 新規) に基づいて、以下をリストアップ:
- メソッドを拡張またはオーバーロードする既存のサービス
- 変更する既存のインターフェース
- ルーティング/DI によって影響を受ける可能性のある既存のエンドポイント
- 編集する(作成しない)既存のファイル
-
変更する各既存コンポーネントについて:
src/*.Test*/**でそれをテストするテストを検索- カバレッジがあれば → OK、続行
- カバレッジがない場合 → HARD BLOCK:
@refactor-worker-testsを呼び出して、現在の動作の特性テストを作成@refactor-verifierを呼び出して、テストが成功することを確認- 個別のコミット:
test(characterization): <クラス名> の特性テストを追加
-
機能が 100% 新規作成の場合 (既存のファイルに触れない):
- 回帰の対象となる範囲はない → 事前確認をスキップ
- ただし、新しい機能のテストはフェーズ 4 で作成され、フェーズ 5 で成功する必要がある
終了基準 (フェーズ 5)
機能を正しいとみなすには、@refactor-verifier が以下が成功することを確認する必要がある:
- 新しい機能のテスト (サービス + エンドポイント)
- 間接的な影響範囲の既存のテスト (回帰)
いずれかが失敗した場合、機能は完了できません。
フェーズ 2 — 決定木: 何をどこに作成するか
フェーズ 1.5 (再利用/拡張/新規) とフェーズ 1.6 (設定) の決定を適用する。
再利用による READ-ONLY エンドポイントの場合
*.API/
+ {名前}Function.cs — 新しい Function/Controller
+ {名前}Request.cs — プレゼンテーション専用
+ {名前}Response.cs — プレゼンテーション専用
*.Test*/
+ {名前}FunctionTests.cs — レスポンスの形状のテスト (ロジックなし)
新しいサービスによる MUTATION エンドポイントの場合
*.Contracts/
+ ICS{名前}Service.cs — サービスのインターフェース
+ {名前}Request.cs — Request が共有の場合
+ {名前}Response.cs — Response が共有の場合
*.Impl/
+ CS{名前}Service.cs — 実装
+ I{名前}Options.cs — フェーズ 1.6 で設定が検出された場合のみ
*.API/
+ {名前}Function.cs — Function/Controller
+ {名前}Request.cs — 専用 (Contracts に配置されなかった場合)
+ {名前}Response.cs — 専用 (Contracts に配置されなかった場合)
*.Test*/
+ CS{名前}ServiceTests.cs — ハッピーパス + 少なくとも 1 つのエラー
既存のサービスの拡張の場合
*.Contracts/
~ ICS{名前}Service.cs — メソッドのシグネチャを追加 (またはオーバーロードを作成)
*.Impl/
~ CS{名前}Service.cs — 新しいメソッド/オーバーロードを実装
*.API/
+ {名前}Function.cs — 新しい Function/Controller
+ {名前}Request.cs — 専用の場合
+ {名前}Response.cs — 専用の場合
*.Test*/
+ (または ~) サービスのテスト — 新しいメソッドのテストケースを追加
フェーズ 3 — 作成計画
ワーカーを呼び出す前に、オーケストレーターはこの計画をユーザーに提示し、明示的な確認を待つ:
[作成計画] 機能: <名前> — <簡単な説明>
ホスト: <FUNCTIONS | WEBAPP>
分類: <READ-ONLY | MUTATION>
戦略: <再利用 | 拡張 | 新規>
再利用分析 (フェーズ 1.5):
· 候補サービス: <ICSXxxService> または "なし"
· 候補メソッド: <XxxService.YyyMethod> または "なし"
· 決定: <再利用 | 拡張 | 新規>
設定分析 (フェーズ 1.6):
· 設定が必要: <はい | いいえ>
· 必要な場合: <IXxxOptions + appsettings セクション>
公開 API への影響 (フェーズ 1.7):
· 影響を受ける呼び出しサイト: <リスト> または "なし"
· 破壊的変更: <はい | いいえ>
作成する成果物:
*.Contracts/ ([N] ファイル):
+ ICS{名前}Service.cs — 新しいインターフェース (または: メソッドを IXxx に追加)
+ {名前}Request.cs — 共有タイプの場合
+ {名前}Response.cs — 共有タイプの場合
*.Impl/ ([N] ファイル):
+ CS{名前}Service.cs — サービスの実装
+ I{名前}Options.cs — 設定が必要な場合のみ (フェーズ 1.6)
*.API/ ([N] ファイル):
+ {名前}Function.cs — Azure Function (または: {名前}Controller.cs)
+ {名前}Request.cs — 専用タイプの場合
+ {名前}Response.cs — 専用タイプの場合
*.Test*/ ([N] ファイル):
+ CS{名前}ServiceTests.cs — サービステスト (ハッピーパス + エラー)
+ {名前}FunctionTests.cs — エンドポイントテスト (該当する場合)
既存ファイルの変更:
~ src/.../IoCExtensions.cs — サービスとオプションを登録 (該当する場合)
実行順序: Contracts → Impl → Presentation → Tests
続行しますか?
ユーザーの明示的な承認なしに、ワーカーを呼び出さないこと。
フェーズ 4 — 実行
ワーカーの順序
@refactor-worker-contracts—*.Contracts/に新しい型またはシグネチャがある場合のみ@refactor-worker-impl—*.Impl/にコードがある場合常に@refactor-worker-presentation— エンドポイントがある場合常に@refactor-worker-tests— 常に最後
注: 機能が新しい Service Gateway を公開する場合を除き、
@refactor-worker-crosscuttingは呼び出されません。これは作成時には稀なケースであり、通常はリファクタリング時に行われます。
各ワーカーへの指示
プロンプトに以下を含める:
- 完全な計画 (フェーズ 3)
- プロジェクトのパターン: 作成する前に類似のファイルを読むこと
- 期待される内容を含む正確なファイルリスト
- フェーズ 1.6 で設定が検出された場合:
IXxxOptionsのパスと設定セクション
フェーズ 5 — 検証とコミット
@refactor-verifierを呼び出す- PASS の場合 → コミットを提案 (形式):
feat(<スコープ>): <短い名前> 機能を追加 - ICS{名前}Service インターフェースと CS{名前}Service 実装を追加 - {VERB} /{パス} Function/Controller を追加 - {名前}Request/{名前}Response コントラクトを追加 - 新しい設定用の I{名前}Options を追加 (該当する場合) - CS{名前}Service の単体テストを追加 - FAIL の場合 → 失敗したレイヤーを特定し、ワーカーを再呼び出し、再検証する
ホスト別パターン
FUNCTIONS — Azure Functions Isolated Worker
Function を作成する前に、既存の HTTP Function を読み、そのスタイルをコピーすること。典型的な例:
public class {名前}Function
{
private readonly I{名前}Service _{フィールド};
public {名前}Function(I{名前}Service {フィールド}) => _{フィールド} = {フィールド};
[Function("{名前}Function")]
public async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "{パス}")] HttpRequestData req)
{
var request = await req.ReadFromJsonAsync<{名前}Request>();
var result = await _{フィールド}.ExecuteAsync(request);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(result);
return response;
}
}
作成前に確認:
AuthorizationLevel.FunctionまたはAuthorizationLevel.Anonymous?- 適切なルートテンプレート
- 適切な HTTP メソッド (GET, POST, PUT, DELETE)
- エラーハンドリング (try-catch またはミドルウェア)