mcpField
A
architecture-optimization

architecture-optimization

github.com/wondelai開発2.5k1.4k 回インストール7 週間前に更新
リポジトリ

architecture-optimization について

遅くなったり複雑化したりした稼働中のコードベースを対象に、8段階で進める対話型の最適化スキルです。動作をテストで固定し、基準値を測定してから構造変更や性能改善に進み、判断と成果物をプロジェクトの `docs/` に記録します。中断・再開にも対応します。

主な機能

  1. 018段階の最適化プロセス
  2. 02動作の固定と基準値測定を先行
  3. 03測定結果に基づくボトルネック対応
  4. 04判断を `docs/` に記録
  5. 05中断と再開に対応

活用シーン

  1. 01レガシーコードの安全なリファクタリング計画
  2. 02測定済みの性能ホットスポットの改善
  3. 03データ層やシステムアーキテクチャの点検
  4. 04性能・信頼性の継続的な予算設定

インストール

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

$npx skills add https://github.com/wondelai/skills --skill architecture-optimization

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

同梱ファイルreferences/artifact-templates.mdreferences/methods.md

詳細

アーキテクチャの最適化

稼働中のコードベースを、動作を壊すことなく、アーキテクチャ、コード品質、パフォーマンスの3つの軸で同時に最適化します。これは8つのフェーズからなる、対話形式で後から再開できる取り組みです。エージェントはすべての判断の前に確認し、その結果をプロジェクトの docs/ フォルダーに記録するため、どのフェーズの後でも中断して、後から再開できます。稼働して収益を上げているものの、遅く複雑になってきたシステムを対象としています。構造を整えるフェーズでは、安全かつ低コストでコードを変更できるようにし、パフォーマンスのフェーズでは測定可能な速度向上を実現し、最後のフェーズではその状態を維持します。

基本原則

最適化の前に測定し、構造変更の前に動作を固定する。判断を下すのは直感ではなく、プロファイラーとセーフティネットです。 早すぎる最適化が多くの問題の根源とされるのは、最適化が悪いからではありません。測定せずに最適化すると、コードのうち間違った97%を対象にしてしまうからです。また、動作を固定せずに構造を変更するのは改善ではなく、賭けです。このスキルはフェーズの順序を定め、判断に必要な質問を行い、すべての選択を docs/ に記録します。個々のスキルが手法を担うため、独自の枠組みを即興で作るのではなく、それらを呼び出してください。

取り組みの全体像

フェーズスキル答える質問成果物
1working-with-legacy-codeすべての変更を検証できるように、動作は固定され、パフォーマンスは測定されていますか?docs/PERFORMANCE.md + docs/TECH-DEBT.md を作成し、docs/TESTING.md を拡張 — ゲート
2clean-architectureコードが成長するにつれて境界がずれていませんか?依存関係は今も内側を向いていますか?docs/ARCHITECTURE.md を拡張
3software-design-philosophyモジュールは深くなっていますか?それとも、構造そのものが複雑さの原因になっていますか?docs/TECH-DEBT.md を拡張
4refactoring-patterns名前の付いた、動作を維持する手順で、ホットパスの形を変えられますか?docs/TECH-DEBT.md + docs/TESTING.md を拡張
5system-design測定した負荷から、ボトルネックと最も低コストな対策として何が分かりますか?docs/PERFORMANCE.md + docs/ARCHITECTURE.md を拡張
6ddia-systemsデータレイヤーがボトルネックですか?クエリ、インデックス、分離、派生データに問題がありますか?docs/ARCHITECTURE.md + docs/PERFORMANCE.md を拡張
7release-it依存関係の応答が遅いときや停止したときも、速さと安定性を保てますか?docs/RELIABILITY.md を作成または拡張
8pragmatic-programmer作業を終えた後も速く、クリーンな状態を保つために、どのような予算と習慣が必要ですか?docs/PERFORMANCE.md + docs/TECH-DEBT.md + docs/TESTING.md を拡張

