mcpField
D
debugging

debugging

github.com/mgd34msu開発664 回インストール10 週間前に更新
リポジトリ

debugging について

debuggingは、実行時エラーや予期しない挙動、ビルド問題を調べる開発者向けの、GoodVibes用デバッグスキルです。再現、切り分け、根本原因の特定、修正、検証の手順を示し、ネットワークや状態の調査も扱います。

主な機能

  1. 01段階的なデバッグ手順
  2. 02エラー情報とスタックトレースの分析
  3. 03データフローと境界条件の追跡
  4. 04依存関係、インポート、型の確認
  5. 05型チェックとテストによる修正検証
  6. 06ネットワークと状態の問題調査

活用シーン

  1. 01TypeScriptの型エラーの特定
  2. 02実行時例外やロジック不具合の調査
  3. 03APIリクエストとレスポンスの障害分析
  4. 04ビルドエラーや性能上のボトルネックの発見

インストール

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

$npx skills add https://github.com/mgd34msu/goodvibes-plugin --skill debugging

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

同梱ファイルreferences/debugging-patterns.mdscripts/validate-debugging.sh

詳細

リソース

scripts/
  validate-debugging.sh
references/
  debugging-patterns.md

デバッグ品質スキル

このスキルでは、GoodVibes の高精度ツールを使って体系的にデバッグする方法を学びます。効果的なデバッグには、問題を再現し、原因を切り分け、根本的な問題を特定し、修正を適用して、解決策を検証するという手順が必要です。

このスキルを使用する場面

次のような場合に、このスキルを読み込んでください。

  • ランタイムエラーや例外を調査するとき
  • 予期しない動作やロジックエラーを追跡するとき
  • ネットワークリクエスト/レスポンスの問題を分析するとき
  • 状態管理の問題をデバッグするとき
  • パフォーマンスのボトルネックを診断するとき
  • ビルドエラーやコンパイルエラーを調査するとき
  • TypeScript の型エラーを理解するとき
  • 根本原因分析を実施するとき

トリガーフレーズ:「このエラーをデバッグして」「なぜ失敗するのか」「問題を調査して」「問題を追跡して」「エラーを分析して」。

基本的なワークフロー

フェーズ 1:再現 — 問題を確認する

デバッグを始める前に、問題を確実に再現できることを確認します。

ステップ 1.1:エラーのコンテキストを収集する

利用可能なエラー情報をすべて収集します。

precision_exec:
  commands:
    - cmd: "npm run typecheck 2>&1"
    - cmd: "npm run lint 2>&1"
    - cmd: "npm run build 2>&1"
  verbosity: standard

記録する情報:

  • エラーメッセージとスタックトレース全体
  • エラーの種類とコード(該当する場合)
  • ファイルパスと行番号
  • タイムスタンプと環境情報
  • エラーを引き起こしたユーザー操作
ステップ 1.2:エラーの発生箇所を探す

コードベース内で、類似するエラーを検索します。

discover:
  queries:
    - id: error_throw_sites
      type: grep
      pattern: "throw new (Error|TypeError|RangeError)"
      glob: "**/*.{ts,tsx,js,jsx}"
    - id: error_handlers
      type: grep
      pattern: "catch\\s*\\("
      glob: "**/*.{ts,tsx,js,jsx}"
    - id: console_errors
      type: grep
      pattern: "console\\.(error|warn)"
      glob: "**/*.{ts,tsx,js,jsx}"
  verbosity: locations

パターンのカテゴリ:

エラーパターン意味よくある原因
ReferenceError変数が定義されていないタイプミス、インポート漏れ、スコープの問題
TypeError誤った型が使用されているnull/undefined、誤ったメソッド、型の不一致
RangeError値が範囲外配列インデックス、数値のオーバーフロー
SyntaxError構文が無効パースエラー、不正な形式の JSON
NetworkErrorリクエストに失敗したCORS、タイムアウト、404、認証の失敗
ステップ 1.3:ローカルで再現する

失敗する操作を実行し、再現できることを確認します。

