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. 01定位 TypeScript 类型错误
  2. 02排查运行时异常或逻辑错误
  3. 03分析 API 请求与响应故障
  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/undefineduser.name使用 user?.name
除以零total / count检查 count !== 0
空字符串操作str[0]检查 str.length > 0
对象缺少键obj.key使用 obj?.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'))
  • 空值检查(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);
}

空值安全修复

// 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 未授权缺少或令牌无效添加身份验证标头,刷新令牌
404 未找到URL 或路由错误修正端点路径
500 服务器错误后端异常检查服务器日志,修复后端
超时请求耗时过长延长超时时间,优化后端
网络故障获取失败检查网络连接,添加重试逻辑

调试 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)
  • 缺少 tree-shaking(检查导入)
  • 在生产环境中使用了开发依赖(检查 package.json)
阶段 9:根因分析

不止于表面症状,找出潜在问题。

步骤 9.1:连续追问五个为什么

逐步深入,找出根本原因。

示例:

  1. 为什么应用崩溃了? - 用户数据未定义
  2. 为什么用户数据未定义? - 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 与 lockfile 不一致)
  • 对等依赖冲突
  • 已知存在错误的过时软件包
  • 缺少原生依赖项
步骤 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 块是否处理了错误
  • 是否已从生产环境中排除调试依赖

快速参考

调试检查清单

复现:

  • 错误可以稳定复现
  • 已确定最简复现步骤
  • 环境一致
  • 已捕获错误消息

隔离:

  • 已分析堆栈跟踪
  • 已追踪数据流
  • 已测试边界条件
  • 已找到相似模式

识别:

  • 已对错误分类
  • 已识别根本原因(而非表面症状)
  • 已验证假设
  • 已检查依赖项

修复:

  • 已选择合适的修复方案
  • 已添加防御性代码
  • 已应用修复
  • 未引入新问题

验证:

  • 类型检查通过
  • 测试通过
  • 已完成手动验证
  • 已测试边缘情况

预防:

  • 已针对该问题添加测试
  • 已添加日志
  • 已配置监控
  • 已更新文档
错误严重性指南

严重(立即修复):

  • 应用崩溃
  • 数据丢失或损坏
  • 安全漏洞
  • 生产环境中断

高(尽快修复):

  • 功能完全失效
  • 用户体验差
  • 性能下降
  • 违反类型安全

中(有条件时修复):

  • 边缘情况失败
  • 轻微的用户体验问题
  • 控制台警告
  • 缺少错误处理

低(之后修复):

  • 代码风格问题
  • 缺少文档
  • 优化机会
  • 重构需求
应避免的常见错误

修复症状,而非原因:

  • 错误:添加 null 检查,却不弄清它为什么是 null
  • 正确:追踪该值为何为 null,并修复源头

跳过验证:

  • 错误:应用修复后就假定问题已解决
  • 正确:运行测试、类型检查并进行手动验证

忽略边缘情况:

  • 错误:只修复常见情况
  • 正确:测试 null、undefined、空值和大值

不做预防:

  • 错误:修复 Bug 后就继续往下做
  • 正确:添加测试和日志以防止问题再次发生

高级技巧

二分调试

对于复杂问题,使用二分法缩小范围。

注释掉一半代码:

  1. 注释掉函数的一半
  2. 如果错误仍然存在,问题就在剩余部分
  3. 如果错误消失,问题就在被注释的部分
  4. 重复此过程,直到定位问题
橡皮鸭调试法

大声讲解问题:

  1. 描述代码应该做什么
  2. 描述代码实际做了什么
  3. 逐行梳理代码
  4. 讲解过程中通常就能发现问题
时间回溯调试

使用 git 查找 Bug 是何时引入的:

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 查找安全漏洞

资源

评论

支持 Markdown