Agent Skills: Optimize

【最適化の判断】実行時パフォーマンス最適化の思考プロトコル。推測による最適化を拒否し計測を最優先する。「速くしたい」「遅い」「重い」「ボトルネック」「最適化」「パフォーマンス改善」「スケールしない」「p99が悪い」「メモリが膨らむ」「GCが頻発」「CPU張り付く」「タイムアウト」「レイテンシ削減」「スループット向上」「もっと速く」「なぜ遅い」などの語、または相手が具体的な最適化提案 (キャッシュ追加 / 並列化 / インデックス追加 / アルゴリズム変更 / 言語切替 / サーバー増強 等) を出してきた際の妥当性検証時に発動。計測を最優先し、上流に遡り、暗黙の前提を疑い、層を横断して案を生成し、軽い案を優先し、帰結を予測する。

UncategorizedID: TakumiOkayasu/dotfile-work/optimize

Install this agent skill to your local

pnpm dlx add-skill https://github.com/TakumiOkayasu/dotfile-work/tree/HEAD/common/skills/optimize

Skill Files

Browse the full folder contents for optimize.

Download Skill

Loading file tree…

common/skills/optimize/SKILL.md

Skill Metadata

Name
optimize
Description
【最適化の判断】実行時パフォーマンス最適化の思考プロトコル。推測による最適化を拒否し計測を最優先する。「速くしたい」「遅い」「重い」「ボトルネック」「最適化」「パフォーマンス改善」「スケールしない」「p99が悪い」「メモリが膨らむ」「GCが頻発」「CPU張り付く」「タイムアウト」「レイテンシ削減」「スループット向上」「もっと速く」「なぜ遅い」などの語、または相手が具体的な最適化提案 (キャッシュ追加 / 並列化 / インデックス追加 / アルゴリズム変更 / 言語切替 / サーバー増強 等) を出してきた際の妥当性検証時に発動。計測を最優先し、上流に遡り、暗黙の前提を疑い、層を横断して案を生成し、軽い案を優先し、帰結を予測する。

Optimize

実行時パフォーマンスを「測定なき推測」で改善しないための思考の指針。相手が設定した「速くしたい場所」をそのまま受け入れず、ボトルネックを再特定し、層を横断して選択肢を棚卸しし、計測根拠と漸近性で評価し、最も軽くて効く案を推奨する。

derive-optimal-solution を土台に、実行時パフォーマンス特有の罠 (Amdahl の壁・テイルレイテンシ・キャッシュ汚染・マイクロベンチ偽陽性・GC/アロケーション・メモリ局所性・並列化の同期コスト) を組み込んだ派生スキル。

以下は順番に踏む手続きではなく、最適化を考えるときに当てるべき観点。規模に応じて深さを変える: 関数 1 つのマイクロ最適化なら計測と案出しを最低限、システム全体の判断なら全観点を厳密に当て、層横断の案出しは並列 subagent に分散してよい。

哲学

  1. 測定なき最適化は罪 — 推測でホットパスを当てにいかない。
  2. そもそもその処理を実行しているのか — 速くする前に「なぜ実行されるのか / なぜこの頻度か / なぜこのデータ量か」を問う。実行されない処理は無限に速い。
  3. 重い案ほど効きそうに見える錯覚を捨てる — キャッシュ層追加・並列化・言語切替は最後の手段。入力を絞る / 実行回数を減らす / アルゴリズムを変える が先。

典型的な失敗

相手が「処理 X が遅いのでキャッシュを足したい / 並列化したい / Rust で書き直したい」と聞いてくる → X とその対策を所与として実装詳細に踏み込む → X がそもそも実行不要だった (デッドコード・冗長呼び出し・上流フィルタ抜け)、または X が全体の 5% しか占めない (Amdahl の壁) を見逃す → コードは複雑化したが体感は変わらない。問題は「速くする」ではなく「何を速くするか」の特定。

トリガー条件

いずれか該当で適用する。

  • 症状語: 遅い / 重い / もっさり / タイムアウト / スケールしない / メモリ膨らむ / CPU 張り付く / GC 頻発 / p99・テイル悪化
  • 改善要求: 速くしたい / 最適化したい / 軽くしたい / レイテンシ削減 / スループット向上 / コスト削減
  • 具体提案の検証: 相手がキャッシュ追加・並列化・インデックス追加・Redis 導入・言語切替・サーバー増強を提示済み
  • 計測前の判断要請: profiler 出力・ベンチ・本番メトリクスが示されていないのに「どう直すべきか」を聞いてきている
  • トレードオフの可視化要請、規模変化の予兆 (データ N 倍予定 等)

