mcpField
A
accelint-ts-performance

accelint-ts-performance

github.com/gohypergiant開発25344 回インストール2 週間前に更新
リポジトリ

accelint-ts-performance について

JavaScript/TypeScript の性能を体系的に監査・改善するスキルです。ボトルネックやアンチパターンの分析から、最適化手法と変更後の正当性確認までを案内します。

主な機能

  1. 01体系的な性能監査
  2. 02アルゴリズム上の非効率を特定
  3. 03CPU とメモリのトレードオフ評価
  4. 04問題別の最適化パターン適用
  5. 05変更後の正当性確認

活用シーン

  1. 01JavaScript コードベースの性能監査
  2. 02非効率なループや検索の特定
  3. 03メモリや I/O 動作の最適化

インストール

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

$npx skills add https://github.com/gohypergiant/agent-skills --skill accelint-ts-performance

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

AGENTS.md
README.md
assets/
output-report-template.md
references/
avoid-allocations.md
batching.md
bounded-iteration.md
cache-property-access.md
cache-storage-api.md
currying.md
defer-await.md
memoization.md
object-operations.md
performance-misc.md
predictable-execution.md
quick-reference.md
reduce-branching.md
reduce-looping.md

詳細

TypeScript のパフォーマンス最適化

JavaScript/TypeScript のコードベースを体系的に最適化します。監査ワークフローと、実行時パフォーマンスを高める専門的な最適化パターンを組み合わせています。

パフォーマンス最適化で絶対にしてはいけないこと

