Debug Mode
実行時証拠に基づく構造化デバッグ。 推測するな。観察せよ。
基本原則
-
ログなしに修正なし — コードを読むだけでは不十分
-
複数の仮説 — 最低3つ、理想は5つ
-
証拠に基づく判定 — CONFIRMED / REJECTED / INCONCLUSIVE
-
検証前にクリーンアップしない — 修正が確認されるまで計装を残す
ワークフロー
問題把握 → ログ準備 → 仮説生成 → 計装挿入 → ログクリア → 再現 → 分析 → 修正 → 検証 → クリーンアップ
Step 1: 問題を理解する
ユーザーから以下を聞き取る(不明なら質問する):
-
症状(期待した動作 vs 実際の動作)
-
再現手順
-
最近の変更
Step 2: ログ収集の準備
環境に応じて選択する。ログフォーマットとregion構文は references/common.md を参照。
言語別パターン:
- JavaScript/TypeScript
ブラウザ(React): コレクターサーバーを起動
node -e "require('http').createServer((q,s)=>{s.setHeader('Access-Control-Allow-Origin','*');s.setHeader('Access-Control-Allow-Methods','POST,OPTIONS');s.setHeader('Access-Control-Allow-Headers','Content-Type');if(q.method==='OPTIONS'){s.writeHead(204).end();return}let b='';q.on('data',c=>b+=c);q.on('end',()=>{require('fs').appendFileSync('debug.log',b+'\n');s.writeHead(204).end()})}).listen(4567,()=>console.log('Collector: http://localhost:4567'))"
サーバーサイド(Node.js / Lambda): ファイル直接書き込み。サーバー不要。
Step 3: 仮説を立てる
3-5個の仮説を生成する。1つに固執しない。
仮説
H1: [タイトル]
- 原因: ...
- 検証方法: XをYの前後で確認する
H2: [タイトル]
- 原因: ...
- 検証方法: ...
H3: [タイトル]
- 原因: ...
- 検証方法: ...
Step 4: 計装を挿入する
各仮説に対応するログを挿入する。3-8箇所。
計装ポイント:
-
関数の入口(引数)
-
関数の出口(戻り値)
-
重要な処理の前後
-
分岐パス(どのif/elseを通ったか)
-
状態変更の前後
必須: #region debug:{hypothesisId} で囲む
テンプレートは言語別リファレンスを参照。
Step 5: 古いログを削除
rm -f debug.log
Step 6: 再現を依頼する
再現手順
- ログ収集の準備ができていることを確認(必要ならコレクターを起動)
debug.logが削除されていることを確認- アプリを起動/再起動
- [バグを発生させる具体的な操作]
- 完了したら教えてください
Step 7: ログを分析する
cat debug.log | jq . # 全件表示 jq 'select(.h == "H1")' debug.log # 仮説でフィルタ cat debug.log | jq -s 'group_by(.h)' # 仮説ごとにグルーピング tail -f debug.log | jq . # リアルタイム
各仮説を評価する:
判定 意味
CONFIRMED ログがこの仮説を明確に支持する
REJECTED ログがこの仮説と矛盾する
INCONCLUSIVE データ不足で判断できない
Step 8: 修正する
仮説がCONFIRMEDの場合のみ。
-
根本原因を修正する。症状が出た箇所ではなく、原因の発生元を直す
-
エラーが出た関数をtry-catchで握り潰すのは修正ではない
-
不正な値が渡されるなら、渡す側を直す(受け取る側でガードするだけでは対症療法)
-
コールチェーンを遡り、最初に問題が発生した地点を特定してそこを修正する
根本原因が実装方針の誤りだった場合: 勝手に直さず、ユーザーに報告する。
以下の構造で説明し、修正方針の判断をユーザーに委ねる:
調査結果
現状(何がどうなっているか)
- [コードの現在の実装・データフローを事実として記述]
不一致(なぜバグになるか)
- [ユーザーが期待する動作と、現状の実装がどう矛盾しているか]
修正案(どこをどう変える必要があるか)
-
[修正が必要なファイル・関数・ロジックと、変更内容の概要]
-
[影響範囲があれば明記]
-
最小限の差分で修正する
-
計装はそのまま残す
全仮説がREJECTEDの場合: 別のサブシステムに着目して新しい仮説を立てる → Step 3へ。
修正が3回失敗した場合: 立ち止まる。個別のバグではなくアーキテクチャの問題を疑う。ユーザーに状況を共有し、方針を相談する。
Step 9: 検証する
rm -f debug.log- アプリを再起動
- 同じ操作を実行
- 完了したら教えてください
修正前後のログを比較する。
Step 10: クリーンアップ
ユーザーが修正の動作を確認した後にのみ実施。
grep -rn "#region debug:" src/
計装コードを削除し、debug.log を削除し、コレクターを停止する。
ログフォーマット
NDJSON(1行1JSON):
{"h":"H1","l":"state_before","v":{"userId":"123"},"ts":1702567890123}
フィールド 意味
h 仮説ID
l ラベル
v 値
ts タイムスタンプ(ms)
禁止事項
-
ログ分析前に修正を提案すること
-
仮説を1つしか立てないこと
-
検証前に計装を削除すること
-
「たぶんこれ」という推測
-
setTimeout/sleep による「修正」
-
対症療法的な修正(エラーを握り潰す、表示を隠す、条件分岐で回避する等)
リファレンス
-
references/common.md — ログフォーマット、region構文
-
references/javascript.md — JavaScript/TypeScript