計測 (推測を排除する)

最優先。計測を欠いた最適化はギャンブル。まず最適化対象 (何を最小化したいか) を確定する — 対象でメトリクスが変わる。

| 最適化対象 | 主指標 (ベースライン化) | 内訳分解 (ホットスポット特定) | | --- | --- | --- | | レイテンシ | p50/p90/p99/max [ms] | CPU/I/O/ロック/GC の内訳 | | スループット | req/sec, ops/sec | ボトルネック資源の飽和率 | | コスト (¥/月) | 月額請求・単価×量分解 | サービス/リージョン/インスタンスタイプ別、アイドル時間 | | メモリ・容量 | ライブヒープ・使用量 | アロケーション源、保持期間別 | | 帯域 | 転送量 [GB/月] | エンドポイント/オブジェクト種別 |

計測の原則:

  • 何を: エンドツーエンドのレイテンシ、CPU/オフ CPU/メモリのプロファイル、テイル分布 (p50〜p999, max — 平均だけでは詐欺)、スループット
  • どこで: 本番条件に近い負荷で、ウォームアップ後、複数回 + 分散 (1 回計測は信用しない)
  • 何を判定: ベースライン (基準値)、目標値 (SLA/UX/コスト要件)、その差 (改善必要量)

コスト文脈の読み替え: 「プロファイラ」→ Cost Explorer / Billing 詳細、「Amdahl」→ コスト寄与の大きい上位 3 項目で全体の何 % か、「テイル分布」→ 時間帯別ピーク。請求書を見ずにインスタンスタイプ変更を提案しない。

計測結果が入手不能な場合: 必要な計測項目を相手に提示し、結果を待つことを推奨する。それでも進めるなら推奨を「計測仮説」と明記し、最初のタスクを「計測ハーネス構築」にする。

症状と構造を切り分ける

「遅い」は症状。原因は構造。症状 ≠ 問題。

  • 症状例: API が遅い / クエリが遅い / 描画がもたつく / メモリが膨らむ
  • 構造例: データモデルがユースケースと不一致 (深い 1:N:N) / 本来非同期で良い処理を同期実行 / フロント-バック間で N+1 通信 / 定常的なアロケーション / アクセスパターンと噛み合わない責務分割

観測している症状はどの構造的要因に起因するか、仮説を書き下して計測と突き合わせる。

上流に遡る

「なぜ遅い」を 2 回以上問う。1 回で止まらない。

なぜ遅い → 直接ボトルネック (例: クエリが O(n²)) → なぜそのコードパスを通る → 上流の呼び出し設計 (1 リクエストで N 回呼ばれている) → なぜ N 回 → そもそもの責務分割 (個別取得の連鎖) → 上流を変えれば問題が消えるか (バルク取得 1 回にすればクエリ N 回が不要)。

最適化の典型的な「上流」:

  • 冗長呼び出し: メモ化以前に「呼ぶ必要があるか」
  • N+1 アクセス: 個別最適化以前に「バルク化できるか」
  • 早すぎる材料化: 使わないデータも取得 → フィルタを上流へ
  • 遅すぎるフィルタ: 取得後に絞る → WHERE 句 / インデックス / プッシュダウン
  • 同期で待っている: 本質的に非同期可能なら イベント駆動 / 事前計算 / 遅延

暗黙の前提を疑う

相談文には明示されない前提が多数含まれる。最適化文脈では「実行頻度」「データ量」「レスポンスタイム要求」「正確性要求」が暗黙の所与になりやすい。相談文の断定表現 (「〜する必要がある」「リアルタイムで」「全件」「最新の」「同期で」「毎回」等) を 3 つ以上抜き出し、根拠 (SLA 文書・計測値・ユーザー要望) が示されているか確認する。引用された他者提案 (「SRE から X しようと出ている」) も対象 — 引用提案ほど無批判に通りやすい。根拠が弱い前提があれば、それを変える案を必ず候補に含める。

