claude-howto 重构技能参考:代码坏味道(Code Smells)完整识别与治理指南
2026/9/10 17:28:33 网站建设 项目流程

claude-howto 重构技能参考:代码坏味道(Code Smells)完整识别与治理指南

【免费下载链接】claude-howtoA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-howto

本指南基于 claude-howto 仓库中 refactor 技能 的核心参考文档 code-smells.md,系统整理马丁·福勒《重构》第二版中的 22 种代码坏味道:坏味道是更深层问题的表面症状,它们本身不是 Bug,而是"设计可能出了问题"的信号。读完本文,你将掌握五大类坏味道的识别特征、危害、对应重构手法、量化阈值,以及如何借助仓库中的 detect-smells.py 与 analyze-complexity.py 脚本自动化检测与度量改进效果。

「代码坏味道是通常对应系统中更深层次问题的表面迹象。」—— 马丁·福勒


一、坏味道到底是什么

坏味道(Code Smell)是一种启发式信号:某段代码"闻起来不对劲",需要进一步调查。它与明确的错误不同——代码可能完全能运行,但其结构暗示了可维护性、可测试性或扩展性隐患。识别坏味道是 refactor 技能 的第三阶段核心工作,识别之后需要:

  1. 依据 refactoring-catalog.md 选择对应重构手法;
  2. 借助 templates/refactoring-plan.md 制定分阶段计划;
  3. 以"行为不变、小步快跑、测试护航"为原则实施。

福勒把坏味道分为五大家族,每一族代表一类结构问题:

家族关注点代表坏味道
臃肿体(Bloaters)代码膨胀到难以高效工作Long Method、Large Class、Primitive Obsession、Long Parameter List、Data Clumps
滥用面向对象(OO Abusers)OOP 原则被不完整或不正确使用Switch Statements、Temporary Field、Refused Bequest、Alternative Classes with Different Interfaces
阻碍变更(Change Preventers)改一处必须连带改多处Divergent Change、Shotgun Surgery、Parallel Inheritance Hierarchies
多余之物(Dispensables)没有存在价值、应当删除的东西Comments、Duplicate Code、Lazy Class、Dead Code、Speculative Generality
耦合器(Couplers)类之间过度耦合Feature Envy、Inappropriate Intimacy、Message Chains、Middle Man

二、臃肿体(Bloaters):代码过度膨胀的信号

臃肿体的共同特征是"某个元素长得太大,无法高效工作"。仓库的检测脚本 detect-smells.py 对这类坏味道给出了可量化的阈值定义(见THRESHOLDS字典,源码第 101–110 行),你可以直接作为硬性指标。

2.1 过长方法(Long Method)

识别特征:

  • 方法超过30–50 行(detect-smells.py 中long_method_lines: 30very_long_method_lines: 50两个阈值分别对应中、高严重度);
  • 需要滚动才能看完整个方法;
  • 存在多层嵌套;
  • 用注释来解释每个代码段"在做什么"。

为什么有害:难以理解、难以隔离测试、修改的副作用难以预料,且内部往往藏着重复逻辑。源码中_check_method_length()(第 198–218 行)会在超过 50 行时报 HIGH 严重度、超过 30 行报 MEDIUM,建议直接应用 Extract Method 拆分。

重构手法:Extract Method、Replace Temp with Query、Introduce Parameter Object、Replace Method with Method Object、Decompose Conditional。

重构前:

function processOrder(order) { // 订单校验(20 行) if (!order.items) throw new Error('No items'); if (order.items.length === 0) throw new Error('Empty order'); // ... 更多校验 // 汇总计算(30 行) let subtotal = 0; for (const item of order.items) { subtotal += item.price * item.quantity; } // ... 税费、运费、折扣 // 发送通知(20 行) // ... email 逻辑 }

重构后:

function processOrder(order) { validateOrder(order); const totals = calculateOrderTotals(order); sendOrderNotifications(order, totals); return { order, totals }; }

2.2 过大类(Large Class)

识别特征:

  • 实例字段超过7–10 个
  • 方法超过15–20 个
  • 类名含糊(Manager、Handler、Processor);
  • 部分方法根本不用到某些实例字段。

检测阈值(来自 detect-smells.py 的_check_class_size(),第 292–318 行):

行数 > 300 方法数 > 10 字段数 > 10

其中类行数超过 300 直接判定为 HIGH 严重度。这与文档中"代码行数 > 300、方法数 > 15、字段数 > 10"的速查标准相互印证。

为什么有害:违反单一职责原则、难以测试、变更波及无关功能、部分难以复用。

重构手法:Extract Class、Extract Subclass、Extract Interface。

2.3 基本类型偏执(Primitive Obsession)

识别特征:

  • 用基本类型表达领域概念(用string表示 email、用int表示金额);
  • 用基本类型数组代替对象;
  • 用字符串常量表示类型码;
  • 魔法数字 / 魔法字符串。

为什么有害:类型层面没有校验、业务逻辑散落在整个代码库、容易传入错误的值、领域概念缺失。detect-smells.py 中_detect_magic_numbers()(第 338–367 行)会把出现在运算或比较中、且不在白名单(0, 1, -1, 2, 100, true, false...)里的数值字面量标记为 LOW 严重度坏味道,建议替换为具名常量。

重构手法:Replace Primitive with Object、Replace Type Code with Class、Replace Type Code with Subclasses、Replace Type Code with State/Strategy。

重构前:

const user = { email: 'john@example.com', // 只是字符串 phone: '1234567890', // 只是字符串 status: 'active', // 魔法字符串 balance: 10050 // 用整数表示分 };

重构后:

const user = { email: new Email('john@example.com'), phone: new PhoneNumber('1234567890'), status: UserStatus.ACTIVE, balance: Money.cents(10050) };

2.4 过长参数列表(Long Parameter List)

识别特征:

  • 方法参数超过4 个(detect-smells.py 中max_parameters: 4_detect_long_parameter_lists()第 220–256 行会在参数超过 6 个时报 HIGH、4–6 个报 MEDIUM,且自动过滤 Python 的self/cls);
  • 某些参数总是成对出现;
  • 布尔标志位改变方法行为;
  • 频繁传递 null/undefined。

为什么有害:难以正确调用、参数顺序易混淆、说明方法职责过多、新增参数困难。

重构手法:Introduce Parameter Object、Preserve Whole Object、Replace Parameter with Method Call、Remove Flag Argument。

重构前:

function createUser(firstName, lastName, email, phone, street, city, state, zip, isAdmin, isActive, createdBy) { // ... }

重构后:

function createUser(personalInfo, address, options) { // personalInfo: { firstName, lastName, email, phone } // address: { street, city, state, zip } // options: { isAdmin, isActive, createdBy } }

2.5 数据泥团(Data Clumps)

识别特征:

  • 相同的 3 个以上字段反复一起出现;
  • 参数总是结伴旅行;
  • 类中有一部分字段天然属于彼此。

为什么有害:处理逻辑重复、缺少抽象、难以扩展,并且提示存在隐藏的类。

重构手法:Extract Class、Introduce Parameter Object、Preserve Whole Object。

示例:

// 数据泥团:坐标 (x, y, z) function movePoint(x, y, z, dx, dy, dz) { } function scalePoint(x, y, z, factor) { } function distanceBetween(x1, y1, z1, x2, y2, z2) { } // 抽出 Point3D 类 class Point3D { constructor(x, y, z) { } move(delta) { } scale(factor) { } distanceTo(other) { } }

三、滥用面向对象(OO Abusers):OOP 原则被扭曲

3.1 Switch 语句(Switch Statements)

识别特征:

  • 冗长的 switch/case 或 if/else 链;
  • 同一 switch 出现在多个地方;
  • 针对类型码做 switch;
  • 新增 case 必须到处修改。

为什么有害:违反开闭原则、修改波及所有 switch 出现处、难以扩展、往往暗示缺失多态。detect-smells.py 的_detect_switch_statements()(第 429–469 行)对 Python 检测连续 4 个以上的if/elif ==链、对 JS/TS 检测 4 个以上case的 switch,统一给出 MEDIUM 严重度并建议 Replace Conditional with Polymorphism。

重构手法:Replace Conditional with Polymorphism、Replace Type Code with Subclasses、Replace Type Code with State/Strategy。

重构前:

function calculatePay(employee) { switch (employee.type) { case 'hourly': return employee.hours * employee.rate; case 'salaried': return employee.salary / 12; case 'commissioned': return employee.sales * employee.commission; } }

重构后:

class HourlyEmployee { calculatePay() { return this.hours * this.rate; } } class SalariedEmployee { calculatePay() { return this.salary / 12; } }

3.2 临时字段(Temporary Field)

识别特征:实例字段只在部分方法中使用;字段按条件设置;为特定场景做复杂的初始化。

为什么有害:字段存在却可能是 null、对象状态难以理解、暗示隐藏的条件逻辑。

重构手法:Extract Class、Introduce Null Object、Replace Temp Field with Local。

3.3 被拒绝的遗赠(Refused Bequest)

识别特征:子类不使用继承来的方法/数据;子类重写父类方法使其空转;用继承做代码复用而非表达 IS-A 关系。

为什么有害:抽象错误、违反里氏替换原则、层级关系具有误导性。

重构手法:Push Down Method/Field、Replace Subclass with Delegate、Replace Inheritance with Delegation。

3.4 异曲同工的类(Alternative Classes with Different Interfaces)

识别特征:两个类做着相似的事;对同一概念使用不同方法名;本可互换使用。

为什么有害:重复实现、缺少统一接口、切换困难。

重构手法:Rename Method、Move Method、Extract Superclass、Extract Interface。


四、阻碍变更(Change Preventers):改一处要牵连一片

这类坏味道的核心危害是"改一个东西需要连带改许多其他东西",变更成本高、风险大。

4.1 发散式变更(Divergent Change)

识别特征:一个类因为多种不同原因被修改;不同领域的变更都会触发对同一类的编辑;类是"上帝类"。

为什么有害:违反单一职责、变更频率高、合并冲突多。

重构手法:Extract Class、Extract Superclass、Extract Subclass。

示例:User类因为认证变更、资料变更、计费变更、通知变更而被反复修改 → 应抽出AuthServiceProfileServiceBillingServiceNotificationService

4.2 霰弹式修改(Shotgun Surgery)

识别特征:一次变更要求编辑多个类;小功能需要改动 10+ 个文件;修改分散、难以找全。

为什么有害:容易遗漏、耦合度高、易出错。检测提示:如果给某处"增加一个字段"需要改动 5 个以上文件,就应当警惕。

重构手法:Move Method、Move Field、Inline Class。

4.3 平行继承体系(Parallel Inheritance Hierarchies)

识别特征:在一个层级中新建子类,就必须在另一个层级中新建对应子类;类名前缀互相呼应(如DatabaseOrderDatabaseProduct)。

为什么有害:双重维护、层级间强耦合、容易漏改其中一边。

重构手法:Move Method、Move Field、消除其中一个层级。


五、多余之物(Dispensables):没有存在必要的东西

5.1 过多注释(Comments)

识别特征:注释解释"代码做了什么";被注释掉的代码;永远留着的 TODO/FIXME;注释里写道歉的话。

为什么有害:注释会撒谎(与代码脱节)、代码应当自文档化、死代码造成困惑。

重构手法:Extract Method(用方法名表达意图)、Rename、删除被注释代码、Introduce Assertion。

好注释 vs 坏注释:

// 坏:解释"做了什么" // 遍历用户并检查是否活跃 for (const user of users) { if (user.status === 'active') { } } // 好:解释"为什么" // 只保留活跃用户——非活跃用户由清理任务处理 const activeUsers = users.filter(u => u.isActive);

detect-smells.py 的_detect_excessive_comments()(第 369–389 行)会用正则匹配set/get/return/loop/iterate/check/if/increment/decrement等"解释做什么"的注释动词,将其标记为 LOW 严重度坏味道。

5.2 重复代码(Duplicate Code)

识别特征:同一代码出现在多处;相似代码只有细微差异;复制粘贴模式。

为什么有害:修 Bug 要修多处、不一致风险、代码库膨胀。检测规则:任何重复 3 次以上的代码都应被抽出。detect-smells.py 的_detect_duplicate_code()(第 491–513 行)对规范化后长度超过 20 字符、出现至少 3 次的行进行标记。

重构手法:Extract Method、Extract Class、Pull Up Method(层级内)、Form Template Method。

5.3 懒散类(Lazy Class)

识别特征:类做的事情不足以证明其存在;没有附加价值的包装层;过度设计的产物。

为什么有害:维护开销、不必要的间接层、无益的复杂度。

重构手法:Inline Class、Collapse Hierarchy。

5.4 死代码(Dead Code)

识别特征:不可达代码;未使用的变量/方法/类;被注释的代码;不可能成立的条件之后的代码。

为什么有害:造成困惑、维护负担、拖慢理解速度。detect-smells.py 的_detect_dead_code()(第 515–539 行)会识别TODO...deleteFIXME...removeif False:if (false)等模式。

重构手法:Remove Dead Code、Safe Delete。

检测思路:

# 查找未使用的导出 # 查找未使用的函数 # 留意 IDE 的 "unused" 警告

5.5 过度泛化(Speculative Generality)

识别特征:只有一个子类的抽象类;"为将来准备"的未使用参数;只做转发的委托方法;为单一场景搭的"框架"。

为什么有害:无益的复杂度、违反 YAGNI(You Ain't Gonna Need It)、更难理解。

重构手法:Collapse Hierarchy、Inline Class、Remove Parameter、Rename Method。


六、耦合器(Couplers):类与类之间的过度纠缠

6.1 依恋情结(Feature Envy)

识别特征:方法使用另一个类的数据多于自己的;大量调用别的对象的 getter;数据与行为分离。

为什么有害:行为放置位置错误、封装性差、难以维护。

重构手法:Move Method、Move Field、Extract Method(然后移动)。

重构前:

class Order { getDiscountedPrice(customer) { // 大量使用 customer 的数据 if (customer.loyaltyYears > 5) { return this.price * customer.discountRate; } return this.price; } }

重构后:

class Customer { getDiscountedPriceFor(price) { if (this.loyaltyYears > 5) { return price * this.discountRate; } return price; } }

6.2 过度亲密(Inappropriate Intimacy)

识别特征:类互相访问彼此的私有部分;双向引用;子类对父类了解过多。

为什么有害:高耦合、变更级联、很难独立修改其中一个。

重构手法:Move Method、Move Field、Change Bidirectional to Unidirectional、Extract Class、Hide Delegate。

6.3 消息链(Message Chains)

识别特征:长调用链a.getB().getC().getD().getValue();客户端依赖导航结构;"列车残骸"式代码。

为什么有害:脆弱(任何环节变化都破坏整条链)、违反迪米特法则、与结构强耦合。detect-smells.py 的_detect_message_chains()(第 471–489 行)用正则(\w+(?:\.\w+\([^)]*\)){3,})捕获连续 3 个以上方法调用的链(long_chain_length: 3),标记为 MEDIUM 并建议 Hide Delegate。

重构手法:Hide Delegate、Extract Method、Move Method。

示例:

// 坏:消息链 const managerName = employee.getDepartment().getManager().getName(); // 好:隐藏委托 const managerName = employee.getManagerName();

6.4 中间人(Middle Man)

识别特征:类只负责转发给别的类;一半以上方法都是委托;没有附加价值。

为什么有害:不必要的间接层、维护开销、架构混乱。

重构手法:Remove Middle Man、Inline Method。


七、按严重度分级处置:把力气花在刀刃上

坏味道不是都要立即处理。文档给出了四档严重度模型,detect-smells.py 的SmellSeverity枚举(源码第 35–41 行)与报告输出的分级完全对应,且脚本会自动统计 Critical/High/Medium/Low 的数量并给出处置建议:

严重度描述行动
Critical(严重)阻塞开发、引发 Bug立即修复
High(高)显著的维护负担在当前迭代内修复
Medium(中)明显但可控安排到近期工作
Low(低)轻微不便顺手修复

实际处置优先级可参考 refactor/SKILL.md 的分阶段策略:

  • 快速胜利(低风险高价值):重命名变量、抽取明显重复、删除死代码;
  • 结构性改进(中风险):从长方法中抽取方法、引入参数对象、把方法移到合适的类;
  • 架构性变更(高风险):用多态替换条件、抽取类、引入设计模式。

八、自动化检测:用脚本扫描坏味道

手工扫描难免遗漏,仓库为此打包了两个可执行脚本(Python 3 标准库实现,无第三方依赖),支持 Python / JavaScript / TypeScript 三类文件(扩展名.py/.js/.jsx/.ts/.tsx)。

8.1 坏味道检测器

dectect-smells.py 的用法:

# 分析单个文件 python scripts/detect-smells.py <file> # 分析整个目录 python scripts/detect-smells.py --dir <directory> # 详细模式,附带代码片段 python scripts/detect-smells.py -v <file> # JSON 输出(便于接入 CI 或脚本) python scripts/detect-smells.py -j <file>

它检测的坏味道与本文五大家族对应,完整清单(SmellType枚举,源码第 43–58 行)包括:Long Method、Long Parameter List、Duplicate Code、Large Class、Dead Code、Complex Conditional、Magic Number/String、Feature Envy、Excessive Comments、Deeply Nested Code、Primitive Obsession、Data Clumps、Switch Statement、Message Chain。可配置阈值集中在THRESHOLDS字典(第 101–110 行):方法 30/50 行、参数 4 个、大类 300 行/10 方法、嵌套深度 4、链长 3、重复最小 5 行。

8.2 复杂度分析器

analyze-complexity.py 用于量化重构效果,支持三种模式:

# 分析单个文件 python scripts/analyze-complexity.py <file> # 对比重构前/后两个文件 python scripts/analyze-complexity.py <before_file> <after_file> # 分析整个目录 python scripts/analyze-complexity.py --dir <directory>

它输出六项指标:

  • 圈复杂度(Cyclomatic Complexity):按 McCabe 公式CC = E - N + 2P的简化实现,统计决策点 + 1;
  • 认知复杂度(Cognitive Complexity):考虑嵌套深度与控制流中断,衡量理解难度;
  • 可维护性指数(Maintainability Index,0–100):基于 Halstead 体量、圈复杂度与 LOC 的简化计算,85+ 高度可维护、65–84 中等、50–64 难以维护、0–49 极难维护;
  • 代码行数、函数数量、平均函数长度。

对比模式下脚本会自动给出"可维护性提升/复杂度降低/函数变小"的评估结论(print_comparison(),第 376–439 行),正好对应 refactoring-plan.md 中"重构前后指标对比表"的填写需求。


九、快速自查清单

在扫描代码时逐项过一遍这份清单(源自原文档的完整清单,未删减):

  • 是否存在超过 30 行的方法?
  • 是否存在超过 300 行的类?
  • 是否存在超过 4 个参数的方法?
  • 是否存在重复的代码块?
  • 是否存在针对类型码的 switch/case?
  • 是否存在未使用的代码?
  • 是否存在大量使用其他类数据的方法?
  • 是否存在过长的调用链?
  • 是否存在解释"做了什么"而非"为什么"的注释?
  • 是否存在本应是对象的原始类型?

十、坏味道 → 重构手法速查

识别坏味道只是第一步,接下来需要在 refactoring-catalog.md 中选择对应手法(该目录为每个重构都提供了动机、逐步机制与代码示例),并用 refactoring-plan.md 模板组织成"目标 → 坏味道 → 技术 → 步骤 → 风险 → 回滚"的完整计划:

坏味道主要重构手法备选手法
Long MethodExtract MethodReplace Temp with Query
Duplicate CodeExtract MethodPull Up Method
Large ClassExtract ClassExtract Subclass
Long Parameter ListIntroduce Parameter ObjectPreserve Whole Object
Feature EnvyMove MethodExtract Method + Move
Data ClumpsExtract ClassIntroduce Parameter Object
Primitive ObsessionReplace Primitive with ObjectReplace Type Code
Switch StatementsReplace Conditional with PolymorphismReplace Type Code
Temporary FieldExtract ClassIntroduce Null Object
Message ChainsHide DelegateExtract Method
Middle ManRemove Middle ManInline Method
Divergent ChangeExtract ClassSplit Phase
Shotgun SurgeryMove MethodInline Class
Dead CodeRemove Dead Code
Speculative GeneralityCollapse HierarchyInline Class

十一、进一步阅读

  • refactor/SKILL.md — 六阶段重构工作流:研究 → 测试评估 → 坏味道识别 → 计划 → 增量实施 → 回顾;
  • refactoring-catalog.md — 每个坏味道对应的完整重构机制与代码示例;
  • refactoring-plan.md — 带风险分级、回滚计划与指标对比表的重构计划模板;
  • detect-smells.py — 坏味道自动检测脚本;
  • analyze-complexity.py — 复杂度与可维护性度量脚本。

参考书目:Fowler, M. (2018).Refactoring: Improving the Design of Existing Code(2nd ed.);Kerievsky, J. (2004).Refactoring to Patterns;Feathers, M. (2004).Working Effectively with Legacy Code

【免费下载链接】claude-howtoA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-howto

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询