注: any/enum による型安全性、null の回避、引数の変更を避けることなど、一般的なベストプラクティスについては、accelint-ts-best-practices スキルを使用してください。このセクションでは、パフォーマンスに特化したアンチパターンのみを扱います。

  • コードがコールドパスだと決めつけないでください - ユーティリティ関数、フォーマッター、パーサー、バリデーターは単純に見えても、ループ、レンダリングパイプライン、リアルタイムシステムで頻繁に呼び出されることがあります。パフォーマンスのアンチパターンがないか、常にすべてのコードを監査してください。使用頻度を推測したり、単純そうだからという理由で監査を省略したりしないでください。

  • すべての最適化を考えなしに適用しないでください - パフォーマンスパターンにはトレードオフがあります。最適化によるメリットとコードの複雑さのバランスを取ってください。監査では体系的な分析を通じてすべてのアンチパターンを特定し、期待できる改善効果とあわせて報告してください。どの最適化を適用するかは、ユーザーが個別の状況に応じて判断できるようにしてください。

  • アルゴリズムの計算量を無視しないでください - O(n²) のコードをマイクロ最適化しても効果はありません。n=1000 の場合、アルゴリズムを修正して O(n² → O(n)) にすれば1000倍高速化できますが、マイクロ最適化では最大でも1.1~2倍程度です。まずアルゴリズムを修正してください。O(1) で検索できる Maps/Sets を使い、ネストした反復をなくし、適切なデータ構造を選んでください。

  • 速度のために正確性を犠牲にしないでください - パフォーマンス上のバグもバグです。最適化によって、手動ループでのインデックスのずれ、空配列での誤動作、null の処理漏れなど、エッジケースで問題が生じることはよくあります。変更の前後で動作が一致することを確認してください。最適化の前にエッジケースを網羅するテストを追加してください。本番環境でバグを見つけるコストは、パフォーマンス改善のメリットをはるかに上回ります。

  • 自分が担当していないコードを最適化しないでください - 共有ユーティリティ、ライブラリの内部実装、または他の人が積極的に開発しているコードへの変更は、マージ競合を招き、作業を重複させ、担当範囲を曖昧にします。パフォーマンスに関する変更は、すべての呼び出し元に影響します。担当者と調整するか、コードが安定するまで最適化を見送ってください。

  • メモリと CPU のトレードオフを無視しないでください - キャッシュはメモリと引き換えに速度を向上させます。上限のないメモ化は、長時間稼働するアプリケーションでメモリリークを引き起こします。CPU を2倍高速化しても、メモリ使用量が10倍になれば、OOM クラッシュや頻繁な GC の一時停止を招き、元の遅さより悪化する可能性があります。CPU とあわせてメモリ使用量もプロファイルしてください。キャッシュサイズに上限を設け、ライフサイクルに紐づくキャッシュには WeakMap を使用してください。

  • 環境を問わずパフォーマンスが同じだと思い込まないでください - V8 の最適化は、Node.js のバージョン(v18 と v20)、ブラウザー(Chrome と Safari)、アーキテクチャ(x64 と ARM)によって異なります。Chrome で3倍高速化する最適化でも、Safari では1.5倍遅くなる可能性があります。リリース前に、対象となるすべての環境でプロファイルしてください。環境固有の最適化には、フォールバック実装を用意してください。

  • 配列メソッドを連結しないでください(.filter().map().reduce()) - 各メソッドは中間配列を作成し、それぞれ別々に反復処理を行います。1万件の配列では、.filter().map() は、フィルターを通過する割合が50%の場合、1万件+5000件分の要素を割り当て、2回反復します。単一の reduce パスを使えば、1回の反復で中間割り当てをゼロにでき、ホットパスでは2~5倍の高速化が期待できます。

  • 繰り返し検索に Array.includes() を使わないでください - Array.includes() は O(n) の線形検索です。1000件の項目を100件の配列に対して検索すると、O(n×m) = 10万回の処理になります。代わりに Set.has() を使ってください。ハッシュテーブルによる O(1) の検索で、処理回数を10万回から1000回に減らし、約100倍の高速化を実現できます。事前に一度だけ Set を作成すれば、償却コストは無視できる程度です。

  • 結果が必要か確認する前に、await してはいけません - 値が不要な場合でも、await は直ちに実行を一時停止します。実際に結果を使う条件分岐の中に await を移動してください。例:const data = await fetch(url); if (condition) { use(data); } は、condition が false のときに I/O 時間を無駄にします。より良い方法は、if (condition) { const data = await fetch(url); use(data); } です。結果が不要な場合は fetch 自体を省略できます。

  • ループ内で定数を再計算してはいけません - 不変値を再計算すると、反復ごとに CPU を浪費します。1 万回の反復では、エンジンがキャッシュしている場合でも array.length の参照や Math.max(a, b) の実行が 1 万回発生し、不要なコストになります。不変値はループの外に移動してください。例:const len = array.length; for (let i = 0; i < len; i++)、または関数をカリー化して定数のパラメーターを一度だけ事前計算します。

  • 上限のないループやキューを作成してはいけません - バグや悪意のある入力によるリソースの暴走を防ぎます。明示的な上限(for (let i = 0; i < Math.min(items.length, 10000); i++))またはタイムアウトを設定してください。上限のないループは UI スレッドをフリーズさせる可能性があり、上限のないキューは OOM クラッシュの原因になります。使いものにならない状態まで徐々に劣化させるのではなく、明確な上限を設けて速やかに失敗させてください。

  • ホットパスに try/catch を置いてはいけません - V8 は try-catch ブロックを含む関数をインライン化できず、関数全体を最適化対象外として扱います。ホットループ内に try-catch が 1 つあるだけで、インライン化、エスケープ解析、その他の最適化が妨げられ、処理速度が 3~5 倍低下します。型ガードを使用してホットパスの前に入力を検証してください。try-catch はループの外に移動して処理全体を囲むか、想定されるエラーには Result 型を使用してください。

パフォーマンスを最適化する前に確認すること

次の確認項目を使って、最適化の取り組みを効果的に優先順位付けしてください。

影響の評価
  • このコードは実際に遅いですか? プロファイリングデータがある場合は、それを参考に優先順位を決めてください。データがない場合は、すべてのコードを監査してアンチパターンを確認してください。
  • 実行時間の何パーセントを占めていますか? プロファイリングデータがある場合は、フレームグラフを使って影響の大きい問題を特定できます。データがない場合は、見つかったアンチパターンをすべて報告してください。
  • 生のパフォーマンスが重要です - 現在の使用状況にかかわらず、すべてのコードを監査してパフォーマンスのアンチパターンを確認してください。ユーティリティ関数、フォーマッター、パーサー、データ変換処理は、一見単純に見えても、ループ、レンダリングパイプライン、リアルタイムシステムで頻繁に呼び出されます。