precision_exec:
  commands:
    - cmd: "npm run dev"
      timeout_ms: 5000
  verbosity: minimal

再現チェックリスト:

  • エラーが一貫して再現する
  • 再現するための最小限の手順を特定した
  • 環境が本番環境と一致している(Node のバージョン、依存関係)
  • エラーメッセージが報告された問題と一致している
フェーズ 2:切り分け — 原因を絞り込む

問題の範囲を狭め、エラーの発生元を見つけます。

ステップ 2.1:スタックトレースを読む

コールスタックを分析し、実行フローを理解します。

スタックトレースの例:

TypeError: Cannot read property 'name' of undefined
    at getUserName (src/utils/user.ts:42:18)
    at UserProfile (src/components/UserProfile.tsx:15:22)
    at renderWithHooks (node_modules/react/cjs/react.development.js:1234)

読み解く手順:

  1. 先頭から確認する — 実際のエラー箇所
  2. さかのぼって追跡する — 呼び出しチェーンをたどる
  3. node_modules は無視する — 自分のコードに注目する
  4. エントリーポイントを見つける — 不正なデータはどこから来たのか?
precision_read:
  files:
    - path: "src/utils/user.ts"
      extract: content
      range: {start: 35, end: 50}
    - path: "src/components/UserProfile.tsx"
      extract: content
      range: {start: 10, end: 25}
  verbosity: standard
ステップ 2.2:データフローを追跡する

データをソースからエラー箇所までたどります。

discover:
  queries:
    - id: function_calls
      type: grep
      pattern: "getUserName\\("
      glob: "**/*.{ts,tsx}"
    - id: data_sources
      type: grep
      pattern: "(fetch|axios|prisma).*user"
      glob: "**/*.{ts,tsx}"
    - id: prop_passing
      type: grep
      pattern: "user=\\{"
      glob: "**/*.tsx"
  verbosity: locations

データフローの分析:

  • データはどこから来るのか?(API、データベース、props)
  • どのような変換が行われるのか?(map、filter、分割代入)
  • どのような前提があるのか?(null ではない、特定の形状である)
  • どこで undefined になる可能性があるのか?
ステップ 2.3:境界条件を確認する

エラーがよく発生するエッジケースをテストします。

discover:
  queries:
    - id: array_access
      type: grep
      pattern: "\\[[0-9]+\\]|\\[.*\\]"
      glob: "**/*.{ts,tsx}"
    - id: null_checks
      type: grep
      pattern: "(if.*===.*null|if.*===.*undefined|\\?\\.|\\?\\?)"
      glob: "**/*.{ts,tsx}"
    - id: optional_chaining
      type: grep
      pattern: "\\?\\."
      glob: "**/*.{ts,tsx}"
  verbosity: locations

よくある境界条件の問題:

問題例修正方法
配列の範囲外arr[arr.length]arr.length > 0 を確認する
null/undefined へのアクセスuser.nameuser?.name を使用する
ゼロ除算total / countcount !== 0 を確認する
空文字列に対する操作str[0]str.length > 0 を確認する
オブジェクトキーの欠落obj.keyobj?.key ?? default を使用する
フェーズ 3:特定 — 根本原因を突き止める

症状だけでなく、根本的な問題を特定します。

ステップ 3.1:エラーパターンを分析する

よくある原因を把握するために、エラーを分類します。

型エラー

precision_exec:
  commands:
    - cmd: "npm run typecheck 2>&1 | head -50"
  verbosity: standard

よくある TypeScript エラー:

エラーコード意味修正方法
TS2339プロパティが存在しませんプロパティを型に追加するか、オプショナルチェーンを使用します
TS2345引数の型が一致しません型を修正するか、型アサーションを追加します
TS2322型を割り当てられません型を変更するか、値を修正します
TS2571オブジェクトの型が unknown です型ガードまたは型アサーションを追加します
TS7006パラメーターの型が暗黙的に any ですパラメーターの型注釈を追加します

実行時エラー

