代码重构的核心目的是在不改变软件可观察行为的前提下,改善代码的内部结构。为了科学地评估重构的效果,避免"为了重构而重构",我们需要从多个维度来关注指标。 通常,代码重构需要关注的指标可以划分为以下六大类。
一 复杂度指标¶
降低复杂度是重构最直接的目标之一,复杂的代码难以理解、容易出错。
圈复杂度:衡量代码中独立执行路径的数量(通常由
if/else、for、while等决定)。指标要求:重构后单个方法的圈复杂度应显著下降,通常建议控制在 10 以下。认知复杂度:相比圈复杂度,它更贴近人类的阅读习惯,会惩罚打断阅读流的结构(如嵌套逻辑、中断等)。指标要求:重构后应更容易被人类大脑"解析"。
嵌套深度:代码块(如缩进层级)的深度。指标要求:重构后(例如通过卫语句提取)嵌套层级通常不应超过 3-4 层。
二 结构与设计指标¶
评估代码是否遵循了优秀的设计原则(如 SOLID 原则)。
代码重复率:代码库中重复代码的比例。指标要求:通过提取公共方法、继承或组合,重复率应下降(通常要求低于 3%-5%)。
耦合度:模块或类之间的依赖程度。指标要求:重构后,不稳定模块对稳定模块的依赖应减少(依赖倒置),类与类之间的直接调用应变少。
内聚性:一个模块/类内部各个元素之间相互结合的紧密程度。指标要求:重构后(如提取类),新类的内聚性应该变高(做一件事)。
类/方法的规模:过大类(God Object)和过长方法的数量。指标要求:类的行数、方法的行数应在合理范围内(如方法不超过 20-50 行)。
三 可维护性与技术债务指标¶
衡量代码库的长期健康度和修改成本。
技术债务比率:SonarQube 等工具提供的指标,公式为
修复所有问题所需时间 / 开发该代码所需时间。指标要求:重构后该比率应下降至安全阈值(如 < 5%)。代码异味数量:如"过长参数列表"、“特性依恋”、"数据泥团"等。指标要求:特定范围内的代码异味数量应减少。
改动扩散度:当你需要修改一个功能时,需要改动多少个文件/类。指标要求:重构后,单一职责的落实应使得单次需求涉及的文件数减少。
四 质量与可靠性保障指标¶
重构的底线是"不引入新 Bug"。
测试覆盖率:包括行覆盖率和分支覆盖率。指标要求:这与其说是重构的结果,不如说是重构的前提。重构过程中覆盖率不能下降,且必须保持在一个较高水平(如核心逻辑 > 80%)。
回归缺陷率:重构后发布引发的线上 Bug 数量。指标要求:必须为 0 或趋近于 0。如果重构导致线上故障,说明重构失败或测试网失效。
构建成功率:CI/CD 流水线在重构期间的成功率。
五 性能指标¶
部分重构(如引入设计模式、增加抽象层)可能会带来微小的性能损耗,需要监控。
响应时间/延迟:接口的 P99、P95 延迟。指标要求:重构后性能不应出现显著劣化(除非这次重构的特定目的就是性能优化)。
吞吐量 (Throughput - TPS/QPS):系统单位时间内处理的请求数。
资源消耗:CPU 使用率、内存占用、GC 频率等(特别是将递归改为迭代,或者优化了数据结构时)。
六 工程效能与业务指标¶
从团队和商业价值的宏观角度看重构的收益��
PR 审查时间:代码从提交到被合并的平均时间。指标要求:重构后代码变清晰,PR 审查速度应该加快。
新功能交付周期:在重构后的模块上开发新功能的耗时。指标要求:长期来看,由于代码易读性和扩展性提升,交付周期应缩短。
Onboarding 时间:新员工理解该模块所需的时间。指标要求:重构后应降低学习曲线。
常用度量工具¶
静态代码分析:SonarQube, CodeClimate, Coverity, Alibaba Java 开发规约扫描插件。
复杂度计算:Lizard (C/C++/Java/等), radon (Python)。
重复度检测:JSCPD (支持多语言), PMD (Java)。
代码度量可视化:CodeScene(专注于识别"热点代码"和代码年龄,非常推荐用于指导重构方向)。
黄金法则¶
设立基线:永远不要在没有基线数据的情况下开始重构。先测量,重构,再对比。
拒绝"唯指标论":不要为了把圈复杂度从 11 降到 10 而强行重构,要看实际阅读代码的体感。
小步快跑,持续验证:不要试图一次性优化所有指标。一次只针对一种"代码异味"进行重构,每走一小步就运行一次测试(红灯-绿灯-重构循环)。
区分"重构"与"重写/优化":如果是性能优化,重点关注性能指标;如果是架构重构,重点关注耦合和内聚;如果是纯粹的重构,功能和性能指标必须保持不变。