正確性の検証
  • このコードを対象とするテストはありますか? パフォーマンスの不具合は見つけにくいものです。包括的なテストがあれば、最適化によるリグレッションを検出できます。最適化する前にテストを追加してください。
  • エッジケースは何ですか? オフバイワンエラー、空の配列、null/undefined の値は、手動でループを最適化すると発生しやすくなります。徹底的にテストしてください。
複雑さとメリット
  • アルゴリズムの計算量は最適ですか? O(n) → O(1) なら速度は 1000 倍になります。マイクロ最適化で得られる速度向上は、最大でも 1.1~2 倍です。まずアルゴリズムを改善してください。
  • この最適化は長く維持されますか? コードが頻繁に変更される場合、最適化はすぐに破棄される可能性があります。まず安定したコードを最適化してください。
  • 可読性への影響はどの程度ですか? 手動のループは .map() より高速ですが、保守が難しくなります。パフォーマンスとチームの開発速度のバランスを取ってください。

使用方法

このスキルでは、コンテキストの使用量を最小限に抑えるため、段階的な開示を採用しています。

1. ワークフローから始める(SKILL.md)

以下の 4 フェーズの監査ワークフローに従い、体系的にパフォーマンスを分析してください。

2. パフォーマンスルールの概要を参照する(AGENTS.md)

AGENTS.md を読み込み、カテゴリ別に整理された簡潔なルールの概要を確認してください。

3. 必要に応じて具体的なパフォーマンスパターンを読み込む

具体的なパフォーマンスの問題を特定したら、該当するリファレンスファイルを読み込み、詳細な ❌/✅ の例を確認してください。

4. レポートテンプレートを使用する(明示的に監査を依頼された場合)

ユーザーからパフォーマンス監査を明示的に依頼された場合は、テンプレートを読み込み、一貫性のあるレポートを作成してください。

パフォーマンス最適化ワークフロー

2 つの動作モード:

  1. 監査モード - スキルが直接呼び出された場合(/accelint-ts-performance <path>)、またはユーザーが明示的にパフォーマンス監査を依頼した場合

    • テンプレートを使って構造化された監査レポートを作成します(フェーズ 1~2 のみ)
    • 実装前に、ユーザーが確認できるように調査結果を報告します
    • どの最適化を適用するかは、ユーザーが決定します
  2. 実装モード - 機能の作業中にスキルが自動的に起動した場合

    • 最適化を特定し、直接適用します(全 4 フェーズ)
    • 正式なレポートは不要です
    • 問題をその場で修正することに集中します

進捗を記録するには、このチェックリストをコピーしてください:

- [ ] Phase 1: Profile - Identify actual bottlenecks using profiling tools
- [ ] Phase 2: Analyze - Categorize issues by impact and optimization category
- [ ] Phase 3: Optimize - Apply performance patterns from references/
- [ ] Phase 4: Verify - Measure improvements and validate correctness
フェーズ 1:ボトルネックの特定に向けたプロファイリング

重要:パフォーマンスのアンチパターンについて、すべてのコードを監査してください。 使用頻度に関する推測に基づいてコードを調査対象から外さないでください。ユーティリティ関数、フォーマッター、パーサー、バリデーター、データ変換処理は、実装が単純に見えても、ループ、レンダリングパイプライン、リアルタイムシステムで頻繁に呼び出されることがあります。

プロファイリングツールを利用できる場合は、ベースラインの測定に使用してください:

  • ブラウザー:Chrome DevTools の Performance タブ
  • Node.js:node --prof script.js && node --prof-process isolate-*.log

プロファイリングデータの有無にかかわらず、体系的な静的コード分析を行い、パフォーマンスのアンチパターンをすべて特定してください:

  • O(n²) の計算量(ネストされたループ、検索の繰り返し)
  • 過剰なメモリ割り当て(テンプレートリテラル、オブジェクトスプレッド、配列メソッド)
  • String() で十分な箇所でのテンプレートリテラルの割り当て
  • 配列メソッドのチェーン(.filter().map())
  • 非同期処理のブロッキング
  • ループ内の try/catch