discover:
  queries:
    - id: unsafe_access
      type: grep
      pattern: "\\.[a-zA-Z]+(?!\\?)"
      glob: "**/*.{ts,tsx}"
    - id: async_errors
      type: grep
      pattern: "await.*(?!try)"
      glob: "**/*.{ts,tsx}"
  verbosity: files_only

よくある実行時エラー:

  • undefined のプロパティ X を読み取れません
  • null のプロパティ X を読み取れません
  • X は関数ではありません
  • X は反復可能ではありません
  • コールスタックの最大サイズを超過しました(無限再帰)
ステップ 3.2:依存関係とインポートを確認する

モジュール解決エラーはよく発生します。

discover:
  queries:
    - id: imports
      type: grep
      pattern: "^import.*from"
      glob: "**/*.{ts,tsx}"
    - id: dynamic_imports
      type: grep
      pattern: "import\\("
      glob: "**/*.{ts,tsx}"
    - id: require_statements
      type: grep
      pattern: "require\\("
      glob: "**/*.{ts,js}"
  verbosity: locations

よくあるインポートの問題:

問題症状修正方法
エクスポートがないモジュールにエクスポートされたメンバーがありませんソースファイルにエクスポートを追加します
循環依存初期化前にアクセスできませんインポートの構成を変更します
パスが間違っているモジュールが見つかりません相対パスまたはエイリアスを修正します
デフォルトと名前付きの違いX は関数ではありませんimport X または import { X } を使用します
型のみのインポート値として使用できませんtype キーワードを削除します
ステップ 3.3:前提を検証する

データの形状や状態に関する前提を見直します。

precision_grep:
  queries:
    - id: type_assertions
      pattern: "as (unknown|any|[A-Z][a-zA-Z]+)"
      glob: "**/*.{ts,tsx}"
  output:
    format: context
    context_before: 2
    context_after: 2
  verbosity: standard

危険な前提:

  • API は常に期待どおりの形状でデータを返す
  • 配列が空になることはない
  • ユーザーは常に認証済みである
  • データは常に有効である
  • Props は常に渡される

次の方法で検証します:

  • 実行時の型検証(Zod、Yup)
  • 型ガード(if (typeof x === 'string'))
  • null チェック(if (x != null))
  • デフォルト値(x ?? defaultValue)
フェーズ 4:修正 - 解決策を適用する

根本原因の分析に基づいて修正を実装します。

ステップ 4.1:適切な修正方法を選ぶ

問題の種類に合った修正方法を選びます。

型安全性の修正

// Before: Implicit any
function getUser(id) {
  return users.find(u => u.id === id);
}

// After: Explicit types
function getUser(id: string): User | undefined {
  return users.find(u => u.id === id);
}

null 安全性の修正

// Before: Unsafe access
const name = user.profile.name;

// After: Optional chaining
const name = user?.profile?.name ?? 'Anonymous';

非同期エラー処理

// Before: Unhandled promise
await fetchData();

// After: Try/catch
try {
  await fetchData();
} catch (error: unknown) {
  logger.error('Failed to fetch data', { error });
  throw new AppError('Data fetch failed', { cause: error });
}

配列の境界に関する修正

// Before: Unsafe access
const first = items[0];

// After: Safe access
const first = items.length > 0 ? items[0] : null;
// Or: const first = items.at(0) ?? null;
ステップ 4.2:防御的なコードを追加する

同様のエラーが今後発生しないようにします。

入力検証:

import { z } from 'zod';

const userSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  name: z.string().min(1).max(100),
});

function processUser(data: unknown) {
  const user = userSchema.parse(data); // Throws if invalid
  // Now user is type-safe
}

型ガード:

function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'email' in value
  );
}

if (isUser(data)) {
  // TypeScript knows data is User
  logger.info('User email', { email: data.email });
}

エラーバウンダリ(React):

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error }: { error: Error }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
    </div>
  );
}

<ErrorBoundary FallbackComponent={ErrorFallback}>
  <MyComponent />
</ErrorBoundary>
ステップ 4.3:修正を適用する

precision_edit を使用して変更します。