| 暗黙の前提 | 疑い方 | | --- | --- | | リアルタイムで返す必要がある | 何 ms 以内? なぜその閾値? | | 全件取得する必要がある | ページング・上位 N 件で代替不可? | | 最新データである必要がある | 何秒前なら許容? 1 秒キャッシュで体感は変わるか? | | 正確である必要がある | 99.9% 近似 (HyperLogLog 等) で要件を満たさないか? | | 同期で実行する必要がある | 非同期 / 通知ベースに変えられないか? | | サーバー側で計算する必要がある | クライアント / エッジ / CDN にオフロード可能か? | | 毎リクエスト計算する必要がある | 事前計算 / マテビュー / バッチで代替可能か? | | 現在のスキーマを維持する必要がある | 非正規化 / 集計テーブル / 検索専用ストアを置けないか? |

この前提疑いで見つかる案は、しばしば最も軽く根本的な解になる。スキップすると相手の提案空間に閉じ込められ、コード最適化に終始する。

問題空間を広げる

相手の問題空間の外側に候補があるか、各次元で問い直す。

| 次元 | 最適化文脈での問い | | --- | --- | | 時間軸 | 即時応答が必須か / 事前計算で代替可能か / 遅延許容で非同期化できるか | | 主体 | サーバー / クライアント / エッジ・CDN・DB・OS のどこで解くか | | スコープ境界 | 1 リクエスト内で完結が必要か / 分割・バッチ集約可能か | | 抽象レベル | 症状対処 / 構造変更 / 原理再定義 (要件緩和・近似) | | 業界・前例 | 類似スケールのサービスはどう解いているか (LSM-tree, CDN, 確率的構造) | | 負荷形状・分布 | 平均 vs ピーク vs バースト / 一様 vs 偏り (Zipf, hot key) で最適化対象が変わる |

層を横断して案を出す

最適化は層 (要件 → アーキ → アルゴ → データ構造 → 実装 → 並列 → HW) を横断する。1 層に閉じず、5 つ以上の案を生成する。相手の案があれば変形案も含め、「やらない / 計測待ち / 延期」を必ず入れる。

| 層 | 制御点 | | --- | --- | | 要件 | SLA を緩める / 近似許容 / 遅延許容 / バッチ許容 / 一部機能を削る | | アーキテクチャ | 同期→非同期 / リアルタイム→事前計算 / モノリス→CDN・エッジ / 集約→シャーディング / Pull→Push | | アルゴリズム | 計算量を下げる / 確率的構造 (Bloom, HLL) / 近似アルゴ | | データ構造 | 配列/ハッシュ/ツリー/ヒープ / AoS vs SoA / 索引追加 / 非正規化 / カラムナ | | 実装 | ホットループ最適化 / アロケーション削減 / インライン化 / 分岐削減 / SIMD | | 並列化 | スレッド (CPU) / 非同期 I/O / SIMD / GPU | | ハードウェア | スケールアップ / NVMe / 大容量メモリ / 専用アクセラレータ |

軽い案が見落とされやすい (重要): 議論は派手な案に流れるが、最も軽くて効くのはたいてい — コードパスの削除 (デッドコード・不要なログ)、早期リターン / 条件の入れ替え、N+1 のバルク化 (1 行修正で 100 倍)、インデックス 1 本、リクエスト合流 / debounce / throttle。

解の重さで優先順位をつける

案を、追加される責務・複雑度で並べる。軽いほうから優先検討する。

| 重さ | パターン | 例 | | --- | --- | --- | | 0 やらない/計測待ち/延期 | 現状維持・計測ハーネスのみ・SLA 達成済みなら未着手 | 「先に計測すべき」推奨 | | 1 入力を絞る | 範囲限定・フィルタ・ページング・サンプリング・近似 | LIMIT, WHERE 強化, 上位 N 件, 近似集計 | | 2 実行回数を減らす | メモ化・デバウンス・バッチ化・遅延化 | useMemo, N+1 のバルク化, lazy 評価 | | 3 アルゴ/データ構造を入れ替える | 計算量改善・適切なコンテナ・索引追加 | O(n²)→O(n log n), List→HashMap, B-tree | | 4 新しい仕組みを足す | 外部キャッシュ層・ワーカー・事前計算ジョブ | Redis, バッチジョブ, マテビュー, CDN | | 5 アーキ刷新/言語切替 | サービス分割・シャーディング・ネイティブ実装 | マイクロサービス分離, Rust 書き直し, GPU 化 |

