Claude Codeで200コンポーネントを一括修正した実録 — バグ分類・修正・検証の全工程
このトピックを深掘りする
Claude Code活用
Claude Codeを使った大規模リファクタリング・CLAUDE.md設計・セッション管理の実践知
全4本中 1 本目。
次に読む記事
CLAUDE.mdを育てる — AIコラボレーション設定ファイルの3ヶ月の変遷
323コミットのプロジェクトでCLAUDE.mdを3ヶ月間更新し続けた記録。効いたルール、効かなかったルール、そして「助言的」設定の限界。
1セッション1タスク — Claude Codeのコンテキスト管理で学んだ原則
Claude Codeで203コンポーネントを開発する中で、「1セッション1タスク」が最も生産性に効いた原則だった。コンテキスト枯渇の実例と対策。
AIが量産するコードの品質をどう担保するか — 200コンポーネントで運用する4層の品質ゲート
約200個のインタラクティブコンポーネントをAI駆動で量産・運用しているサイトの品質担保の実構成。pre-commitフック4本・データ不変条件テスト・ブラウザ実機スモーク・品質スコア+PR提案の4層を、構成ファイル名のレベルで公開する。
シリーズ全体の流れを見ながら、次に読む記事へ進めます。 初めての方はホームへ →
はじめに
このポートフォリオサイトには211個のインタラクティブコンポーネントがある。流体シミュレーション、ピアノ、迷路生成、ピンボール——ブラウザ上で動く小さなデモを次々と追加してきた結果だ。
問題は、これだけの数になるとバグも比例して増えることだ。setTimeout のリーク、AudioContext の未ハンドル例外、NaN が Canvas に流れ込む数値安全性の欠如。1つ1つは小さいが、211ファイルを手動で点検して直すのは現実的ではない。
そこでClaude Codeを使い、6コミットで延べ100+コンポーネントを一括修正した。この記事はその実録だ。何が効いて、何が失敗したかを、コミットハッシュとファイル数の実データとともに共有する。
一括修正の実績データ
まず結果から示す。以下は実際のコミットログから抽出したデータだ。
08925bcb— 31ファイル: リソースリーク、コード品質、安全性の包括修正04163d8e— 18ファイル: AudioContext エラーハンドリング、mountedRef ガード、clipboard 安全性f51f0c83— 15ファイル: モジュールレベル可変状態の排除、レンダーパフォーマンス最適化1fc14711— 8ファイル: 数値安全性ガード、Canvas サイズバリデーション、システム設定追跡7723cfaf— 16コンポーネント: passive event listener 追加、touch-action 設定、Pointer Events 統一e129df45— 7コンポーネント: キーボードアクセシビリティ対応
合計で95ファイル以上を修正した。各コミットは1つのバグカテゴリに絞っている。これが精度を保つための最も重要な判断だった。
ワークフロー: 「分類 → 一括適用 → 検証」
一括修正は4ステップで進めた。
1. バグの分類
最初にやるのは「パターンの発見」だ。211コンポーネントを眺めて、繰り返し現れるバグを分類する。
実際に見つかったパターンの例:
- setTimeout/setInterval リーク:
useEffectの cleanup でclearTimeoutしていない - AudioContext 未ハンドル: ユーザーインタラクション前の
new AudioContext()が例外を投げる - NaN 伝播:
canvas.widthが 0 のとき1 / widthがInfinityになり描画が壊れる - モジュールレベル状態: ファイルスコープで
let count = 0のように状態を持つとHMRで壊れる - mouse → pointer 未統一:
onMouseDownとonTouchStartを別々に書いている(Pointer Eventsに統一すべき)
この分類フェーズは人間がやる。Claude Code はパターンの「発見」よりも「大量適用」が得意だからだ。
2. 修正テンプレートの定義
分類ができたら、各パターンに対して「こう直す」というテンプレートを定義する。
例えば AudioContext の修正テンプレート:
// Before: 例外が投げられる可能性
const ctx = new AudioContext()
// After: try-catch + resume() ガード
let ctx: AudioContext | null = null
try {
ctx = new AudioContext()
if (ctx.state === 'suspended') {
await ctx.resume()
}
} catch (e) {
console.warn('AudioContext initialization failed:', e)
}数値安全性のテンプレート:
// Before: NaN/Infinity が伝播する
const scale = 1 / canvas.width
// After: ガード付き
const scale = canvas.width > 0 ? 1 / canvas.width : 1このテンプレートを CLAUDE.md に記述しておくと、Claude Code が全ファイルに一貫して適用してくれる。
3. 一括適用
Claude Code にパターンとテンプレートを渡し、「このパターンに該当する全ファイルを修正して」と指示する。
ここで重要なのは 1回のセッションで1カテゴリだけ を扱うことだ。「AudioContext の修正」と「passive listener の追加」を同時に頼むと、見落としが発生する。コンテキストウィンドウは最も希少なリソースだ。
実際のセッションの流れ:
- 対象パターンを説明(テンプレート付き)
- Claude Code が該当ファイルを走査
- 修正を適用
- ビルドが通ることを確認
- 1コミット
4. 検証
bun run build で TypeScript の型チェックとビルドを通す。これが最低限のバリデーションだ。加えて、修正カテゴリによっては手動確認も行う。
- Canvas 系の修正 → ブラウザで実際に描画を確認
- AudioContext 系 → Safari と Chrome で音声再生を確認
- アクセシビリティ系 → キーボードのみで操作を確認
全自動にはできないが、「バグカテゴリごとに確認観点が決まっている」ので効率は良い。
効いたプラクティス
6回のバルクフィックスを通じて学んだ、効果の高いプラクティスを4つ挙げる。
バリデーション先行
テストやビルドチェックを先に整備してから Claude Code に渡すと、品質が体感で2-3倍になる。AI は「何が正解か」を判定する手段があると、自己修正のループが回る。
逆に、バリデーション手段がないと「見た目は正しそうだが実は壊れている」コードが増える。vitest を導入して97テストを一括追加したのも、この考え方に基づいている。
1セッション1タスク
先述の通り、1回のセッションでは1つのバグカテゴリだけを扱う。コミット f51f0c83(モジュールレベル状態の排除、15ファイル)と 04163d8e(AudioContext 修正、18ファイル)は別セッションで実行した。
混ぜると精度が下がるだけでなく、レビューも困難になる。「このコミットで何が変わったか」が一目でわかる粒度を保つことが重要だ。
パターンの名指し
「このファイルと同じパターンで修正して」が最も精度が高い指示方法だ。例えば:
Match3.tsx の AudioContext 修正パターンを参照して、残りの17ファイルに同じ修正を適用して。
抽象的な説明よりも、具体的なコード例を1つ渡す方が圧倒的に再現性が高い。
レビュー視点の分離
コードレベル(微視的)のレビューと仕様レベル(巨視的)のレビューは別々に行う。
- 微視的: 「
clearTimeoutが正しく呼ばれているか」「nullチェックが漏れていないか」 - 巨視的: 「この修正でユーザー体験が変わっていないか」「パフォーマンスに影響はないか」
1つのレビューで両方を見ようとすると、どちらも中途半端になる。
失敗したこと
成功談だけでは不誠実なので、失敗も共有する。
「全部直して」は機能しない
最初の試みでは、「全コンポーネントのバグを全部直して」と丸投げした。結果は散々だった。スコープが広すぎて、修正の粒度がバラバラになり、一部は過剰な書き換え、一部は見落としという状態に。
ここから「1カテゴリ1コミット」のルールが生まれた。
バグカテゴリの混合
初期のコミット 08925bcb(31ファイル)は実は「リソースリーク、コード品質、安全性」と3カテゴリが混在している。このコミットのレビューは他の5つと比べて明らかに時間がかかった。後の5コミットでは1カテゴリに絞った結果、レビュー時間が大幅に短縮された。
CLAUDE.md の肥大化
プロジェクトの CLAUDE.md にルールを追加し続けると、ある時点から効かなくなる。ルールが多すぎてコンテキスト内で競合するのだ。
対策として定期的な棚卸しを行い、「もう該当するコードがないルール」や「一般的すぎて意味がないルール」を削除している。hooksは決定論的に動くが、CLAUDE.md は助言的にしか機能しない。効かないルールは削除が最善だ。
定量的な結果
プロジェクト全体の数字を共有する。
- 総コミット数: 323
- Claude co-authored コミット: 82(約25%)
- バッチフィーチャーコミット: 21回(各5コンポーネントずつ新規追加)
- バルクフィックスコミット: 6回(合計100+コンポーネント修正)
- テスト一括追加: 97テスト(vitest 導入時)
注目すべきは、コミットの25%が Claude との共著である一方、アーキテクチャ設計やワークフロー定義は100%人間が行っている点だ。AI が書いたコードの品質を担保しているのは、人間が設計した「仕組み」だ。
AIとの分業モデル
6回のバルクフィックスを経て、AI との分業モデルが明確になった。
人間が担当すること:
- アーキテクチャ設計(Canvas vs DOM の判断、物理エンジンの設計)
- バグパターンの発見と分類
- ワークフローの定義(「1カテゴリ1コミット」などのルール)
- デザイン目標の設定(「滞在時間の最大化」という方針)
- 最終的な品質判断
AI が担当すること:
- パターンに基づく実装の大量適用
- リファクタリング(同じ変換を多数のファイルに適用)
- バグ修正(テンプレートが定義済みの場合)
- テストの一括生成
- コンテンツ生成
核心は「仕組みの中で AI を動かす」ことだ。テンプレート、ルール、パターンを人間が事前に定義し、AI は選択と配置に集中する。AI に「何を作るか」を考えさせるのではなく、「定義済みのパターンをどこに適用するか」を判断させる。
これは工場のラインに似ている。設計図は人間が書く。AI は設計図に従って組み立てる。設計図の品質がそのまま成果物の品質になる。
まとめ:Claude Code一括修正
211コンポーネントのバルクフィックスで学んだことを3つに絞る。
1. AI は「パターンの大量適用」が最も得意
18ファイルに同じ AudioContext 修正を適用する、16コンポーネントの mouse events を pointer events に書き換える——こうした反復作業での AI の精度と速度は、人間を圧倒する。
2. 人間は「パターンの発見と定義」に集中すべき
「setTimeout リークがある」と気づくのは人間の仕事だ。「useEffect の cleanup に clearTimeout を追加する」というテンプレートを書くのも人間の仕事だ。AI にパターンを発見させようとすると、精度が大幅に下がる。
3. バルクフィックスの秘訣は「分類の粒度」
1コミットに1カテゴリ。これが全てだ。スコープを狭く保てば、AI の精度は上がり、レビューは楽になり、問題が起きたときのロールバックも容易になる。
200コンポーネントを1つずつ直す必要はない。正しく分類すれば、6回の操作で済む。