precision_edit:
  edits:
    - path: "src/utils/user.ts"
      find: |
        function getUserName(user) {
          return user.name;
        }
      replace: |
        function getUserName(user: User | undefined): string {
          return user?.name ?? 'Unknown';
        }
  verbosity: minimal
フェーズ 5:検証 - 修正が機能することを確認する

修正によって問題が解決し、ほかに問題が生じていないことを検証します。

ステップ 5.1:型チェック

TypeScript のエラーが解消されていることを確認します。

precision_exec:
  commands:
    - cmd: "npm run typecheck"
  verbosity: standard

すべての型エラーを解消する必要があります。

ステップ 5.2:テストを実行する

テストが成功することを確認します。

precision_exec:
  commands:
    - cmd: "npm test"
  verbosity: standard

テストが失敗した場合:

  • 修正によってリグレッションが発生した
  • テストの期待値を更新する必要がある
  • テストによって別の問題が見つかった
ステップ 5.3:手動で検証する

元のエラーが発生した状況を再現します。

precision_exec:
  commands:
    - cmd: "npm run dev"
      timeout_ms: 5000
  verbosity: minimal

検証チェックリスト:

  • 元のエラーが再発しない
  • エッジケースに対応している(null、空、大きな値)
  • 新たなエラーが発生していない
  • パフォーマンスが低下していない
  • ユーザーエクスペリエンスが向上している
フェーズ 6:ネットワークのデバッグ

API リクエストとレスポンスをデバッグします。

ステップ 6.1:ネットワーク呼び出しを見つける

すべての HTTP リクエストを特定します。

discover:
  queries:
    - id: fetch_calls
      type: grep
      pattern: "fetch\\("
      glob: "**/*.{ts,tsx,js,jsx}"
    - id: axios_calls
      type: grep
      pattern: "axios\\.(get|post|put|delete|patch)"
      glob: "**/*.{ts,tsx,js,jsx}"
    - id: api_routes
      type: glob
      patterns: ["src/app/api/**/*.ts", "pages/api/**/*.ts"]
  verbosity: locations
ステップ 6.2:リクエスト/レスポンスの処理を確認する

ネットワーク呼び出しのエラー処理を検証します。

precision_grep:
  queries:
    - id: fetch_with_catch
      pattern: "fetch\\([^)]+\\).*catch"
      glob: "**/*.{ts,tsx,js,jsx}"
  output:
    format: context
    context_after: 5
  verbosity: standard

よくあるネットワークの問題:

問題症状修正方法
CORS エラーCORS ポリシーによってブロックされたAPI に CORS ヘッダーを追加します
401 Unauthorizedトークンがないか無効認証ヘッダーを追加し、トークンを更新します
404 Not FoundURL またはルートが間違っているエンドポイントのパスを修正します
500 Server Errorバックエンドの例外サーバーログを確認し、バックエンドを修正します
タイムアウトリクエストに時間がかかりすぎるタイムアウトを延長し、バックエンドを最適化します
ネットワーク障害フェッチに失敗した接続を確認し、再試行ロジックを追加します

CORS のデバッグ:

// Next.js API route
export async function GET(request: Request) {
  return Response.json(data, {
    headers: {
      'Access-Control-Allow-Origin': '*', // Development only - use specific origin in production
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  });
}

認証のデバッグ:

// Check for auth header
const token = request.headers.get('Authorization')?.replace('Bearer ', '');
if (!token) {
  return Response.json({ error: 'Unauthorized' }, { status: 401 });
}

try {
  const session = await verifyToken(token);
} catch (error: unknown) {
  logger.error('Token verification failed', { error });
  return Response.json({ error: 'Invalid token' }, { status: 401 });
}
ステップ 6.3:リクエストペイロードを検証する

リクエストデータが正しいことを確認します。

discover:
  queries:
    - id: request_bodies
      type: grep
      pattern: "(body:|JSON.stringify)"
      glob: "**/*.{ts,tsx}"
    - id: validation_schemas
      type: grep
      pattern: "z\\.object\\("
      glob: "**/*.{ts,tsx}"
  verbosity: locations

リクエストの検証:

import { z } from 'zod';

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1).max(100),
});