出力:特定されたすべてのアンチパターンの完全な一覧と、それぞれの場所および想定されるパフォーマンスへの影響を記載します。「重大度」や「優先度」に基づいて絞り込まず、見つかったものをすべて報告してください。

監査レポートを作成する場合(スキルが /accelint-ts-performance <path> で直接呼び出された場合、またはユーザーが明示的にパフォーマンス監査を依頼した場合)は、構造化テンプレートを使用してください:

  1. レポートの構成については、assets/output-report-template.md を読み込みます
  2. 一貫した書式設定と問題のグループ化のため、テンプレートのガイダンスに従います
フェーズ 2:問題の分析と分類

フェーズ 1 で特定したすべての問題について、最適化の種類ごとに分類します:

すべての問題を最適化の種類ごとに分類してください:

問題の種類カテゴリー想定される効果
ネストされたループ、O(n²) の計算量アルゴリズムの最適化10-1000x
高コストな計算の繰り返しキャッシュとメモ化2-100x
メモリ割り当ての多いコードメモリ割り当ての削減1.5-5x
連続アクセスの違反メモリ局所性1.5-3x
過剰な I/O 操作I/O の最適化5-50x
非同期処理のブロッキングI/O の最適化2-10x
ループ内のプロパティアクセスキャッシュとメモ化1.2-2x

問題の分類に関するクイックリファレンス:

問題とカテゴリーの詳細な対応付け、およびアンチパターンの検出については、references/quick-reference.md を読み込みます。

出力: すべての問題を最適化カテゴリーごとに分類した一覧を作成します。フェーズ 1 で見つかった内容を絞り込んだり、優先順位を付けたりせず、すべて列挙してください。

フェーズ 3:パフォーマンスパターンを使用して最適化する

ステップ 1: フェーズ 2 の分析に基づき、ボトルネックのカテゴリを特定します。

ステップ 2: 該当するカテゴリの必須リファレンスを読み込みます。範囲制限を設けず、各ファイルを最後まで読みます。

カテゴリ必須ファイル任意読み込まないファイル
アルゴリズム(O(n²)、ネストしたループ、ルックアップの繰り返し)reduce-looping.md
reduce-branching.md
—memoization、caching、I/O、allocation
キャッシュ(ループ内のプロパティアクセス、計算の繰り返し)memoization.md
cache-property-access.md
cache-storage-api.md(Storage API の場合)I/O、allocation
I/O(非同期処理のブロック、過剰な I/O 操作)batching.md
defer-await.md
—algorithmic、memory
メモリ(割り当ての多さ、GC の負荷)object-operations.md
avoid-allocations.md
—I/O、caching
局所性(逐次アクセスの違反、キャッシュミス)predictable-execution.md—その他すべて
安全性(上限のないループ、制御不能なキュー)bounded-iteration.md—その他すべて
マイクロ最適化(ホットパスの微調整、1.1~2 倍の改善)currying.md
performance-misc.md
—その他すべて(アルゴリズム上の修正後にのみ適用)

注:

  • ボトルネックが複数のカテゴリにまたがる場合は、該当するすべてのカテゴリのリファレンスを読み込みます
  • マイクロ最適化を適用するのは、ボトルネックがホットパスにあり、アルゴリズム上の最適化をすでに適用していて、さらに 1.1~2 倍のパフォーマンス向上が必要な場合に限ります

ステップ 3:最適化中にクイックリファレンスを確認する

AGENTS.md を読み込み、カテゴリ別に整理されたルールの要約を確認します。上記の詳細なリファレンスファイルのパターンを実装する際のクイックリファレンスとして活用します。

パターンを体系的に適用します:

  1. 特定した問題カテゴリのリファレンスファイルを読み込みます
  2. ❌/✅ の例を確認し、一致するパターンを探します
  3. 正しさを保つため、変更を最小限に抑えて最適化を適用します
  4. 最適化の内容と参照したパターンを説明するコメントを追加します

最適化の例:

// ❌ Before: O(n²) - nested iteration
for (const user of users) {
  const items = allItems.filter(item => item.userId === user.id);
  process(items);
}

