代码质量不是靠感觉

「这段代码写得很乱」是每个人都能说一句的话,但乱在哪、有多乱、该先收拾哪一段,往往说不清楚。凭感觉评判代码,最后只会变成个人偏好之争,解决不了真实的可维护性问题。

代码质量需要一些可观察、可比较的指标,帮你在成千上万行代码里,快速定位到真正危险的那几处。度量不是为了给人打分,而是为了把有限的精力花在刀刃上。

重构最怕的不是改不动,而是不知道该先改哪里。度量就是那盏指路灯。
本文核心知识点
  • 圈复杂度数一个函数有多少条分支岔路。
  • 度量用途找重点、看趋势,不当成绩排名。
  • 测试先行重构前先把行为用测试钉住。
  • 小步手法抽函数、搬字段、改命名,一次只动一处。
  • 持续做把重构融进日常需求,而不是搞大扫除。
代码质量重构示意:蓝色渐变背景上左侧一团交错缠绕的杂乱发光线条与节点,向右逐渐梳理成整齐平行的发光光带网格,过渡处有悬浮发光扳手与天平,扁平科技插画
重构就是把左边那团乱麻,一步步梳成右边整齐的光带。

圈复杂度:数一个函数有多少条岔路

圈复杂度是最常用的一个指标,思路很直接:一个函数里有多少条可以走的路。每多一个 if、循环、case、短路条件,就多一条岔路,测试时要覆盖的情况也就翻一倍。

一个圈复杂度高的函数,意味着读它时要在脑子里同时追踪很多种组合,出 bug 的概率天然更高。它不需要精确,只要能让你一眼看出「这个函数太岔了」。

# 圈复杂度高的样子:一个函数里塞满分支(示意)
def 结算(订单):
    if 订单.是会员:
        if 订单.有券:
            if 订单.满减:
                …           # 每条 if 都是一条岔路
            else:
                …
    else:
        if 订单.有券:
            …
    # 岔路一多,读代码像在走迷宫,测试也难写全。

经验上,一个函数的圈复杂度明显超过周边同类,它就是你下一个该收拾的对象。

度量是为了找重点,不是为了扣分

一旦把度量变成对人的考核,事情就变味了:大家开始为了数字好看而拆分函数、堆注释,代码反而更难读。度量的正确用法是看趋势和找异常。

度量看什么不该怎么用
圈复杂度哪个函数突然高得离谱给每个开发者排名次
重复率哪几段几乎复制粘贴追求零重复而过度抽象
函数长度哪个函数长到读不下来强行拆成十几个小函数
测试覆盖核心逻辑有没有被钉住为凑覆盖率写无意义用例

把度量接进 CI,让它在评审时温和地提示哪里变复杂了,而不是作为一个红黑榜。

重构第一步:先补测试保护

没测试就重构,等于蒙着眼睛拆炸弹。你改了结构,很可能悄悄改了行为却不自知。所以重构的第一条纪律是:动手之前,先让现有行为被测试罩住。

  • 先跑通一套覆盖这个函数主要路径的测试,让它变绿。
  • 之后每次小重构,都跑一次测试,一直是绿的才继续。
  • 测试意外变红,说明这步改动碰到了行为,立刻回退或修正。
# 重构节奏(红-绿-重构里的「重构」阶段)
1. 先有一套覆盖旧行为的测试,全部通过
2. 做一个小改动:把一段逻辑抽成函数
3. 跑测试 —— 还是绿的?继续下一个小改动
4. 哪一步红了?回退那一步,想清楚再动
# 有测试托底,重构才敢放心大胆地进行。

如果这段代码实在没有测试、也补不出来,那就先给它补一个最粗糙的冒烟用例,哪怕只是钉住一两个关键行为。