運用ルール

  1. まず再開してください。 何よりも先に、docs/ARCHITECTURE-OPTIMIZATION-PLAN.md と Journey Map 内のすべての成果物を読んでください。トラッカーが存在する場合は、Journey の状態を3~5行で要約し、どのフェーズに進むかを尋ねてください。ユーザーが開始点を確認したら完了です。トラッカーがある Journey は再開し、決して最初からやり直しません。
  2. 初回実行時のみインテークを行います。 トラッカーがない場合は、以下のインテークを実行し、すべてのフェーズの状態を pending | in-progress | awaiting-evidence | done | deferred: reason | skipped: reason のいずれかにして、docs/ARCHITECTURE-OPTIMIZATION-PLAN.md を作成してください。トラッカーが存在し、ユーザーがフェーズ計画を確認したら完了です。
  3. フェーズへの着手。 フェーズで行うこと、決定が必要な事項、作成する成果物、おおよその作業量を伝えてください。続行/スキップ/延期の選択肢を提示します。GATE と記されたフェーズは延期できますが、スキップはできません。続行する場合は、フェーズの状態を in-progress にしてください。ユーザーが選択したら完了です。
  4. スキルの呼び出しと代替手段。 フェーズのスキルを読み込み、使用してください。各フェーズの Invoke 行にはスキルがスラッグで指定されています。そのスキルを使ってフェーズを実行してください。利用できない場合は、npx skills add wondelai/skills/<slug> --global を提示してください。ユーザーが断った場合は、Brief に基づいてフェーズを実行します。どの方法で進めるかを明示してください。
  5. フェーズ内の決定。 「ユーザーと決定する」の下にある質問をすべて、具体的な選択肢と推奨案を添えて尋ねてください。選択内容をトラッカーの Key Decisions に記録します。決定を黙って行うのは不備です。
  6. フェーズの終了。 書き込む前に、成果物の草案を提示して承認を得てください。承認後、docs/ ファイルを作成または追記し、トラッカーを更新してください(状態、Key Decisions、Next Actions)。ファイルが書き込まれ、フェーズの行が done になったら完了です。
  7. 成果物の扱い。 書き込む前に読み込んでください。ファイルがない場合にのみ作成し、すでにある場合は追記してください。ほかの人の内容は保持し、自分のセクションを追加または更新します。ファイル名は docs/ 内で大文字にしてください。推奨事項はすべて、担当者と優先度を含むチェックボックスまたは表の行に記載してください。docs/ ファイルを初めて作成する場合は、references/artifact-templates.md を参照してください。すべてのセクション見出しを含む完全なひな形から作成し、フェーズで指定されたセクションを記入します。
  8. 測定していないものを最適化せず、固定していないものを再構成しないでください。 測定済みのベースラインを改善する変更には、そのベースラインを明記し、変更前と変更後の値を PERFORMANCE.md の Optimization Ledger に記録してください。数値が改善しない変更は残さず、元に戻します。(タイムアウト、ブレーカー、バルクヘッド、ページネーション、CI ゲートなどのレジリエンスおよびゲーティング作業は、レイテンシの変化ではなく、それぞれのフェーズの完了条件で評価します。)構造変更の対象は Safety Net Map で固定されたコードに限り、動作を維持してください。また、構造変更は動作変更や最適化のコミットとは分け、構造変更のみのコミットにしてください。

インテーク

トラッカーを作成する前に、以下を確認します。

  1. システムは何を行い、「遅すぎる」ことでどのような損失が発生しますか — ユーザーの喪失、SLA 違反、インフラ費用などです。(どの指標が重要か、またこの取り組みにどれだけの労力をかける価値があるかを判断します。)
  2. 現時点でどのような根拠がありますか — APM トレース、低速クエリログ、p95 レイテンシ、クラウド料金、あるいは苦情だけですか。(フェーズ 1 のベースラインに反映します。苦情だけの場合は、まず計測を導入します。)
  3. どのフローやエンドポイントに最も問題があり、それらをどのモジュールが実装していますか?(各フェーズで取り組むホットパスを選定します。)
  4. 自動テストは存在し、すべて成功しますか?(フェーズ 1 のセーフティネットの範囲を決めます。ホットパスのテストが固定されていない場合は、そこに手を加える前に固定します。)
  5. 技術スタックは何ですか — 言語、フレームワーク、ORM、データベース、キャッシュなど。また、どこで実行していますか?(フェーズ 5~6 の実施条件となります。)
  6. 実際の負荷数値はいくつですか — 平均およびピーク時の QPS、データ量、成長率などです。(フェーズ 5 の実施条件となります。懸念ではなく数値に基づいて規模を決めます。)
  7. 今回は取り組みのどこまでを進めますか?(フェーズ 1~4 では安全かつ容易に変更できる状態にし、フェーズ 5~6 では高速化し、フェーズ 7~8 ではその状態を維持します。)