// ✅ After: O(n) - single pass with Map lookup
// Performance: reduce-looping.md - build lookup once pattern
const itemsByUser = new Map<string, Item[]>();
for (const item of allItems) {
  if (!itemsByUser.has(item.userId)) {
    itemsByUser.set(item.userId, []);
  }
  itemsByUser.get(item.userId)!.push(item);
}

for (const user of users) {
  const items = itemsByUser.get(user.id) ?? [];
  process(items);
}
フェーズ 4:改善を検証する

パフォーマンス向上を測定します:

  1. 同じ入力を使用してプロファイラーを再実行します
  2. 実行時間の割合を最適化前後で比較します
  3. 高速化率を記録します(例:「2.3 倍高速」)

正しさを検証します:

  1. 既存のテストスイートを実行します。すべてのテストに合格する必要があります
  2. 最適化によって影響を受けるエッジケースのテストを新たに追加します
  3. ユーザー向けの機能を手動でテストします

最適化を記録します:

// Performance optimization applied: 2026-01-28
// Issue: Nested iteration causing O(n²) complexity with 10k items
// Pattern: reduce-looping.md - Map-based lookup
// Speedup: 145x faster (5200ms → 36ms)
// Verified: All tests pass, manual QA complete

最適化を維持するかどうかの判断:

  • 10 倍を超える高速化: テストに合格すれば常に維持します
  • 2~10 倍の高速化: テストに合格し、コードの保守性が保たれる場合は維持します
  • 1.2~2 倍の高速化: ホットパス(1 秒あたり 1,000 回を超える実行)またはリアルタイムシステムの場合は維持します
  • 1.05~1.2 倍の高速化: 変更がごくわずかな場合、または重要なレンダリング/アニメーションループの場合に限り維持します
  • 1.05 倍未満の高速化: 可読性も向上する場合を除き、元に戻します

リアルタイムシステム(60fps のレンダリング、ライブデータの可視化): 重要なホットパスでは、1.05 倍の改善でも効果があります。フレームタイミングプロファイラーを使用して、フレーム予算(60fps では 16.67ms)への影響を検証します。

テストが失敗した場合: 最適化を修正するか、元に戻します。パフォーマンスの問題もバグです。

自由度の調整

最適化による効果に応じて、ガイダンスの具体性を調整します:

最適化の種類自由度ガイダンスの形式例
アルゴリズム(10倍以上の改善)中程度複数の有効なアプローチを示し、制約に応じて選択「O(1)で検索するにはMap、重複を除去するにはSetを使用します」
キャッシュ(2~10倍の改善)中程度例を含むパターンと、キャッシュ無効化戦略「ライフサイクルがソースオブジェクトと一致する場合は、WeakMapでメモ化します」
マイクロ最適化(1.1~2倍)低いリファレンスにある正確なパターンを使用し、まず測定する「ループ内でarray.lengthをキャッシュします:for (let i = 0, len = arr.length; ...)」

判断基準:「高速化の効果と保守コストはどれくらいですか?」

  • 10倍以上の高速化 → 複雑さに見合う価値があります。パターンを示し、自由度は中程度にします
  • 2~10倍の高速化 → 測定結果で正当性を示し、自由度は中程度にします
  • 1.2~2倍の高速化 → ホットパスやリアルタイムシステムでは価値があります。正確なパターンを示し、自由度は低くします
  • 1.05~1.2倍の高速化 → 変更がごく簡単な場合、または重要なホットパス(60fpsの描画など)に限ります

