关于 codeprobe-code-smells
用于检查代码异味与反模式的 codeprobe 技能,覆盖可维护性、面向对象设计、耦合和可读性,并支持配置检测阈值。
主要功能
- 01检测过长方法与大型类
- 02查找数据团块与基本类型偏执
- 03检查继承与对象耦合问题
- 04识别死代码与过度抽象
- 05标记魔法数字与深层嵌套
适用场景
- 01审查代码中的可维护性风险
- 02寻找简化复杂方法的机会
- 03重构前检查代码
- 04按项目配置异味检测阈值
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ machineroom-dev/ codeprobe --skill codeprobe-code-smells安装后在 Claude Code 中输入/codeprobe-code-smells确认已加载。
详细介绍
独立模式
如果直接调用(而非通过协调器调用),必须先:
- 读取
../codeprobe/shared-preamble.md(相对于此 SKILL.md 的位置解析——即同级的codeprobe技能目录,而非用户的项目),了解输出约定、执行模式和限制。 - 根据项目的技术栈,从
../codeprobe/references/(按相同方式解析)加载适用的参考文件。 - 除非用户另有指定,否则默认为
full模式。
代码异味与反模式检测器
领域范围
此子技能检测以下类别中的代码异味与反模式:
- 臃肿问题 — 长方法、大类、数据泥团、基本类型偏执
- 面向对象滥用 — 特性嫉妒、不当亲密、拒绝继承
- 变更阻碍因素 — 霰弹式修改、发散式变更
- 可舍弃项 — 死代码、投机性通用化、中间人
- 耦合问题 — 时间耦合
- 可读性 — 魔法数字、布尔盲区、深层嵌套
不会标记的内容
- 生成的代码 — 迁移文件、编译输出、供应商目录(
vendor/、node_modules/、dist/、build/、.next/)和自动生成的文件(例如 GraphQL 代码生成、Prisma 客户端)。 - 包含冗长设置方法的测试文件 — 测试上下文有所不同;用于安排测试数据的长
setUp()或beforeEach()方法属于预期且可接受的情况。 - 包含许多条目的配置文件 — 含有 50 个键值对的配置文件不属于“大类”异味。
- 数据迁移文件 — 这类文件本质上采用过程式写法,通常包含长方法。
- 提交到仓库中的第三方代码(例如,随仓库一同提供的库)。
- 已由
codeprobe-solid或codeprobe-architecture标记的结构问题 — 大类也可能被标记为违反 SRP 或属于上帝对象。此子技能仍应检测并报告这些问题,但协调器会对同一位置重叠的发现进行去重。
检测说明
可配置阈值
开始分析前,检查项目根目录中是否存在 .codeprobe-config.json 文件。如果存在,加载 severity_overrides 部分以调整以下默认值:
| 阈值 | 配置键 | 默认值 |
|---|---|---|
| 长方法 LOC 限制 | long_method_loc | 30 |
| 大类 LOC 限制 | large_class_loc | 300 |
| 深层嵌套最大层数 | deep_nesting_max | 3 |
臃肿问题
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重性 |
|---|---|---|---|---|---|
SMELL | 长方法 | 函数/方法超过 LOC 阈值 | 统计每个函数/方法主体中的行数(不包括空行和单行注释)。与 long_method_loc 阈值比较。对于超过阈值 2 倍的方法,提升为主要级别。 | > 30 LOC | 次要 |
SMELL | 大类 | 类超过 LOC 阈值 | 统计每个类定义中的总行数。与 large_class_loc 阈值比较。对于超过阈值 2 倍的类,提升为主要级别(如果尚未达到该级别)。绝不提升为严重级别——大类属于可维护性问题,而非生产缺陷。 | > 300 LOC | 主要 |
SMELL | 数据泥团 | 相同的 3 个以上参数在 3 个以上位置一同传递 | 搜索函数/方法签名。找出在 3 个以上不同函数签名或调用位置中共同出现的 3 个以上参数组。应将其提取为参数对象或值对象。 | 3 个以上参数,出现 3 次以上 | 次要 |
SMELL | 基本类型偏执 | 在适合使用值对象的场景中使用字符串/整数 | 查找表示领域概念的字符串/整数变量:电子邮件地址(通过内联正则表达式验证)、金额(数值与货币分别传递)、电话号码、在多个位置进行比较的状态字符串、邮政编码、通过多层代码以普通字符串形式传递的 UUID。 | 模式识别 | 次要 |
面向对象滥用
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重程度 |
|---|---|---|---|---|---|
SMELL | 特性嫉妒 | 方法访问另一个对象数据的次数达到自身数据的 3 倍或以上 | 统计方法引用 $other->property 或 other.property 的次数,与引用 $this->property 或 this.property(或 self.)的次数。如果外部引用次数达到内部引用次数的 3 倍或以上,该方法很可能应该属于另一个类。 | 外部访问 3 次或以上 | 轻微 |
SMELL | 不当亲密 | 类访问另一个类的私有/受保护内部成员 | 搜索基于反射的访问(setAccessible(true)、访问受保护字段的 __get、__set 魔术方法)、友元类模式,或直接访问按惯例应为私有的属性(在 Python/JS 中以 _ 为前缀)。 | 出现任意一次 | 严重 |
SMELL | 拒绝继承 | 子类继承了父类,却未使用父类的大多数方法 | 检查子类:如果父类有 N 个公共方法,而子类重写的方法不到其中的 30%,且大多数情况下也不调用 super/parent::,这表明该子类可能并不需要继承关系。 | 父类方法大多未使用 | 轻微 |
变更阻碍因素
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重程度 |
|---|---|---|---|---|---|
SMELL | 霰弹式修改 | 修改一个概念需要编辑 5 个或更多文件 | 搜索某个单一概念(例如字段名、状态值、业务规则)是否出现在许多文件中。如果相同的常量、列名或业务术语出现在 5 个或更多文件中,且未集中到单一事实来源中,则标记出来。 | 一个概念涉及 5 个或更多文件 | 严重 |
SMELL | 发散式变化 | 一个类因 3 个或更多不相关的原因而被修改 | 检查大型类(超过 200 行代码)。确认其方法是否围绕不同且互不相关的职责聚集。如果一个类同时处理用户身份验证、电子邮件格式化和报告生成,那么它存在发散式变化——这 3 个领域中的任意一个发生变化都会导致该类需要修改。 | 3 个或更多不同职责 | 严重 |
可有可无的部分
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重程度 |
|---|---|---|---|---|---|
SMELL | 死代码 | 不可达分支、未使用的导入、已注释掉的代码块 | 搜索以下内容:(1) 文件中其他位置从未引用其符号的 import/use/require 语句;(2) 已注释掉的代码块(连续 3 行或更多包含代码语法而非文档的注释行);(3) 在代码库中任何地方都未调用的函数/方法(使用 Grep 搜索整个项目);(4) if (false) 或 if (0) 代码块,以及无条件 return/throw/exit 后的不可达代码。 | 出现任意一次 | 轻微 |
SMELL | 投机式通用化 | 抽象/接口只有一个实现,且看不到第二个实现的可能 | 搜索只有一个具体实现的接口、抽象类或泛型类型参数。如果该抽象未出现在 DI 容器配置或测试模拟对象中,且领域本身也未显示未来会有其他变体,则将其标记为过早抽象。 | 只有一个实现 | 建议 |
SMELL | 中间人 | 只将调用委托给另一个类、不添加任何逻辑的类 | 查找所有方法都只是调用注入依赖中的相同方法并返回结果,且不添加任何逻辑、验证、转换或错误处理的类。该类增加了不必要的间接层。 | 所有方法均为纯委托 | 轻微 |
耦合问题
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重程度 |
|---|---|---|---|---|---|
SMELL | 时序耦合 | 方法必须按特定顺序调用,但没有任何机制强制执行 | 查找以下模式:(1)必须先调用方法 A 再调用方法 B,但没有编译时或运行时检查;(2)必须先调用 init()/setup() 再调用 process(),但类允许先调用 process();(3)多个顺序调用的方法共享可变状态,调整调用顺序会导致错误。检查是否有“必须先调用 X”或“在 Y 之后调用”等注释。 | 隐式顺序依赖 | 主要 |
可读性
| ID 前缀 | 异味 | 信号 | 检测方法 | 默认阈值 | 严重程度 |
|---|---|---|---|---|---|
SMELL | 魔法数字 | 业务逻辑中使用未命名常量的硬编码数值/字符串字面量 | 搜索条件、计算或业务逻辑中使用的数值字面量(0、1、-1 除外)和字符串字面量。标记逻辑路径中未定义为命名常量的值,例如 86400、3.14159、"pending"、0.15。排除:数组索引、取值为 0/1 的循环边界、数学库中的常见数学常量。 | 逻辑路径中的任意值 | 次要 |
SMELL | 布尔盲点 | 方法包含 2 个或更多布尔参数 | 搜索包含 2 个或更多 bool/boolean 参数的函数/方法签名。像 process(true, false, true) 这样的调用点难以理解。建议改用命名参数、枚举或选项对象。 | 2 个或更多布尔参数 | 次要 |
SMELL | 深层嵌套 | 缩进层级超过阈值 | 统计每个函数的嵌套深度:嵌套在另一结构中的每个 if、for、while、foreach、switch、try、match 都会增加一级。嵌套深度超过 deep_nesting_max 阈值时标记。建议使用提前返回、守卫子句或提取方法。 | > 3 级 | 次要 |
ID 前缀和修复提示示例
所有发现项都使用 SMELL- 前缀,并按顺序编号:SMELL-001、SMELL-002 等。
修复提示示例
- “将
UserService@register中的第 45-90 行提取到私有方法validateAndNormalizeInput()中——该方法有 120 行代码,处理 3 件互不相关的事情:输入验证(第 45-65 行)、数据规范化(第 66-80 行)和持久化(第 81-90 行)。将持久化保留在register()中,并提取另外两个职责。” - “将
app/Services/CacheService.php第 55 行的魔法数字86400替换为命名常量SECONDS_PER_DAY = 86400,并在类的顶部定义该常量。” - “重构
OrderProcessor.php(第 30 行)中的processOrder(bool $isExpress, bool $requiresSignature, bool $isFragile),使其接受ShippingOptions值对象,而不是 3 个布尔参数。创建一个包含命名属性的ShippingOptions类。” - “删除
PaymentGateway.php第 88-105 行的注释代码块——这是之前实现遗留的死代码。如有需要,可从版本控制中恢复。” - “在
ReportGenerator.php中,第 20 行的generate()方法有 95 行代码。将数据获取逻辑(第 25-50 行)提取到fetchReportData(),并将格式化逻辑(第 51-85 行)提取到formatReport()。generate()方法应负责协调这两个步骤。”
评论
支持 Markdown