进阶 #software-eng#code-review#refactoring

代码审查与重构

代码审查(Code Review)让其他开发者检查你的代码——发现 Bug、提高可读性、分享知识。重构是在不改变外部行为的前提下优化内部结构

📝 为什么需要”别人”来看你的代码?

你写了一篇论文,自己检查了三遍,觉得没问题了。但导师一看——“第二段的论证有逻辑漏洞”。

自己检查自己的代码很难发现所有问题——因为你对自己的思路太熟悉了,会不自觉地”脑补”正确的逻辑。你的眼睛看的是代码,但脑子里自动运行的是”正确的版本”。

代码审查(Code Review) 就是让另一个开发者阅读你的代码——用”新鲜的眼睛”找到你自己看不到的问题。

📖 类比:互相改作文

高中的时候,老师让你们互相交换作文本批改。

你给自己找 Bug = 看自己的作文——“我觉得写得挺好的啊”

代码审查 = 同桌看你的作文——“这里逻辑不通顺""这里有个错别字”

审查者不熟悉你的思路,反而更容易发现你想当然的地方。


✅ 代码审查的好处

1️⃣ 发现 Bug

有些 Bug 你自己测了很多次都没发现——但别人一眼就看到了。

# 开发者写的
def calculate_total(items):
    total = 0
    for item in items:
        total += item.price * item.quantity
    return total

# 审查者:"如果 items 是空列表,会返回 0——这是预期的吗?"
# 开发者:"啊,空列表应该返回 None 表示没有订单,不是 0!"

研究发现,代码审查可以发现 60-90% 的 Bug——比测试发现的更多。

2️⃣ 知识分享

资深开发者审查新人的代码——新人学到了”怎么写更好”。新人的代码里有些新技巧——资深者也学到了。

"哦,原来 Python 3.10 的 match-case 可以这么用!"
"这个算法复杂度太高了,试试用哈希表优化?"

3️⃣ 代码风格一致

整个团队用同一个标准——不会出现”一个文件用驼峰命名、另一个文件用下划线命名”的混乱。

4️⃣ 每人负责,但不止一人知道

核心代码至少两个人熟悉——不会出现”张三请假了,没人懂支付模块”的情况。


🔍 代码审查时看什么?

# 一份 PR 给审查者的参考检查清单

def process_order(order_data):
    """处理订单——假设这是你要审查的代码"""
    
    # 1️⃣ 正确性——逻辑对吗?
    if not order_data.get("items"):
        return {"error": "订单不能为空"}
    
    # 2️⃣ 边界条件——空值、零、异常处理
    total = sum(item["price"] * item["quantity"] 
                for item in order_data["items"])
    
    # 3️⃣ 安全性——有没有注入风险?输入验证?
    # 如果 item["price"] 是用户输入的,有没有验证是数字?
    
    # 4️⃣ 性能——有没有不必要的循环或查询?
    # 这里用了列表推导,性能 OK
    
    # 5️⃣ 可读性——命名清晰?需要注释?
    # "process_order" 太泛了,建议改为 "calculate_order_total"
    
    # 6️⃣ 测试——有对应的测试吗?
    # 审查者应该能看到对应的测试文件修改
    
    return {"total": total}

给审查者的原则

✅ 关注"能不能改善",而不是"挑刺"
✅ 说清楚"为什么"——不只是"这样不对"
✅ 对事不对人——审查的是代码,不是写代码的人
✅ 小 PR 更容易审查——一个大 PR 改成 5 个小 PR

给提交者的原则

✅ 写清楚的 PR 描述——"做了什么"和"为什么"
✅ PR 越小越好——一次只改一个功能
✅ 对审查意见表示感谢——"好建议,我改一下"
✅ PR 不要留到第二天——24 小时内开始审查

🔧 重构——不改变功能,只改善结构

重构(Refactoring) 和代码审查紧密相关——审查发现代码”可以写得更好”,但改了之后功能不变。

重构 = 在不改变外部行为的前提下,优化内部结构。

# 重构前——一个大函数做所有事
def process_user_data(user_data):
    # 验证
    if not user_data.get("name") or len(user_data["name"]) > 50:
        return {"error": "名字无效"}
    if not user_data.get("email") or "@" not in user_data["email"]:
        return {"error": "邮箱无效"}
    
    # 创建用户
    user = User(name=user_data["name"], email=user_data["email"])
    db.session.add(user)
    db.session.commit()
    
    # 发送通知
    send_email(user.email, "欢迎注册!")
    
    # 记录日志
    logger.info(f"新用户: {user.name}")
    
    return {"id": user.id, "name": user.name}
# 重构后——拆成小函数,每个只做一件事
def validate_user_data(data):
    errors = []
    if not data.get("name") or len(data["name"]) > 50:
        errors.append("名字无效")
    if not data.get("email") or "@" not in data["email"]:
        errors.append("邮箱无效")
    return errors

def create_user(data):
    user = User(name=data["name"], email=data["email"])
    db.session.add(user)
    db.session.commit()
    return user

def notify_user(email):
    send_email(email, "欢迎注册!")

def process_user_data(data):
    errors = validate_user_data(data)
    if errors:
        return {"error": errors}
    
    user = create_user(data)
    notify_user(user.email)
    logger.info(f"新用户: {user.name}")
    
    return {"id": user.id, "name": user.name}

常见重构手法

手法适用场景怎么做
提取函数函数太长把一段逻辑拆成独立函数
重命名名字不能表达意图calc(a,b)calculate_discount(price, rate)
简化条件if-else 太复杂拆成多个小函数,或用策略模式
引入参数对象参数太多把多个参数聚合成一个对象
用多态替换条件多个 if-else 检查对象类型用不同的子类代替

📝 小结

概念一句话
代码审查(Code Review)别人看你的代码——发现你自己看不到的问题
审查要点正确性、边界、安全、性能、可读性、测试
PR 原则小 PR、描述清晰、及时审查
重构(Refactoring)改善内部结构,不改变外部行为
常见重构提取函数、重命名、简化条件、引入参数对象
测试保障重构前有测试覆盖——不改坏功能

🎯 小练习:找一段你之前写过但觉得”可以更好”的代码,应用本篇学到的重构手法(至少 3 种),写出重构前后的对比。

为什么先学这个? 代码质量有了保证,接下来看看系统之间怎么交互——API 设计与 REST