推測に基づく判断は避けてください。構造に問題がなく、課題が純粋にパフォーマンスだけの場合は、フェーズ 2~3 を監査のみの作業に短縮します。いずれの場合も監査で判明した内容を記録し、「監査のみ、変更なし」という注記を付けてフェーズのステータスを done にします。フェーズ 7 をスキップできるのは、以前の取り組みの RELIABILITY.md にある Integration-Point Audit が検証可能な最新状態である場合に限ります(ファイルを確認し、思い込みで判断しないでください)。フェーズ 1 は決してスキップしないでください。ベースラインのない最適化は当てずっぽうであり、セーフティネットのない再構築は賭けです。

次に、テンプレートから docs/ARCHITECTURE-OPTIMIZATION-PLAN.md を作成し、計画を確認します。トラッカーが存在し、すべてのフェーズにステータスが設定され、ユーザーが計画を確認したら完了です。

フェーズ

フェーズは記載された順序で実行します。各フェーズは、前のフェーズの成果物が存在することを前提とします。速度より構造を先に整えるのは意図的です。フェーズ 2~4 でホットパスを安全かつ低コストで変更できるようにすることで、フェーズ 5~6 の最適化を大規模な改修ではなく、小さな差分で行えるようになります。運用ルールに従って、どのフェーズからでも着手、スキップ、延期できます。ただし、フェーズ 1 はすべてのフェーズの前提です。独立した 2 つのセーフティネットとして機能し、動作を固定することでフェーズ 2~4 に着手でき、ベースラインを記録することでフェーズ 5~6 に着手できます。そのため、数週間かかることもあるプロファイルの収集を待たずに、構造の改善に着手できます。フェーズ 1 のプロファイルでデータベースが支配的だと判明した場合は、フェーズ 5 と 6 の順序を入れ替えてもかまいません。N+1 やインデックスの欠落を修正してからキャッシュを追加するのが、このスキルにおける「まず最も低コストな方法から」の原則です。Brief からいずれかのフェーズを実行する場合(構成スキルがインストールされていない場合)は、まず references/methods.md を読んでください。ここには各フェーズの詳細な手法、チェックリスト、数式、ヒューリスティクスが記載されています。Brief は概要のみです。

フェーズ 1 — 現状を固定し、測定する(working-with-legacy-code)— ゲート

目的: 以降のすべての変更を、テストで固定した動作と、数値で固定したパフォーマンスの両面から立証できるようにします。固定されていないコードにはどのフェーズも手を加えず、測定されていない経路は最適化しません。

概要(フォールバック): 2つの網を張ります。動作面では、テストのないコードはレガシーコードです。網羅してから変更し、編集して祈ることはしません。ホットパス上の変更点を見つけ、インラインの依存関係は最も影響の少ない接合点で切り離します(本番環境でのデフォルト値を持つ Parameterize Constructor、埋もれた呼び出しには Extract and Override を1つ)。実際の動作を記録する特性テストを書きます。まず誤った値をアサートし、失敗を確認して、実際の値を固定します。パフォーマンス面では、何かに手を加える前にプロファイリングします。ボトルネックは、直感で想定した場所にあるとは限りません。現実的なデータ量で、各ホットフローのレイテンシ(p50/p95/p99)、スループット、リソース使用量を記録します(開発用データベースでの計測値は当てになりません)。リソースごとに Gregg の USE メソッドを適用し、CPU、メモリ、ディスク、ネットワーク、接続プールの使用率(Utilization)、飽和度(Saturation)、エラー(Errors)を確認します。各指標が満たすべき予算を設定し、「完了」を感覚ではなく数値で判断できるようにします。

実行: intake で指定されたホットパスのモジュールに対して、working-with-legacy-code スキルを使用します。最適化する各フローの現在の動作を固定するために必要な接合点と、最小限の特性テストセットを確認し、続いて該当フローのプロファイラーまたは APM のベースラインを取得します。

ユーザーと決めること: (1) 対象範囲のホットパスを確定します。疑いではなく、測定された問題を基準にします。(2) 指標ごとの予算(例:チェックアウトの p95 < 500ms)と、記録の基準となるツール(プロファイラー、APM、負荷テスト)を決め、変更前後の数値を比較可能にします。(3) 特性テスト中に見つかったバグは、現在の動作を固定して台帳に記録し、黙って修正しないでください。呼び出し元がその挙動に依存している可能性があります。

成果物: docs/TESTING.md の ## Safety Net Map と ## Characterization Backlog を拡充します。## Baselines & Budgets、## Load Reality、## Profile Findings、## Optimization Ledger を含む docs/PERFORMANCE.md を作成します。現状のまま固定したバグと、テストされていないホストについて、docs/TECH-DEBT.md の ## Debt Ledger と ## Sprout / Wrap Register を新規作成または拡充します。トラッカーを更新します。