export async function POST(request: Request) {
  const body = await request.json();
  const result = createUserSchema.safeParse(body);
  
  if (!result.success) {
    return Response.json(
      { error: 'Validation failed', details: result.error.flatten() },
      { status: 400 }
    );
  }
  
  // Now result.data is type-safe
}
フェーズ 7:状態のデバッグ

React の状態と状態管理をデバッグします。

ステップ 7.1:状態の使用箇所を見つける

状態の宣言と更新箇所を特定します。

discover:
  queries:
    - id: useState_calls
      type: grep
      pattern: "useState<?"
      glob: "**/*.{tsx,jsx}"
    - id: state_updates
      type: grep
      pattern: "set[A-Z][a-zA-Z]*\\("
      glob: "**/*.{tsx,jsx}"
    - id: useEffect_hooks
      type: grep
      pattern: "useEffect\\("
      glob: "**/*.{tsx,jsx}"
  verbosity: locations

よくある状態の問題:

問題症状修正方法
古いクロージャ状態の値が古い関数形式の更新を使用する
依存関係の不足useEffect が再実行されない依存配列に追加する
無限ループコンポーネントが延々と再レンダリングされる依存関係または条件を修正する
状態の競合状態更新が互いに上書きされるreducer またはキューを使用する
アンマウント時の状態消失データが消える状態を上位に移動するか、グローバル状態を使用する

古いクロージャの修正:

// Before: Stale closure
const [count, setCount] = useState(0);

function increment() {
  setTimeout(() => {
    setCount(count + 1); // count is stale
  }, 1000);
}

// After: Functional update
function increment() {
  setTimeout(() => {
    setCount(prev => prev + 1); // Always current
  }, 1000);
}

useEffect の依存関係の修正:

// Before: Missing dependency
useEffect(() => {
  fetchData(userId);
}, []); // userId changes ignored

// After: Complete dependencies
useEffect(() => {
  fetchData(userId);
}, [userId]); // Re-runs when userId changes
ステップ 7.2:状態の変更を確認する

状態を直接変更している箇所(アンチパターン)を見つけます。

discover:
  queries:
    - id: array_mutations
      type: grep
      pattern: "\\.(push|pop|shift|unshift|splice)\\("
      glob: "**/*.{tsx,jsx}"
    - id: object_mutations
      type: grep
      pattern: "[a-zA-Z]+\\.[a-zA-Z]+\\s*=\\s*"
      glob: "**/*.{tsx,jsx}"
  verbosity: locations

不変な更新:

// Before: Mutation
const [items, setItems] = useState([1, 2, 3]);
items.push(4); // BAD: Mutates state
setItems(items);

// After: Immutable
setItems([...items, 4]); // GOOD: New array

// Object updates
const [user, setUser] = useState({ name: 'Alice', age: 30 });
setUser({ ...user, age: 31 }); // GOOD: New object
フェーズ 8:パフォーマンスのデバッグ

パフォーマンスのボトルネックを診断します。

ステップ 8.1:パフォーマンスのアンチパターンを見つける

よくあるパフォーマンスの問題を検索します。

discover:
  queries:
    - id: n_plus_one
      type: grep
      pattern: "(for|forEach|map).*await.*(prisma|db|query)"
      glob: "**/*.{ts,tsx}"
    - id: inline_objects
      type: grep
      pattern: "(onClick|onChange|style)=\\{\\{"
      glob: "**/*.{tsx,jsx}"
    - id: missing_memo
      type: grep
      pattern: "(map|filter|reduce|sort)\\("
      glob: "**/*.{tsx,jsx}"
  verbosity: locations

パフォーマンスの問題:

アンチパターン影響修正方法
N+1 クエリデータベースクエリが遅くなるinclude またはバッチ読み込みを使用する
JSX 内のインラインオブジェクト不要な再レンダリング定数に切り出すか、useMemo を使用する
仮想化されていない大規模なリストレンダリングが遅くなるreact-window などを使用する
インデックスの不足クエリが遅くなるデータベースインデックスを追加する
不要な再レンダリングUI の動作が遅くなるReact.memo、useMemo、useCallback を使用する
ステップ 8.2:ビルドのパフォーマンスをプロファイリングする

