第二讲:代码坏味道识别——那些让你头疼的“代码病”

大家好,欢迎来到第二讲。上一讲我们聊了重构的价值,今天咱们来点实在的——怎么一眼看出代码里藏着哪些“坏味道”。

说实话,我刚开始做C++开发那几年,根本不懂什么叫“坏味道”。代码能跑就行,管它长什么样。直到有一次,我接手一个遗留项目,打开一个源文件,好家伙,光一个函数就800多行。我盯着屏幕看了十分钟,愣是没看懂它在干嘛。那一刻我才明白——代码的“味道”,真的很重要。

今天我们就来聊聊最常见的几种坏味道。你想想看,是不是经常遇到?

1. 重复代码——最臭的味道

重复代码,说白了就是“复制粘贴”的后遗症。我见过最夸张的,一个项目里同样的排序逻辑出现了7次,每次就改了个变量名。

典型症状:

  • 相同的逻辑出现在多个函数中
  • 相似的循环结构反复出现
  • 几乎一样的if-else分支
// 坏味道:重复代码
void processOrderA() {
    for (int i = 0; i < items.size(); i++) {
        if (items[i].price > 100) {
            applyDiscount(items[i], 0.9);
        }
    }
}

void processOrderB() {
    for (int i = 0; i < items.size(); i++) {
        if (items[i].price > 100) {
            applyDiscount(items[i], 0.9);  // 完全一样!
        }
    }
}

我的经验:遇到重复代码,别犹豫,直接提取成函数。我曾经在一个模块里提取了5个公共函数,代码量直接减少40%。

2. 过长函数——一眼望不到头

一个函数超过50行,我就开始警惕了。超过100行?那基本可以断定,这个函数至少干了三件事。

为什么会这样?因为很多人习惯把“所有逻辑”塞进一个函数里。我见过一个函数,从读取配置文件、解析数据、计算统计、生成报表到发送邮件,全在一个函数里完成。你想想看,这怎么维护?

// 坏味道:过长函数
void processData() {
    // 读取文件(30行)
    // 解析数据(50行)
    // 计算统计(40行)
    // 生成报表(60行)
    // 发送邮件(20行)
    // 总共200行!
}

避坑指南:我曾经把一个300行的函数拆成6个小函数,每个函数只做一件事。结果呢?bug率下降了70%。记住:一个函数只做一件事,做好一件事。

3. 过大的类——上帝类的诞生

一个类超过500行?嗯,这很可能是“上帝类”的前兆。上帝类,就是那种什么都能干、什么都往里塞的类。

我个人习惯,一个类的职责应该单一。如果一个类既负责数据存储,又负责业务逻辑,还负责界面展示,那它迟早会变成一团乱麻。

类的大小 建议
< 200行 正常
200-500行 需要审视
> 500行 必须拆分

4. 过长参数列表——函数签名像购物清单

一个函数有6个以上参数?我建议你停下来想想。参数越多,调用越容易出错,测试越难写。

我记得有一次,一个同事写了个函数,参数列表长达12个。每次调用都要对着文档一个一个填,填错一个就出bug。后来我们把它改成了参数对象,世界清净了。

// 坏味道:过长参数列表
void createOrder(int userId, int productId, double price, 
                 int quantity, string address, string phone,
                 string couponCode, int paymentMethod) {
    // ...
}

// 改进:使用参数对象
struct OrderParams {
    int userId;
    int productId;
    double price;
    int quantity;
    string address;
    string phone;
    string couponCode;
    int paymentMethod;
};

void createOrder(const OrderParams& params) {
    // ...
}

5. 发散式变化——改一处,动全身

发散式变化,说白了就是“牵一发而动全身”。当你修改一个功能时,需要改动多个不同的类或模块,这就是发散式变化。

我遇到过最典型的例子:一个支付系统,每次新增支付方式,都要修改订单类、支付类、日志类、报表类……改得人心力交瘁。

判断标准:如果同一个原因(比如新增支付方式)导致你修改了3个以上的文件,那就有问题了。

知识体系总览

下面这张图,是我自己总结的代码坏味道识别框架。你可以把它当作一个检查清单,每次review代码时对照着看。

代码坏味道 重复代码 过长函数 过大的类 过长参数列表 发散式变化 霰弹式修改 识别坏味道是重构的第一步,也是最重要的一步

如何快速识别?我的实战技巧

说了这么多,你可能想问:有没有快速识别的方法?当然有。我总结了一套“三看”法则:

  1. 看长度:函数超过50行、类超过300行、参数超过5个,直接标记
  2. 看重复:搜索代码库,相同的代码片段出现2次以上,必须提取
  3. 看变化:每次需求变更,需要改动的文件数超过3个,说明设计有问题

我的小工具:我习惯用clang-tidy的静态分析功能,它能自动检测出很多坏味道。比如过长函数、过大的类、重复代码等。配合代码review,效果翻倍。

好了,这一讲的内容就到这里。记住:识别坏味道不是目的,目的是让代码变得更好。下一讲,我们会深入讨论如何用设计模式来消除这些坏味道。

可可精品资料库