完了条件: 対象範囲のすべてのフローで動作が固定され(テストスイートが成功)、フェーズ 2~4 に進める状態になっていること。また、記録済みのベースラインと予算があり、フェーズ 5~6 に進める状態になっていること。2つの条件は別々に記録します。プロファイルの収集中であれば、構造フェーズを妨げるのではなく、Next Actions の行を追加して awaiting-evidence として保留にします。

フェーズ 2 — ずれた境界を引き直す(clean-architecture)

目的: コードベースが逸脱してしまった依存関係ルールを復元します。関心事が混在しているため変更が危険に感じられ、遅い部分を個別に最適化できなくなっています。

概要(代替案): ソースの依存関係は内側を向きます。フレームワーク → インターフェースアダプター → ユースケース → エンティティの順です。内側の要素が外側の要素を名前で参照することはありません。成長したコードベースでは、逸脱は具体的な形で現れます。たとえば、ビジネスロジックが ORM をインポートする、コントローラーがドメインルールを計算する、ベンダー SDK があらゆる場所から呼び出される、といった状態です。実際の依存関係グラフを作成し、違反を列挙します。ホットパスのビジネスルールを、フレームワークに依存しないユースケースとして抽出し、独自に所有するインターフェースの背後に置きます(依存性逆転)。これにより、フェーズ 5〜6 も実現できます。境界があれば、後から大掛かりな変更をせずにキャッシュやキューを挿入できるためです。完全な境界を設けるのは、データベース、外部サービス、デリバリーなど、本当に変化しやすい部分だけにします。それ以外では、形式だけのレイヤーを統合します。重要なのは方向であり、フォルダーの数ではありません。

実行方法: インテークで得たモジュールマップとスタックを使って、clean-architecture スキルを実行します。依存関係グラフと、ビジネスロジックがフレームワーク、ORM、またはベンダーを参照しているすべての違反を洗い出し、ホットパスのユースケースを抽出する計画を作成するよう依頼します。その際、どの境界がコストに見合うかを明示します。

ユーザーと決めること: 今回、境界をどこまで徹底するか。まずはホットパスから着手し、一括でレイヤーを再構築することは避けます。どのベンダーを最初に独自のインターフェースの背後に置くか。どの違反を今修正し、どれを記録しておくか。

成果物: docs/ARCHITECTURE.md の ## Layer Map & Dependency Rule(違反 | 場所 | 修正 | ステータス)と ## Decision Log を拡張します。トラッカーを更新します。

完了条件: 依存関係グラフが作成され、すべての違反が追跡項目として記録され、ホットパスのビジネスルールがフレームワークなしでテストを実行でき、テストスイートがすべて成功していること。

フェーズ 3 — モジュールを深める(software-design-philosophy)

目的: 複雑さによるコストを削減します。成長したコードベースには、浅いクラスや漏れ出した設計判断が蓄積されます。その一つひとつが、コードの実行速度より先にチームの作業を遅らせます。

概要(代替案): モジュールの深さ = 機能 ÷ インターフェースの複雑さ。常に一緒に使われ、状態を共有する浅い受け渡し専用クラスを統合します。それぞれの設計判断を、ただ一か所に隠します。情報漏洩(ある判断が複数のモジュールに反映されている状態)は、最も重大な警告です。実行順序に沿ってモジュールを整理する時間的分解をやめ、知識に沿って整理します。レイヤー間で同じ抽象化の受け渡しが続く場合、その境界はコストに見合っていない兆候です。これは戦術から戦略への転換です。今、10〜20%を投資することで、後続のすべてのフェーズで変更するファイル数が減ります。統合によってホットパスの呼び出しチェーンにある形式的な処理も減りますが、その理由はナノ秒単位の高速化ではなく、読みやすさです。

実行方法: フェーズ 2 でマッピングしたモジュールを使って、software-design-philosophy スキルを実行します。浅いクラスはどれか、一つの判断がどこでモジュール間に漏れ出しているかを特定し、より深く、インターフェースの小さいモジュールに統合する計画を作成するよう依頼します。

ユーザーと決めること: どの統合を今実施し、どれを記録しておくか。実際には無関係な関心事まで過剰に統合しないよう注意します。今後チームが採用する設計規約も決めます。

成果物: docs/TECH-DEBT.md の ## Smell Inventory(統合を適用した浅いモジュールと情報漏洩の項目)と ## Adopted Conventions を拡張します。トラッカーを更新します。

