1-4-4-认知偏差是Debug最大敌人
1.4.4 认知偏差是 Debug 最大敌人
引言
Debug 最大的障碍不是技术问题,而是心理问题。
人类大脑有各种认知偏差(Cognitive Biases),在 Debug 时,这些偏差会:
- 让你忽略关键信息
- 让你坚持错误的假设
- 让你过早下结论
- 让你看不到明显的问题
要成为好的 Debug 高手,首先要认识和克服自己的认知偏差。
常见的认知偏差
偏差1:确认偏差(Confirmation Bias)
定义:倾向于寻找支持自己假设的证据,忽略反对的证据。
Debug 中的表现:
# 你认为问题在数据库查询
def get_users():
# 你花了1小时优化这个查询
users = db.query(User).filter(User.active == True).all()
return users
# 实际问题:你没有意识到的地方
def display_users(users):
# 这里有个 O(n^2) 的循环,才是真正的性能瓶颈
for user in users:
for order in get_user_orders(user.id): # 每次都查数据库!
print(f"{user.name}: {order.total}")
你认为是数据库慢,所以只看数据库相关的代码,完全忽略了显示逻辑的问题。
如何克服:
# 强迫自己质疑假设
# Q: "如果不是数据库的问题呢?"
# A: 让我测量一下每个部分的时间
import time
def get_users():
start = time.time()
users = db.query(User).filter(User.active == True).all()
print(f"DB query time: {time.time() - start}s") # 0.01s
return users
def display_users(users):
start = time.time()
for user in users:
for order in get_user_orders(user.id):
print(f"{user.name}: {order.total}")
print(f"Display time: {time.time() - start}s") # 5.2s ← 问题在这里!
教训:用数据而非直觉,主动寻找反证。
偏差2:可得性启发(Availability Heuristic)
定义:倾向于认为最容易想到的原因就是真正的原因。
Debug 中的表现:
# Bug:用户登录失败
# 你上周刚修了一个密码哈希的bug
# 所以你认为:"一定又是密码的问题!"
def login(username, password):
user = get_user(username)
# 你花了30分钟检查密码验证
if not verify_password(password, user.password_hash):
return False
# 真正的问题:用户被禁用了
if not user.is_active: # ← 你没检查这里
return False
return True
你最近处理过密码问题,所以大脑自动认为"又是密码",忽略了其他可能。
如何克服:
列出所有可能的原因,而不是只考虑最先想到的:
## Bug:用户无法登录
### 可能的原因
- [ ] 密码错误
- [ ] 用户名不存在
- [ ] 账户被禁用 ← 检查这个
- [ ] 数据库连接问题
- [ ] 会话服务问题
- [ ] 网络问题
### 逐一排查
1. 密码验证:正常
2. 用户存在:是的
3. 账户状态:被禁用了! ← 找到了
偏差3:锚定效应(Anchoring Bias)
定义:过度依赖最初得到的信息。
Debug 中的表现:
# 用户报告:"页面加载很慢"
# 你测量了一下:3 秒
# 你想:"3 秒还好啊,不算太慢"
# 实际情况
# 用户的网络环境:3秒是总时间
# 你的开发环境:本地运行,没有网络延迟
# 真实的用户体验:
# - 网络延迟:1秒
# - 服务器处理:3秒 ← 实际问题
# - 渲染:0.5秒
# 总计:4.5秒
你被第一个数字(3秒)锚定了,没有考虑用户的真实环境。
如何克服:
# 在多个环境测量
# - 开发环境(本地)
# - 测试环境(内网)
# - 生产环境(真实网络)
# - 不同地区的用户
# 不要被第一个数字锚定
偏差4:邓宁-克鲁格效应(Dunning-Kruger Effect)
定义:能力不足的人高估自己的能力。
Debug 中的表现:
# 新手:看了一眼代码
"我知道问题在哪了,肯定是这里!"
# 快速改了代码,没测试就提交
# 结果:引入了新的 bug
# 有经验的工程师:
"这个问题可能在这里,让我先验证一下..."
# 写测试,确认根因,再修改
新手容易过度自信,老手知道自己不知道的有多少。
如何克服:
# 永远验证你的假设
# 不要因为"看起来对"就认为是对的
def suspected_fix():
# 写一个测试验证
assert original_bug_still_exists()
# 应用修复
apply_fix()
# 验证修复有效
assert bug_is_fixed()
# 验证没有引入新问题
run_all_tests()
偏差5:功能固着(Functional Fixedness)
定义:只能看到事物的常规用途,看不到其他可能。
Debug 中的表现:
# 问题:某个 API 端点响应慢
# 你的思路:"一定是代码逻辑的问题"
def get_users_api():
users = User.query.all() # 你优化了这里
return jsonify([u.to_dict() for u in users]) # 你优化了这里
# 实际问题:网络配置
# API 网关的超时设置是 30 秒,但实际响应时间只需要 0.1 秒
# 用户等了 30 秒,是因为网关超时重试了
你被"代码逻辑"的思维固着了,没有考虑基础设施问题。
如何克服:
系统地检查每一层:
## 层次化排查
### 应用层
- [ ] 代码逻辑
- [ ] 数据库查询
### 基础设施层
- [ ] 网络配置
- [ ] 负载均衡器
- [ ] CDN 设置
### 外部依赖
- [ ] 第三方 API
- [ ] DNS 解析
偏差6:沉没成本谬误(Sunk Cost Fallacy)
定义:因为已经投入了时间/精力,不愿意放弃错误的方向。
Debug 中的表现:
# 你花了3小时调试一个复杂的算法
# 同事建议:"要不换个简单的方法?"
# 你想:"我都花了3小时了,肯定能修好,不能白费!"
# 又花了2小时...还是没修好
# 如果一开始就换方法,5分钟就解决了
你被已经投入的时间绑架了。
如何克服:
# 设定时间上限
# "如果 30 分钟内找不到问题,换个思路"
def debug_with_time_limit():
start_time = time.time()
while True:
# 尝试调试
try_to_fix()
# 30 分钟后强制换思路
if time.time() - start_time > 1800:
print("30分钟了,换个方法")
try_alternative_approach()
break
克服认知偏差的方法
方法1:系统化 Checklist
## Debug Checklist
### 1. 收集信息(不要猜测)
- [ ] 错误信息是什么?
- [ ] 能复现吗?
- [ ] 复现步骤是什么?
- [ ] 预期行为 vs 实际行为
### 2. 列出所有可能原因(不只是最可能的)
- [ ] 可能性1:...
- [ ] 可能性2:...
- [ ] 可能性3:...
### 3. 逐一验证(用数据,不凭感觉)
- [ ] 测试可能性1:结果?
- [ ] 测试可能性2:结果?
### 4. 修复并验证
- [ ] 应用修复
- [ ] 确认bug消失
- [ ] 确认没有引入新问题
- [ ] 添加测试防止回归
方法2:第二意见
# 如果卡住了,找同事讨论
# 你:"我觉得问题在数据库查询"
# 同事:"你测量过吗?"
# 你:"呃...没有"
# 同事:"那先测量一下吧"
# 新鲜的视角能发现你的盲点
方法3:休息一下
# 你已经调试了2小时,完全卡住了
# 不要继续死磕
# 休息15分钟,做点别的
# 回来后,往往能立刻看到之前忽略的问题
方法4:橡皮鸭调试法
# 向橡皮鸭(或任何无生命对象)解释问题
# "这个函数应该返回用户列表,但它返回了空列表"
# "我检查了数据库,数据是存在的"
# "我检查了查询条件... 等等!"
# "查询条件写错了!filter_by(active==True) 应该是 filter_by(active=True)"
# 解释的过程强迫你重新审视假设
方法5:记录思维过程
## Debug Journal
### 10:00 - 发现 Bug
用户报告:订单总价不对
### 10:05 - 初步假设
可能是计算逻辑错误
### 10:15 - 验证假设
测试计算逻辑:正确
假设错误,换方向
### 10:20 - 新假设
可能是数据库保存时四舍五入
### 10:25 - 验证
检查数据库字段:DECIMAL(10,2)
应该没问题...
### 10:30 - 发现
检查了实际数据,发现有些订单的折扣是负数!
根因:折扣验证逻辑有漏洞
### 10:35 - 修复
添加折扣验证:0 <= discount <= total
记录过程帮助你:
- 看到自己的思维模式
- 识别认知偏差
- 避免循环思考
对使用AI的建议
AI 也有"认知偏差"
# AI 的"确认偏差"
# 如果你告诉 AI:"我觉得问题在数据库"
# AI 会倾向于生成关于数据库的建议
# 即使问题其实在别处
# 更好的提问方式
"这个函数返回了错误的结果。
输入:[...]
预期输出:[...]
实际输出:[...]
可能的问题在哪里?请列出所有可能性。"
# 让 AI 帮你生成 checklist,而不是直接给答案
实践建议
1. 自我意识
定期问自己:
- "我是不是在寻找支持我假设的证据?"(确认偏差)
- "我是不是因为最近遇到过类似问题,就认为这次也一样?"(可得性启发)
- "我是不是已经在错误的方向上花了太多时间?"(沉没成本)
2. 慢思考
# 快思考(System 1):直觉
"我一看就知道问题在这里!"
# 慢思考(System 2):理性分析
"让我系统地检查每个可能性..."
# Debug 时,强迫自己用慢思考
3. 数据驱动
# 不要凭感觉
"我觉得这里慢"
# 用数据
import time
start = time.time()
suspicious_function()
print(f"Time: {time.time() - start}s")
总结
认知偏差是 Debug 的最大敌人:
- 确认偏差——寻找支持自己假设的证据 → 主动寻找反证
- 可得性启发——最容易想到的原因 → 列出所有可能性
- 锚定效应——被第一个信息锚定 → 多角度测量
- 邓宁-克鲁格——过度自信 → 永远验证假设
- 功能固着——只看常规用途 → 系统化检查每一层
- 沉没成本——不愿放弃已投入 → 设置时间上限
克服方法:
- 使用 Checklist
- 寻求第二意见
- 适时休息
- 橡皮鸭调试
- 记录思维过程
- 数据驱动决策
记住:
Bug 往往出现在你没有检查的地方,因为你的偏差让你忽略了那里。
好的 Debug 高手不是技术最强的,而是最能克服认知偏差的。
永远质疑自己的假设,用数据而非直觉做决策。

浙公网安备 33010602011771号