Bug 修复技能
本文档包含修复 bug 的核心原则和技巧,确保修复方案正确、干净、可维护。
核心原则
1. 不掩盖错误
写代码应该干净,不应该尝试掩盖错误。
当遇到问题时,必须找到根本原因并修复,而不是用临时方案、补丁或 workaround 来掩盖问题。
识别 Workaround
以下模式通常表示在掩盖问题:
❌ 掩盖问题的做法
- •
持续轮询/更新来覆盖错误状态
csharp// 错误:用持续更新来掩盖状态不同步 protected override void OnUpdate() { if (someCondition) FixState(); // 每帧都修复,而不是在正确时机设置 } - •
添加额外的检查来绕过逻辑错误
csharp// 错误:用额外检查掩盖调用时机错误 if (state != null && state.IsValid && state.Active) DoSomething(); // 应该在正确时机调用,不需要这么多检查 - •
用 try-catch 吞掉异常而不处理根本原因
csharp// 错误:吞掉异常而不修复问题 try { DoSomething(); } catch { /* 忽略错误 */ } - •
添加延迟/等待来绕过时序问题
csharp// 错误:用延迟掩盖时序问题 await Task.Delay(100); // 应该修复时序,而不是等待 DoSomething();
✅ 正确的做法
- •
在正确的时机设置状态
csharp// 正确:在移动完成后立即设置朝向 void OnMoveDone(bool reached) { if (reached) Owner.locationAttachment.LookAt(target); } - •
修复调用时机,而不是添加检查
csharp// 正确:确保在正确时机调用 void OnStateActivated() { DoSomething(); // 在状态激活时调用,保证状态正确 } - •
修复根本原因,而不是捕获异常
csharp// 正确:修复空引用问题 if (target != null) target.DoSomething(); // 或者确保 target 在需要时总是有效 - •
修复时序问题,而不是添加延迟
csharp// 正确:使用事件或回调确保正确的执行顺序 void OnEvent() { DoSomething(); // 在事件触发时执行,保证顺序 }
决策流程
当遇到问题时,按以下步骤处理:
- •识别问题:明确问题的表现和影响
- •找到根本原因:为什么会出现这个问题?
- •设计正确方案:如何从根本上解决?
- •实施修复:实现正确的解决方案
- •验证:确保问题真正解决,没有副作用
判断标准
在提出解决方案前,问自己:
- •❓ 这个方案是在掩盖问题,还是在修复根本原因?
- •❓ 如果移除这个代码,问题会重现吗?
- •❓ 这个方案会让代码更复杂还是更简单?
- •❓ 这个方案是临时性的还是永久性的?
如果答案是"掩盖"、"会重现"、"更复杂"、"临时性",那么这不是正确的方案。
常见场景
场景 1:状态不同步
- •❌ 错误:在 Update 中持续同步
- •✅ 正确:在状态变更时同步
场景 2:时序问题
- •❌ 错误:添加延迟
- •✅ 正确:使用回调或事件
场景 3:空引用
- •❌ 错误:到处添加空检查
- •✅ 正确:确保对象在需要时总是有效
代码质量标准
遵循此原则的代码应该:
- •✅ 简单直接:解决方案清晰明了
- •✅ 在正确时机执行:逻辑在合适的时机触发
- •✅ 无副作用:不会引入新的问题
- •✅ 易于维护:未来修改时不会产生问题
- •✅ 自解释:代码本身就能说明意图
反模式检查清单
在提交代码前,检查是否包含:
- • 持续轮询来修复状态
- • 多余的 null 检查掩盖设计问题
- • try-catch 吞掉异常
- • 延迟/等待来绕过时序问题
- • 重复代码来绕过逻辑错误
- • 临时变量掩盖命名问题
- • 注释解释为什么代码很奇怪(说明代码本身有问题)
如果发现以上任何模式,重新审视问题,找到根本原因并修复。
后续原则
更多 bug 修复相关的原则和技巧将在此文档中持续补充。