完了条件: 浅いモジュールの各クラスターが統合されるか、修正内容とともに記録されていること。特定された情報漏洩のある判断がすべて統合されているか、Smell Inventory の項目として記録されていること。テストスイートがすべて成功していること。

Phase 4 — ホットパスをリファクタリングする(refactoring-patterns)

目的: 名前の付いた、動作を維持する変換を用いて、これから最適化するコードの形を整えます。まずクリーンにし、それから高速化します。安全に変更できないものを安全に最適化することはできないためです。

概要(フォールバック): 各コードの臭いを、名前の付いたリファクタリングに対応付けます。コメントほどの大きさのブロックには Extract Method、ネストした条件分岐をガード節に置き換える、条件分岐をポリモーフィズムに置き換える、Parameter Object の導入、一時変数をクエリに置き換える、などです。ワークフローは、テスト成功 → 変換を1つ実施 → テスト成功 → コミットです。テストが失敗したらデバッグせず、元に戻します。作業を進めながら、クリーンコードの規律も取り入れます。意図が伝わる名前、1つの抽象化レベルで1つのことを行う関数、null を返さないこと、操作と状態のコンテキストを含むエラーなどです。Preparatory Refactoring は Phase 5〜6 への橋渡しです。最適化の前に、まず変更を容易にし(構造を整え)、次に容易になった変更を行います(最適化)。これらは別々のコミットにします。

実行: ホットパスのモジュールと Phase 1 のテストを使って、refactoring-patterns スキルを実行します。それぞれの臭いに名前を付け、変換方法を示し、テストを実行しながら1つずつ適用するよう依頼します。

ユーザーと決めること: 今回対応する臭いと台帳に記録する臭いの範囲、今後の最適化のうち挿入箇所で事前に Preparatory Refactoring が必要なもの、リファクタリングしたモジュールを TESTING.md の CI ゲート一覧に加えるかどうか。

成果物: docs/TECH-DEBT.md の ## Smell Inventory(臭い | 場所 | リファクタリング | ステータス)を拡張します。docs/TESTING.md の ## CI Gates を拡張し、ゲート一覧に加えたモジュールを記載します。トラッカーを更新します。

完了条件: 対象の臭いに、名前の付いたリファクタリングと done / ticketed のステータスが記録され、テストが成功し、構造変更のみのコミットに動作変更が含まれていないこと。

Phase 5 — 測定されたボトルネックに取り組む(system-design)

目的: プロファイルで時間がかかっていると示された箇所に、実際の数値に基づいて、最も低コストなものから順に最適化の労力を費やします。

概要(フォールバック): アムダールの法則によって、あらゆる改善の上限が決まります。全体の高速化は、最適化した部分が実際に占める時間の割合に制限されます。リクエストの5%を占める処理を10倍に高速化しても、短縮できるのは4.5%です。対象を選ぶのはコードレビューではなくプロファイルです。概算で負荷を計算します(QPS = 1日のアクティブユーザー数 × 1日あたりのアクション数 ÷ 86,400、ピーク時は平均の2〜5倍)。そのうえで、予算との差を確認します。次の順で対処します。まずアルゴリズム(O(n²) のループや、項目ごとに何度も発生する I/O は、どんなインフラストラクチャの改善よりも効果があります)。次に垂直方向の余力、TTL と明示的な無効化を備えたキャッシュ・アサイド方式(読み取りが多いパスの場合。ヒット率を測定してください。キャッシュが冷えた状態では、純粋なオーバーヘッドになります)、リクエスト処理の経路から時間のかかる処理を移すメッセージキュー(リトルの法則では、処理中のリクエスト数 = 到着率 × レイテンシーです。そのため、レイテンシーを短縮することは処理能力の改善にもなります)、その後に読み取りレプリカを検討します。シャーディングは、根拠がある場合にのみ行います。変更のたびに再測定し、数値を改善したものは維持し、改善しなかったものは元に戻します。

実行: Phase 1 のプロファイルと、初回ヒアリングで得た負荷の数値を使って、system-design スキルを実行します。最初にボトルネックとなるコンポーネント、測定された差を埋めるための最も低コストな施策の順序、そして現時点で明示的に不要な仕組みを尋ねます。

ユーザーと決めること: 今すぐリリースする施策と、発動条件となる数値を明記して延期する施策。キューの背後に移す最初のワークロードがあればその対象。キャッシュする各パスの無効化ルール、つまりどのイベントがどのキーを無効化するか。