原則: 同等効果なら軽い案を主推奨にし、重い案はバックアップ扱い。重さ 3 以上を主推奨にするなら「軽い案では解けない具体的な計測根拠」を明示する。案が複数の重さにまたがる場合 (索引追加 + CTE 書き換え 等) は別案に分割する。重い案 (キャッシュ層・並列化・専用ストア) は新しい暗黙ルール (整合性・順序性・障害時挙動) を増やす点に注意する。

帰結を予測する

相手の最適化提案が採用された 3 ヶ月後・1 年後に何が起きるか。最適化は副作用が遠くで顕在化する。最低 3 視点を検討する。

  • スケール時 (データ/ユーザー/トラフィック N 倍): 改善幅は維持されるか
  • テイルレイテンシ: 平均は良くなったが p99/p999/max が悪化していないか (GC pause, ロック競合, リトライ伝播)
  • キャッシュ整合性: 古いデータ / cache stampede / invalidation 地獄
  • メモリ圧迫: 速度のためのメモリ使用 → GC 頻発 / OOM / コンテナ kill
  • マイクロベンチ vs 本番: 隔離環境で速くても本番ではキャッシュ競合で逆効果
  • 新メンバー参入: 暗黙の最適化 (アロケーション避け等) を知らない人が壊す

受け入れ難い帰結の典型: 適用忘れの再発 (「全箇所で N+1 を避ける規約」系)、二重管理の同期責務 (DB とキャッシュ両持ち)、暗黙の契約 (理由が読めない最適化)、多段防御の破壊 (リトライストーム)、平均↑テイル↑、メモリ↔CPU トレードオフの暴走、マイクロベンチ偽陽性。これらが予測できたら相手の提案は主推奨にせず、構造的に発生させない案を出す。

評価する

「速さ」だけでは不十分。文脈に応じて 4〜7 軸を選ぶ: 計測根拠 (推測ベースか) / 改善上限 (Amdahl 寄与 = 全体に占める割合 × 改善率) / 漸近性 vs 定数倍 / テイル耐性 / 正確性影響 / 可逆性 / 複雑度増加 / 暗黙の前提増加 / 保守コスト / 本番条件耐性。

軸 × 案の表で ✅/⚠️/❌ の 3 段階で可視化する。相手の提案を必ず 1 列含める。「計測根拠」を最初に置く (ここが ❌ なら他の軸は空中戦)。集計スコアは作らない (Amdahl 寄与と保守コストは単純合計できない) — どれが主推奨かは推奨節で文章で示す。

出力前の確認

推奨を出す前に確認する。1 つでも満たさなければ案出しに戻る。

  • 計測根拠に基づいているか (なければ「先に計測すべき」が推奨に明記されているか)
  • 症状ではなく上流に届いているか
  • 相手が問うた粒度の問いに答えているか (関数の話にアーキ刷新を主推奨にしていないか)
  • 主推奨より軽い案で同等以上の効果を持つ案がないか
  • 予測した受け入れ難い帰結を回避しているか
  • 相手の提案にない案・観点 (計測仮説の検証・要件緩和 等) が 1 つ以上あるか

同じ問題で詰まり続ける場合は、保守的な推奨に切り替え、未解決点を不確実性として明記する。

アンチパターン

  • 推測最適化 — 計測なしで「ここが遅そう」で書き始める
  • Amdahl 無視 — ホットパスでない箇所に注力 (全体の 2% を 10 倍にしても 1.8% 改善)
  • マイクロベンチ盲信 — 隔離環境のベンチを本番性能と同一視
  • 平均だけを見る — p99/p999/max を見ない。テイルが UX を決める
  • キャッシュで根本問題を覆い隠す — O(n²) のままキャッシュ層を足す
  • 並列化で問題を増やす — シングルスレッドで遅い処理を並列化してデバッグ困難に
  • アルゴ改善せず定数倍を追う — SIMD・unsafe の前に O 表記を見直す
  • アロケーション / メモリアクセスパターン無視 — ホットループ内の new、false sharing
  • 早すぎる最適化 — プロト・テスト段階で最適化に走る
  • リトライで負荷増幅 — 障害時のリトライストーム
  • 言語切替 / HW 増強への過度な期待 — アルゴが O(n²) なら書き直しても同じ