ビルドが遅い原因を確認します。

precision_exec:
  commands:
    - cmd: "npm run build"
  verbosity: standard

ビルドのパフォーマンスの問題:

  • バンドルサイズが大きい(バンドルアナライザーで確認)
  • TypeScript のコンパイルが遅い(tsconfig を確認)
  • ツリーシェイキングが機能していない(インポートを確認)
  • 本番環境に開発用依存関係が含まれている(package.json を確認)
フェーズ 9:根本原因の分析

症状だけでなく、根本的な問題を見つけます。

ステップ 9.1:5 回「なぜ」を問う

根本原因まで掘り下げます。

例:

  1. なぜアプリがクラッシュしたのか? - ユーザーデータが undefined だった
  2. なぜユーザーデータが undefined だったのか? - API が null を返した
  3. なぜ API が null を返したのか? - データベースクエリが行を返さなかった
  4. なぜ行がなかったのか? - ユーザー ID が正しくなかった
  5. なぜユーザー ID が正しくなかったのか? - ルートパラメーターの解析に失敗した

根本原因: ルートパラメーターの解析がエッジケースに対応していません。

ステップ 9.2:システムの依存関係を確認する

環境と依存関係を検証します。

precision_exec:
  commands:
    - cmd: "node --version"
    - cmd: "npm --version"
    - cmd: "npm list --depth=0"
  verbosity: minimal

よくある依存関係の問題:

  • バージョンの不一致(package.json とロックファイル)
  • ピア依存関係の競合
  • 既知のバグがある古いパッケージ
  • ネイティブ依存関係の不足
ステップ 9.3:最近の変更を確認する

エラーが発生する前に何が変更されたかを特定します。

precision_exec:
  commands:
    - cmd: "git log --oneline -10"
    - cmd: "git diff HEAD~5..HEAD"
  verbosity: standard

複雑な問題に対する Git bisect:

git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Test, then mark:
git bisect good  # or bad
# Repeat until culprit commit found
フェーズ 10:予防 — 今後の問題を回避する

再発を防ぐための安全策を追加します。

ステップ 10.1:テストを追加する

エラーを検出するテストを作成します。

import { describe, it, expect } from 'vitest';

describe('getUserName', () => {
  it('should handle undefined user', () => {
    expect(getUserName(undefined)).toBe('Unknown');
  });
  
  it('should handle user without name', () => {
    expect(getUserName({ id: '123' })).toBe('Unknown');
  });
  
  it('should return user name', () => {
    expect(getUserName({ id: '123', name: 'Alice' })).toBe('Alice');
  });
});
ステップ 10.2:ログを追加する

今後のデバッグに役立つよう、重要な判断箇所をログに記録します。

import { logger } from '@/lib/logger';

function processUser(user: User | undefined) {
  if (!user) {
    logger.warn('User is undefined in processUser');
    return null;
  }
  
  logger.info('Processing user', { userId: user.id });
  
  try {
    // Process user
  } catch (error: unknown) {
    logger.error('Failed to process user', { userId: user.id, error });
    throw error;
  }
}

ログ記録のベストプラクティス:

  • 構造化ログ(JSON)を使用する
  • コンテキスト(ユーザー ID、リクエスト ID)を含める
  • 適切なログレベル(error、warn、info、debug)を使用する
  • 機密データ(パスワード、トークン)は決してログに記録しない
  • リクエストを追跡するために相関 ID を使用する
ステップ 10.3:モニタリングを追加する

本番環境でエラーを追跡します。

エラー追跡(Sentry、Rollbar):

import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 0.1,
  beforeSend(event, hint) {
    // Filter sensitive data
    if (event.request) {
      delete event.request.cookies;
    }
    return event;
  },
});

カスタムエラークラス:

export class AppError extends Error {
  constructor(
    message: string,
    public code: string,
    public statusCode: number = 500,
    public context?: Record<string, unknown>
  ) {
    super(message);
    this.name = 'AppError';
  }
}