成果物: docs/PERFORMANCE.md の ## Profile Findings と ## Optimization Ledger(変更 | 変更前 | 変更後 | 判定 | 日付)を拡張します。docs/ARCHITECTURE.md の ## Decision Log(採用・延期それぞれに発動条件を記載)と ## System Context を拡張します。## System Context では数値を繰り返すのではなく、PERFORMANCE.md の ## Load Reality を参照します。トラッカーを更新します。

完了条件: プロファイルに基づいてボトルネックが特定され、各施策が変更前後の数値とともに台帳へ記録されるか、発動条件を付けて延期され、採用した施策の中にベースラインを上回れなかったものがないこと。

フェーズ 6 — データレイヤーを修正する(ddia-systems)

目的: データベースが原因であることがよくあります。測定された遅さの多くはクエリに起因し、正しさに関する負債の多くは分離性の前提に起因します。根拠に基づいて両方を修正します。

概要(フォールバック): ORM のコードではなく、クエリプランを確認してください。よくある問題は、N+1 クエリ(行ごとに 1 回発行されるクエリです。バッチ処理または結合を使ってください。ORM がこれを暗黙に生成することがあります)、実際のアクセス経路に合ったインデックスの不足(遅いクエリで EXPLAIN を実行し、述語とソート列にインデックスを設定します。ただし、インデックスはどれも書き込みの負荷になります)、上限のない結果セット(すべてのリストをページネーションします)、幅の広い行に対する SELECT *、そして深いオフセットページネーション(キーセット方式を使います)です。ストレージエンジンは読み取りと書き込みのトレードオフがあります(LSM の書き込みスループットと B-tree の読み取りレイテンシーなど)。ハードウェアを購入する前に、アクセスパターンに合ったモデルを選んでください。同時実行時の正しさについては、ほとんどのデータベースのデフォルトは read-committed または snapshot であり、serializable ではありません。そのため、読み取り後に書き込む処理では write skew が発生します。明示的にロックする(SELECT ... FOR UPDATE)か、不変条件の維持が必要な箇所では serializable トランザクションを使ってください。2 つ目の読み取りパターン(検索、分析、フィード)がある場合は、CDC で同期を維持する派生データが妥当です。二重書き込みは決して行わないでください。また、フェーズ 5 で導入したレプリカにより、read-your-writes を意図的に扱う必要があります。

実行: フェーズ 1 のプロファイル、フェーズ 5 の調査結果、インテークで確認したデータベースを使って、ddia-systems スキルを使用してください。クエリレベルのデータソースがまだない場合は、まず有効にしてください(pg_stat_statements、auto_explain、スロークエリログなど)。これはフェーズ 1 で後回しにした計測であり、推測する理由にはなりません。クエリプランの監査(N+1 クエリ、インデックス不足、上限のない読み取り)、実際のデフォルト分離レベルと対象パスで発生する異常、ワークロードごとのデータモデルとエンジンの適合性について確認してください。

ユーザーと決める事項: 書き込みコストを考慮したうえで追加するインデックス、ロック・serializable トランザクション・許容する異常のどれを各パスに適用するか、CDC で同期する 2 つ目のデータストアが必要なワークロードがあるかどうか。

成果物: docs/ARCHITECTURE.md の ## Data & Storage Decisions と ## Decision Log を拡張し、docs/PERFORMANCE.md の ## Profile Findings と ## Optimization Ledger にクエリの修正前後を追記します。トラッカーを更新します。

完了条件: 遅いクエリが測定値付きの修正前後の比較で解消されていること、対象範囲のフローにあるすべてのリストエンドポイントがページネーションされていること(それ以外は Debt Ledger の項目とします)、分離レベルが文書化され、リスクのあるパスがロックされていること、派生データに同期方式が定義されていること。

フェーズ 7 — 障害時も高速性を保つ(release-it)

目的: 依存先の遅延でシステム全体が停止するなら、高速なシステムとは言えません。障害発生時のレイテンシも、パフォーマンス特性の一つです。

概要(代替案): 統合ポイントは最も大きな障害要因です。応答が遅いより、応答がないほうがましです。依存先が応答しないと、ログに何も残らないままスレッドやプールが枯渇します。必須事項:すべてのアウトバウンド呼び出しに接続タイムアウトと読み取りタイムアウトを設定します(タイムアウトはレイテンシ予算です)。重要な依存先にサーキットブレーカーを設定します(待つより、すぐに失敗するほうが適切です)。一つの依存先の遅延で共有プールが枯渇しないよう、バルクヘッドを設けます。指数バックオフとジッターを使って再試行します(単純な再試行は、依存先が停止しかけているときに負荷を3倍にします)。ログ、一時データ、キャッシュが際限なく増えないよう、平常時にもクリーンアップします。エンドポイントごとに RED メトリクス(レート、エラー、所要時間)を設定し、症状(p95 が予算を超過)に対してアラートを設定します。フェーズ 1 の予算を、一度限りのスナップショットではなく、本番環境のガードレールにします。