重要な注意事項

  • すべてを監査する方針 - パフォーマンス上のアンチパターンがないか、すべてのコードを監査します。ユーティリティ関数、フォーマッター、パーサー、バリデーターは、一見単純でも、ループ内やリアルタイムシステムで頻繁に呼び出されます。使用頻度を推測で判断しないでください。
  • すべての検出結果を報告する - プロファイリングデータの有無にかかわらず、体系的な静的解析を行い、予想される改善幅とともに、すべてのアンチパターンを特定して報告します。「深刻度」や「優先度」を基準に除外しないでください。
  • リファレンスファイルは権威ある情報源です - references/ にあるパターンは検証済みです。測定結果で誤りが証明されない限り、正確に従ってください。
  • ホットパスの定義 - ユーザー操作1回あたり1,000回を超えて実行されるコード、またはサーバーのコンテキストで1秒あたり100回を超えて実行されるコードです。リアルタイムシステム(60fpsの描画、ライブ可視化など)では、1フレームあたり1msを超えて消費するクリティカルな描画ループ内の関数がホットパスです。
  • リアルタイムシステムには、より厳しい要件があります - 60fpsのフレーム予算は16.67ms、120fpsでは8.33msです。ホットパスでは、1.05倍の改善でも価値があります。実行時間の合計だけでなく、フレーム時間を計測してプロファイリングしてください。
  • リグレッションテスト - パフォーマンス最適化では、エッジケースで微妙なバグが発生することがよくあります。最適化の前にテストを追加してください。
  • メモリのプロファイリングも重要です - メモ化やキャッシュなどの最適化では、速度と引き換えにメモリを使用することがあります。本番環境でのメモリ使用量を監視してください。特に、長時間稼働するリアルタイムアプリケーションでは重要です。

クイック判断ツリー

この表を使って、どの最適化カテゴリが該当するかをすばやく特定してください。

すべてを監査する:現在の使用状況にかかわらず、コード内のパフォーマンス上のアンチパターンをすべて特定します。期待される改善効果とともに、すべての検出結果を報告してください。

次のような場合...根本原因最適化カテゴリ期待される改善効果
同じデータに対するネストされた for ループO(n²) の計算量アルゴリズム(ループの削減)10~1000倍
.filter() の後に .find() または .map() を実行データを複数回走査アルゴリズム(ループの削減)2~10倍
array.find() または .includes() を何度も実行O(n) の線形探索アルゴリズム(ループの削減、Set/Map の使用)10~100倍
同じ変数に対する if/else チェーンが多い分岐の多いコードアルゴリズム(分岐の削減)1.5~3倍
同じ入力で同じ関数を繰り返し呼び出す冗長な計算キャッシュ(メモ化)2~100倍
ループ内で obj.prop.nested.deep に複数回アクセスプロパティアクセスのオーバーヘッドキャッシュ(プロパティアクセスのキャッシュ)1.2~2倍
ループ内で localStorage.getItem() または sessionStorage を使用ループ内の高コストな I/Oキャッシュ(ストレージ API のキャッシュ)5~20倍
複数の await fetch() を順番に実行I/O の逐次処理によるブロックI/O(バッチ処理、await の遅延)2~10倍
結果が不要な可能性のある条件分岐の前に await を実行早すぎる非同期処理の中断I/O(await の遅延)1.5~3倍
オブジェクトスプレッド {...obj} または配列スプレッド [...arr] を多用メモリ割り当てのオーバーヘッドメモリ(割り当ての回避)1.5~5倍
高頻度で実行されるループ内でオブジェクトや配列を作成メモリ割り当てによる GC 負荷メモリ(割り当ての回避)2~5倍
変更しても問題ない場面で Object.assign() またはスプレッド構文を使用不要なイミュータブル処理のコストメモリ(オブジェクト操作)1.5~3倍
配列要素に順不同でアクセスキャッシュ局所性の問題メモリ局所性(予測可能な実行)1.5~3倍
while(true) または上限のないキューの増大リソース使用量の暴走安全性(反復回数の制限)クラッシュを防止
最初の N 個の引数の大半が同じ状態で関数を呼び出す引数の受け渡しの繰り返しマイクロ最適化(カリー化)1.1~1.5倍
高頻度で実行されるループ内に try/catch があるV8 の最適化解除マイクロ最適化(パフォーマンスその他)3~5倍
ループ内で + による文字列連結二次的な文字列コピーマイクロ最適化(パフォーマンスその他)2~10倍

この表の使い方:

  1. プロファイラーで特定したボトルネックからパターンを識別します
  2. 「次のような場合...」列で該当する行を見つけます
  3. フェーズ 3 の対応する最適化カテゴリに進みます
  4. そのカテゴリの必須リファレンスファイルを読み込みます

コメント