throw new AppError('User not found', 'USER_NOT_FOUND', 404, { userId });

よくあるデバッグパターン

カテゴリ別に整理された詳細なパターンについては、references/debugging-patterns.md を参照してください。

エラーパターンの検出

discover を使用すると、複数のエラーパターンを一度に見つけられます。

discover:
  queries:
    # Type safety issues
    - { id: any_usage, type: grep, pattern: ':\\s*any', glob: '**/*.{ts,tsx}' }
    - { id: type_assertions, type: grep, pattern: 'as (any|unknown)', glob: '**/*.{ts,tsx}' }
    # Runtime safety
    - { id: unsafe_access, type: grep, pattern: '\\.[a-zA-Z]+(?!\\?)', glob: '**/*.{ts,tsx}' }
    - { id: unhandled_promises, type: grep, pattern: 'await.*(?!try)', glob: '**/*.{ts,tsx}' }
    # Performance
    - { id: n_plus_one, type: grep, pattern: 'for.*await.*prisma', glob: '**/*.{ts,tsx}' }
    - { id: inline_objects, type: grep, pattern: 'onClick=\\{\\{', glob: '**/*.{tsx,jsx}' }
  verbosity: locations
系統的なエラー分析

ステップ 1:エラーを分類する

  • 型エラー(コンパイル時)
  • ランタイムエラー(null、undefined、型の不一致)
  • ロジックエラー(誤った動作が発生し、例外は発生しない)
  • パフォーマンスエラー(処理が遅すぎる)
  • ネットワークエラー(API の失敗)

ステップ 2:類似するパターンを探す

  • エラーメッセージを検索する
  • エラーの種類を検索する
  • 失敗している関数名を検索する

ステップ 3:データを追跡する

  • データはどこから来ていますか?
  • どのような変換が行われますか?
  • どこで失敗しますか?

ステップ 4:前提を検証する

  • データの形状は正しいですか?
  • 型は正確ですか?
  • エッジケースに対応していますか?

ステップ 5:修正して検証する

  • 修正を適用する
  • 型チェックを実行する
  • テストを実行する
  • 手動で検証する

デバッグ用の高精度ツール

Discover ツール

エラーパターンを見つけるため、並列検索を実行します。

discover:
  queries:
    - id: error_sites
      type: grep
      pattern: "throw new"
      glob: '**/*.{ts,tsx,js,jsx}'
    - id: catch_blocks
      type: grep
      pattern: "catch\\s*\\("
      glob: '**/*.{ts,tsx,js,jsx}'
    - id: console_logs
      type: grep
      pattern: "console\\.(log|error|warn)"
      glob: '**/*.{ts,tsx,js,jsx}'
  verbosity: locations
Precision Grep

周辺のコードを理解するため、コンテキストを含めて検索します。

precision_grep:
  queries:
    - id: error_context
      pattern: "TypeError|ReferenceError|RangeError"
      glob: "**/*.{ts,tsx,js,jsx}"
  output:
    format: context
    context_before: 5
    context_after: 5
  verbosity: standard
Precision Exec

診断コマンドを実行します。

precision_exec:
  commands:
    - cmd: "npm run typecheck 2>&1"
    - cmd: "npm run lint 2>&1"
    - cmd: "npm test 2>&1"
  verbosity: standard
Precision Edit

修正をアトミックに適用します。

precision_edit:
  edits:
    - path: "src/utils/user.ts"
      find: "user.name"
      replace: "user?.name ?? 'Unknown'"
  verbosity: minimal

検証スクリプト

デバッグの実践内容を検証するには、scripts/validate-debugging.sh を使用します。

./scripts/validate-debugging.sh /path/to/project

スクリプトのチェック項目:

  • 本番環境から console.log 文が削除されている
  • エラーバウンダリが実装されている
  • ソースマップが設定されている
  • 適切なロギングライブラリが使用されている
  • try/catch ブロックでエラーが処理されている
  • デバッグ用の依存関係が本番環境から除外されている