実行: release-it スキルを使い、インテークで特定したアウトバウンド依存先と、フェーズ 1 の予算を適用します。フローのレイテンシ予算から算出したタイムアウト値、サーキットブレーカーとバルクヘッドの配置、RED メトリクスと症状アラートの設計を求めます。

ユーザーと決めること: フローの予算に紐づけた、依存先ごとのタイムアウトとサーキットブレーカーのしきい値。専用プールを割り当てる依存先。重要度の低い依存先が停止した場合に、各コアフローがどのように機能を縮退させるか。

成果物: docs/RELIABILITY.md に ## Integration-Point Audit(依存先 | タイムアウト | サーキットブレーカー | バルクヘッド | 再試行ポリシー | ステータス)、## Query & Resource Findings、## Health Checks & Metrics を新規作成または追記します。トラッカーを更新します。

完了条件: 対象フローのすべてのアウトバウンド呼び出しに、そのフローの予算内のタイムアウトが設定されていること(対象外の呼び出しは Debt Ledger の項目にします)。重要な依存先にサーキットブレーカーとバルクヘッドが設定されていること。上限のない結果セットとブロックされたスレッドが ## Query & Resource Findings に記録されていること。RED メトリクスと症状アラートによって、本番環境でフェーズ 1 の予算が守られていること。

フェーズ 8 — 予算と習慣を定着させる(pragmatic-programmer)

目的: 改善を恒久的なものにします。ゲートが検出しなければ、何気ないコミットが一つずつ回帰を招きます。

概要(代替案): フェーズ 1 の各予算を CI ゲートにします。ホットパスに対するパフォーマンステストやクエリ数のアサーションを設け、p95 の予算超過でビルドが失敗するようにします。DRY が扱うのは知識です。同じルールを二か所で計算すると食い違いが生じ、同じクエリを二つのレイヤーから実行するのは、バグの温床であると同時にパフォーマンスの負担にもなります。割れ窓理論に従い、最初の未レビューの遅いクエリや、見送られたインデックスは、すぐに修正するかチケットにします。放置して徐々に悪化させてはいけません。可逆性を確保するため、ベンダーやインフラは所有するインターフェースの背後に置きます。これにより、キャッシュの交換やキューの変更といった次の最適化が、全面的な書き換えではなく、1 週間の作業で済むようにします。イテレーションごとの負債予算を設定し、規約を書き残します。先送りした項目は記憶ではなく台帳で管理します。

実行: 変更したモジュール全体で pragmatic-programmer スキルを使います。重複した知識(重複クエリやルールを含む)、追跡されていない TODO、割れた窓を特定し、パフォーマンス予算に対する CI ゲートの設計を求めます。

ユーザーと決めること: どの予算をビルドをブロックする CI ゲートにし、どれをダッシュボードのアラートにするか。イテレーションごとの負債予算。割れた窓への対応方針(すぐに修正するものと、チケットにするもの)。

成果物: docs/PERFORMANCE.md の ## Baselines & Budgets を拡張し、各予算のゲートを明記します。docs/TECH-DEBT.md に ## Debt Budget & Broken-Windows Policy と ## Adopted Conventions を追記します。docs/TESTING.md に ## CI Gates を追記します。トラッカーを更新します。

完了条件: 各ホットパスの予算が CI ゲートまたは担当者のいるアラートになっていること。重複した知識が修正または台帳に記録されていること。規約が文書化されていること。

オプションのフェーズ

スキル追加するタイミング成果物
clean-codeホットパス以外でも可読性が低く、コードベース全体で命名、関数、エラーハンドリングを見直す必要がある場合docs/TECH-DEBT.md の ## Smell Inventory、## Adopted Conventions を拡張
domain-driven-design境界がビジネス用語と噛み合わず、ドメインに合わない単位でモジュールが分割されている場合docs/ARCHITECTURE.md の ## Bounded Contexts & Context Map、## Domain Glossary (Ubiquitous Language) を拡張
high-perf-browser計測された遅さがバックエンドではなく、ページ読み込み、LCP、ブロッキングリソースなどブラウザー側にある場合docs/METRICS.md の ## Baselines & Targets、docs/WEBSITE.md の ## Audit Findings を拡張
team-topologies複数のチームがシステムを担当しており、モジュールの境界をチームの境界に合わせる必要がある場合(コンウェイの法則)docs/OPERATIONS.md の ## Team Structure を拡張