典型的な視点シフト

| 相手が設定した問題 | 上流の問題 | | --- | --- | | API が遅い | データモデルとユースケース不一致 (深い 1:N:N) | | クエリが遅い | インデックス不在 / クエリ形状が索引と不一致 / N+1 | | ループが遅い | そもそもループが必要か (ベクトル化, SQL 一発化) | | 画面描画が重い | 再描画トリガー過多 / バンドルサイズ / クリティカルパス | | メモリ使用量が多い | データ構造の選択 (AoS vs SoA) / 一括ロード | | GC が頻発 | ホットパスのアロケーション / 短命オブジェクトの量産 | | 並列化しても速くならない | ボトルネックが I/O または依存関係 / Amdahl の壁 | | p99 が悪い | GC pause / ロック競合 / ロングテイル処理の混入 | | サーバー増強しても改善しない | DB / 共有ストレージ / 共有キャッシュがボトルネック |

最適化対象は末端で観測される。原因はデータフロー・呼び出し設計・要件定義の上流にある。

出力テンプレート

## 計測の状況
- 入手済みデータ / 不足データ (取得方法を提案)
- ベースライン (例: p50=120ms, p99=1.8s) / 目標 (例: p99<500ms)

## 問題の再構成
- 相手が設定した問題 / 観測している症状
- 上流の構造 / 本質的な問い
- ボトルネック仮説 (Amdahl 寄与の見積もり)

## 選択肢の棚卸し
各案に重さ (0〜5) と層を `重さ: N / 層: ...` で付記する。
- 案 A (相手の提案): ... 重さ: N / 層: ...
- 案 B (現状維持 + 計測強化): ... 重さ: 0
- 案 C (上流を変える / 前提を崩す): ... 重さ: 1
- 案 D (アルゴ・データ構造の入れ替え): ... 重さ: 3
- 案 E (やらない / 計測待ち): ... 重さ: 0

## 帰結予測
相手の提案ごとに最低 1 視点 — スケール時 / テイル時 / メモリ圧迫時 等。
受け入れ可能 / 受け入れ難い で判定する。

## 推奨
主推奨を 1 構成で示す。段階展開 (Phase 1: 案 B → Phase 2: 案 C+D → ...) も可。
選ばなかった案の却下理由、計測未済による不確実性も明記する。

境界判断の原則

  • 粒度を越えない: 「上流に遡る」は相手が問うた粒度の中での遡及。関数の最適化を聞かれてサービス分割を主推奨にするのは粒度の越境 (相手が明示的に「層を問わず最善を」と問うた場合のみ例外)。推奨案に「設計を見直す」「組織を変える」のような行動選択肢が混じったら粒度ずれの兆候。
  • 粒度は最適化対象の意味のある最小単位 (関数 / エンドポイント / ジョブ / システム) で切る
  • 計測データが不足する次元は「先に計測すべき」と明示して進む。推測で埋めない
  • 指示が競合する場合 (「並列化したい」vs「テイル悪化を避けたい」) は計測根拠を優先する

適用の型

どこまで遡れば上流に届くかの相場感。

  • マイクロ最適化 (関数 X が 50ms): 本番での呼び出し回数と Amdahl 上限は? 1 回 50ms を 10ms にする前に、N 回呼ばれるのを 1 回にできないか
  • ホットパス最適化 (API p99=2s): どの段階 (パース/認証/DB/外部 API/レンダリング) が支配的か。クエリを速くする前に、そのクエリ形でユースケースを満たすのが適切か
  • コスト削減 (クラウド請求が高い): 内訳は CPU/メモリ/I/O/ネットワークのどれか。安い HW で動かす前に、ワークロード自体の必要性と頻度を問う
  • スケール問題 (ユーザー増で線形以上に悪化): ボトルネックが共有資源 (DB/ロック) なら、増強しても解決しない

ultrathink との併用

ultrathink が「思考時間を使う許可」なのに対し、本スキルは「どこに時間を使うか」の方向付け。併用で計測仮説の検証と上流構造の深掘りに時間を投入できる。