クイックリファレンス

デバッグチェックリスト

再現する:

  • エラーが一貫して再現する
  • 最小限の再現手順を特定している
  • 環境が一致している
  • エラーメッセージを記録している

切り分ける:

  • スタックトレースを分析している
  • データフローを追跡している
  • 境界条件をテストしている
  • 類似するパターンを見つけている

特定する:

  • エラーを分類している
  • 根本原因を特定している(症状ではない)
  • 前提を検証している
  • 依存関係を確認している

修正する:

  • 適切な修正方法を選んでいる
  • 防御的なコードを追加している
  • 修正を適用している
  • 新たな問題が発生していない

検証する:

  • 型チェックに合格する
  • テストに合格する
  • 手動での検証が完了している
  • エッジケースをテストしている

防止する:

  • この問題のテストを追加している
  • ログを追加している
  • モニタリングを設定している
  • ドキュメントを更新している
エラーの重大度ガイド

クリティカル(直ちに修正):

  • アプリケーションがクラッシュする
  • データの損失または破損
  • セキュリティ上の脆弱性
  • 本番環境の停止

高(早急に修正):

  • 機能が完全に動作しない
  • ユーザーエクスペリエンスが低下している
  • パフォーマンスが低下している
  • 型安全性に違反している

中(可能なときに修正):

  • エッジケースでの失敗
  • 軽微な UX の問題
  • コンソール警告
  • エラー処理の欠落

低(いずれ修正):

  • コードスタイルの問題
  • ドキュメントの不足
  • 最適化の余地
  • リファクタリングの必要性
避けるべきよくある間違い

原因ではなく症状を修正する:

  • 悪い例:値が null である理由を理解せずに null チェックを追加する
  • 良い例:値が null である理由を追跡し、発生源を修正する

検証を省略する:

  • 悪い例:修正を適用して、動作すると決めつける
  • 良い例:テスト、型チェック、手動での検証を実行する

エッジケースを無視する:

  • 悪い例:一般的なケースだけを修正する
  • 良い例:null、undefined、空の値、大きな値をテストする

再発防止をしない:

  • 悪い例:バグを修正して、そのまま先に進む
  • 良い例:再発を防ぐためにテストとログを追加する

高度なテクニック

二分探索デバッグ

複雑な問題では、二分探索を使って範囲を絞り込みます。

コードの半分をコメントアウトする:

  1. 関数の半分をコメントアウトする
  2. エラーが続く場合、問題は残りの半分にあります
  3. エラーが消える場合、問題はコメントアウトした部分にあります
  4. 問題を切り分けられるまで繰り返す
ラバーダックデバッグ

問題を声に出して説明します:

  1. コードが何をすべきか説明する
  2. 実際に何をしているか説明する
  3. 1 行ずつ追っていく
  4. 説明しているうちに問題が明らかになることがよくあります
タイムトラベルデバッグ

git を使って、バグがいつ導入されたかを特定します:

git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# Test each commit
git bisect good  # or bad
ロギング戦略

重要な値を追跡する:

function processData(data: unknown) {
  logger.debug('Input data', { data });
  
  const validated = schema.parse(data);
  logger.debug('Validated data', { validated });
  
  const transformed = transform(validated);
  logger.debug('Transformed data', { transformed });
  
  return transformed;
}

相関 ID を使用する:

import { v4 as uuid } from 'uuid';

export async function POST(request: Request) {
  const requestId = uuid();
  logger.info('Request started', { requestId });
  
  try {
    const result = await processRequest(request);
    logger.info('Request completed', { requestId });
    return Response.json(result);
  } catch (error: unknown) {
    logger.error('Request failed', { requestId, error });
    throw error;
  }
}

他のスキルとの連携

  • 自動修正を試みるには error-recovery を使用します
  • レビュー中のエラーを検出するには code-review を使用します
  • リグレッションを防ぐには testing-strategy を使用します
  • パフォーマンスの問題には performance-audit を使用します
  • セキュリティの脆弱性には security-audit を使用します

リソース

コメント