オプションのフェーズにも、コアフェーズと同じ運用ルールが適用されます。記載されている各スキルをコアフェーズと同様に正確に読み込んで使用し、追加条件が初めて満たされた時点で挿入します。これらにはインラインのブリーフはありません。単独で実行する場合は、clean-code を命名、関数のサイズ、エラーハンドリングの見直しとして、domain-driven-design をユビキタス言語と境界づけられたコンテキストのマップとして、high-perf-browser を Core Web Vitals(LCP、INP、CLS)の監査として、team-topologies を認知負荷とチーム境界のレビューとして実行するか、指定されたスキルをインストールして、そのフレームワーク全体を使用してください。

よくある間違い

間違い修正方法
プロファイラーが示す箇所ではなく、直感で選んだ箇所を最適化するまずプロファイリングします(フェーズ 1)。アムダールの法則により、得られる効果は、そのコードが実際に消費する時間の割合が上限となります。
セーフティネットなしに高速化のための書き換えを行うまず特性テストで挙動を固定します(working-with-legacy-code)。間違った答えを高速に返しても、間違いであることに変わりはありません。
数値を改善しなかった最適化を残す変更のたびに Optimization Ledger に前後の数値を記録します。ベースラインを上回らないものは元に戻してください。見返りのない複雑さは、純粋な負債です。
アルゴリズムを直す前にインフラに手を伸ばすO(n²) のループや N+1 クエリには、どんなキャッシュもかないません。まずコードを直し、それから仕組みの規模を決めます(system-design)。
無効化ルールなしにキャッシュする古いデータに関するバグは、削減できたレイテンシよりも大きなコストになります。キャッシュする各経路で、どのイベントがどのキーを無効化するのかを明記します。
ORM が適切な SQL を生成すると信じる遅いクエリを EXPLAIN します(ddia-systems)。N+1 やインデックスの欠落は、一見問題のなさそうなコードに隠れています。
外部呼び出しにタイムアウトを設定せずに高速だと判断する障害時のレイテンシもパフォーマンスの特性です(release-it)。依存先が 1 つでも応答しなくなれば、あらゆる最適化が台無しになります。

道のりの完了

痛みの種類に合わせて対処します。遅いエンドポイントへの不満なら、フェーズ 1、5、6(ベースライン、ボトルネック、クエリ)だけで済む場合があります。数日で、すぐに効果が得られます。あらゆる変更に時間がかかり、リスクも伴うコードベースなら、まず構造を整えるフェーズに取り組みます。境界が明確であってこそ、最適化の規模を小さくできます。いずれの場合も、台帳で成果を確認します。維持した変更はベースラインを上回り、それ以外はすべて元に戻しています。

完了チェックリスト — 各項目は成果物に紐付いています。

  • docs/ARCHITECTURE-OPTIMIZATION-PLAN.md のすべてのフェーズが done、deferred: reason、または skipped: reason になっている。
  • すべてのホットパスにベースラインと予算があり、現在の測定値がその範囲内にある(PERFORMANCE.md の Baselines & Budgets)。
  • 維持した最適化にはすべて測定した変更前後の値が示され、ベースラインを満たさなかったものは維持していない(PERFORMANCE.md の Optimization Ledger)。
  • ホットパス上の Dependency Rule 違反が解消されているか、追跡対象の行として記録されている(ARCHITECTURE.md の Layer Map)。
  • 遅いクエリは実行計画に基づいて修正され、リストにはページネーションが実装され、分離レベルが文書化され、リスクの高いパスがロックされている(ARCHITECTURE.md の Data & Storage Decisions)。
  • すべての外部呼び出しにタイムアウトが設定され、予算が RED メトリクスとアラート、または CI ゲートによって監視されている(RELIABILITY.md、TESTING.md の CI Gates)。

トラッカーを締めくくります。残りの Next Actions を PERFORMANCE.md の台帳と TECH-DEBT.md に引き継ぎ、何も失われないようにします。続いて、次のステップへ進みます。速度ではなく変更への不安が課題なら、remove-technical-debt スキルを続けて実行します。新しく、まだテストされていないプロトタイプに本番向けの仕上げを一通り施すなら、improve-code-quality を使います。次のシステムを初日からこの構造で設計するなら、design-code-architecture を使います。

コメント