8.1.1 先复现,再动手
如果Bug无法稳定复现,任何修复都是碰运气。接到Bug报告后,第一件事是在本地或测试环境还原现场。
复现检查清单:
- 确认环境一致性(数据库版本、配置项、缓存数据)
- 索要完整的操作路径和用户数据(脱敏后的)
- 检查是否为并发/时序问题(加日志观察时间戳)
实战经验:约30%的"偶现Bug"其实是数据问题。让用户导出一条具体的问题数据,比让他描述十遍现象更管用。
8.1.2 定位三板斧
1. 看日志,别猜代码
先查ERROR级日志,再顺着TraceID(如果有分布式追踪)还原请求链路。重点关注:
- 空指针、数组越界(Java/Python常见)
- 超时日志(数据库、RPC、第三方接口)
- 最近部署时间与Bug出现时间的对应关系
2. 二分法定位
如果版本更新后出现问题,用Git二分查找(git bisect):
git bisect start
git bisect bad HEAD # 当前版本有问题
git bisect good v1.2.0 # 上个稳定版本
# 自动检出中间版本,测试后标记good/bad,重复3-5次即可定位提交
3. 本地调试与热修复
- 复杂业务:在疑似位置插入临时日志(避免在生产线直接打断点)
- 性能问题:用Profiler(Arthas、Py-Spy)抓热点,别凭感觉优化
8.1.3 修复原则
最小改动原则
只修该修的,别顺手"重构"。改动越大,回归测试范围越难控制。
防御性编程
- 修复处加上参数校验(防止脏数据再次触发)
- 关键路径加try-catch,记录上下文(方便下次定位)
版本兼容性
- 接口变更:先兼容旧逻辑,发版后再清理(双写/双读过渡)
- 数据库变更:字段先加后删,严禁直接删列
8.1.4 验证与关闭
自测清单(修复后必做):
- 复现步骤走一遍,确认Bug消失
- 跑一遍相关模块的单元测试(
pytest tests/xxx/或mvn test -Dtest=XXX) - 检查边界条件(空值、最大值、并发请求)
提交规范
fix: 修复订单金额计算精度丢失问题
- 原因:BigDecimal未指定scale,导致除法无限循环
- 修复:setScale(2, RoundingMode.HALF_UP)
- 影响:支付模块、对账模块
- 测试:已补充单元测试 testCalculatePrecision()
Closes #1234
复盘(可选但推荐)
如果Bug导致线上故障,写一份简短的Postmortem:
- 为何测试没发现?(补充测试用例)
- 如何更早发现?(加监控告警)
避坑提醒
- 不要在凌晨2点修复复杂Bug,除非宕机了
- 不要相信"只改了一行代码,不用测试",编译器会骗你,缓存会骗你
- 不要一边修复一边做代码格式化,会让Code Review时难以看出关键改动