寻找你代码中的臭味:一个让 AI 帮你嗅出架构腐化的开源 Skill

你有没有过这样的经历:接手一个"跑了三年没人敢动"的项目,打开代码仓库一看——

src/ 下面 200 多个文件平铺在一个目录里,没有分层,没有模块边界。一个叫 UserService 的类 1800 行,发邮件、对接支付、状态管理全塞在里面,还挂着三个 TODO 标着"后面要重构"。业务逻辑全堆在 Service 层,Model 类只剩 getter 和 setter,贫血得像张纸。数据库查询藏在 for 循环里,每循环一次发一条 SQL。你问老员工这模块谁负责,得到一句:"这个……已经没人记得了。"

Martin Fowler 把这类问题叫做"代码坏味道"(Code Smell)。Brian Foote 和 Joseph Yoder 在 1997 年的论文里给了一个更直白的名字:Big Ball of Mud(大泥球)。

祖传的手搓代码是这样。到了 vibe coding 时代,AI 生成的代码也没好到哪去,能力差一些的模型甚至更糟糕。

闻到臭味容易,定位臭源难。更难的是知道该先处理哪个、怎么处理。

今天介绍一个叫 /smell 的开源 Skill,专门干这件事。

它不是为你的新项目设计架构,而是对你已有的项目的分析架构,找到不合理的反模式的设计。

它是干什么的

/smell 是一个可以嵌入 Claude Code、Codex、Cursor 等 AI 编程 Agent 的 Skill。在项目里输入 /smell 或"帮我找找代码里的坏味道",它会扫描代码库,从架构层面到代码层面做一轮完整检测,最后输出一份 Markdown 报告。

报告精确到文件和行号:哪个模块是 God Object,哪里有循环依赖,哪段代码是 N+1 查询,哪个类违反了单一职责。每个问题都附带代码证据和重构建议。

知识库整合了软件架构领域几十年的积累:

  • Martin Fowler 的《重构》和《分析模式》
  • Robert C. Martin 的 SOLID 原则
  • Eric Evans 的领域驱动设计(DDD)
  • Foote & Yoder 的 Big Ball of Mud 论文
  • Clean Architecture、Onion Architecture、Hexagonal Architecture 等主流架构风格
  • 一套算法复杂度反模式检测规则

相当于把一个资深架构师十几年攒下的"闻臭味"经验,塞进了一个命令里。

八个检测维度

1. 架构级反模式

最严重的层级。Big Ball of Mud(根本没有架构)、Distributed Monolith(声称是微服务,改一个功能得同时部署五个)、Anemic Domain Model(贫血模型,逻辑全在 Service 层,Domain 对象只剩 getter/setter)、Violated Layer Boundaries(层级穿透,领域层直接 import 基础设施层)。

2. 耦合问题

循环依赖(A import B,B 又 import A)、Content Coupling(直接改另一个模块的内部状态)、Common Coupling(到处用的全局变量和单例)、Stamp Coupling(传一整个大对象进去只用两个字段)。

3. 内聚性问题

God Object(一个类 800 行、30 个公开方法,管了十件不相关的事)、Shotgun Surgery(改一个需求要动 7 个文件)、Feature Envy(一个方法调别人家方法比调自己的还多)、Data Clumps(同样的参数组合反复出现在不同函数签名里)。

4. 设计原则违反

SOLID 原则的各种违反场景、DRY 重复代码、KISS 过度工程化、YAGNI 为假设的未来需求提前写了一堆抽象。

5. 代码级坏味道

Long Method(超过 50 行的函数)、Long Parameter List(参数超过 4 个)、Primitive Obsession(用 string 表示 Email、int 表示金额)、Magic Numbers(if (status == 3) 到处都是)、Dead Code(注释掉的代码块和未使用的 import)。

6. 测试健康度

零测试覆盖的模块、测试耦合了实现细节(测私有方法、mock 内部调用)、依赖真实 I/O 的慢测试。

7. 命名质量

满屏的 ManagerHandlerUtilHelperService——等于没起名。还有 snake_casecamelCase 混用、同一概念在不同地方用不同名字。

8. 算法复杂度热点

这部分我觉得最有价值。很多工具只管"代码丑不丑",/smell 还管"代码跑不跑得动":

  • N+1 查询:循环里发数据库请求,100 条数据 = 101 次 SQL
  • 嵌套循环 O(n²):双层 for,数据量一大就原地爆炸
  • 循环内线性扫描:includes() 写在循环里,本该用 Set 做 O(1) 查找
  • 循环内排序:每次迭代都 sort() 一遍,K × O(n log n)
  • 渲染路径重计算:React/Vue 组件里 .filter().map().sort() 没做 memoization
  • 选错了数据结构:该用 Map 的地方用了 Array 做 O(n) 查找

怎么用

在 Claude Code 中打开项目,输入:

1
/smell

它会先问分析范围:

1
2
3
4
5
你想分析哪个范围?
A. 整个项目(全面但耗时)
B. 指定模块/目录
C. 仅分析最近改动的文件(git diff)
D. 仅分析架构级问题(跳过代码级坏味道)

选完之后它会启动多个并行探索任务:扫描项目结构、分析依赖关系、检测模块内聚性、识别反模式签名、评估测试覆盖,同时跑。

分析完成后在 tasks/ 目录下生成报告,比如 tasks/smell-report-2026-05-28-1430.md,终端同时打印摘要:

看到摘要你就知道该从哪下手了。可以直接让 AI 按分析结果做架构优化:

重构完成后 AI 会给出修改报告:

报告长什么样

Executive Summary:检测到的架构风格、整体健康评估、最关键的 3-5 个问题,三段话说完。

架构风格识别:分层架构?模块化单体?微服务?六边形?Clean Architecture?还是 Big Ball of Mud。用一张表对比"期望 vs 现实"。

严重度分级清单:🔴 Critical(必须修)、🟡 Warning(应该修)、🔵 Suggestion(建议修)。

逐条问题分析:类别、严重度、反模式名称、文件行号、违反的原则、代码证据、重构建议。每一条都回答三个问题:这是什么坏味道?为什么它是坏味道?怎么改?

依赖图分析:模块间依赖关系、循环依赖路径、耦合热点。

模块健康度记分卡:每个模块的代码行数、God Object 风险、耦合度、内聚性、测试覆盖率。

Smell 分布统计:八个维度各发现多少问题,按严重度排列。

重构路线图:当前 Sprint 立即行动、1-3 个月短期改善、3-12 个月长期演进。分阶段治理,不用一口气全改完。

一个实际场景

接手一个迭代了两年的 Go 项目,不确定架构质量,跑一遍:

1
/smell 分析这个 Go 项目的架构质量

它发现:

  1. internal/model/ 下的结构体全是贫血模型,只有字段没有方法,逻辑全在 internal/service/。典型的 Anemic Domain Model,应该把行为移回领域对象。
  2. internal/service/order.go:233 有 N+1 查询,遍历订单时逐条查商品。改成 WHERE id IN (...) 批量加载就完了。
  3. pkg/authpkg/user 互相导入,循环依赖。抽取一个公共接口可以打破循环。
  4. internal/handler/ 下 6 个文件都有大段重复的参数校验逻辑,违反 DRY。提一个公共校验中间件。
  5. 23 处魔法数字,if order.Status == 3 随处可见。定义个 const StatusCompleted = 3 或者用枚举。

报告附带了分阶段的重构路线图。你按优先级一步步来就行,不用面对整个代码库发呆。

快捷模式

只想看致命伤,不等全面分析:

1
/smell 快速检查一下架构

跳过代码级和命名级检测,只跑架构反模式、循环依赖、God Object、N+1 查询这些 Critical 级别。几分钟出结果。

也可以只关注一个维度:

1
/smell 只分析算法复杂度热点

就只找嵌套循环、N+1 查询、选错数据结构这些性能问题。

为什么需要它

有人会说:"这些坏味道我自己也能看出来啊。"

如果你有十年架构经验、Fowler 和 Uncle Bob 的书都读过、反模式论文烂熟于心,当然可以。但大多数团队不是这样。

团队里的初中级开发看不出 Anemic Domain Model 有什么问题,他们觉得"Service 写逻辑、Model 放数据"天经地义。即使你自己有经验,一个 10 万行的项目你也看不过来。看了三天同一套代码,嗅觉已经疲劳了。Code Review 通常只关注功能正确性和代码风格,没人在 PR Review 的时候画依赖图、算圈复杂度。

/smell 填补的就是这个空缺。它给你证据,你自己做决策。每个问题都标了严重度,你根据优先级和资源决定修哪些。

安装

这个 Skill 内置在 goal-workflow 的 skills 集合中。已配置 goal-workflow 的直接用 /smell

安装命令:

1
npx skills add smallnest/goal-workflow --skill smell

用 Claude Code 的话,也可以直接把 SKILL.md 放到 .claude/skills/smell/ 目录下,立刻生效。

写在最后

代码坏味道是一天天堆出来的。每次赶 deadline 时的妥协,每次"只加一个 if"的侥幸,每次 copy-paste 省下的五分钟,都在给代码库增重。

治理的难点从来不是"要不要做",而是"从哪开始"。/smell 给你一张问题地图,标清楚了臭在哪、有多严重、该按什么顺序清理。路还是得你自己走。

代码是给人读的,顺便让机器执行。如果你自己都不想读自己的代码,让 AI 先帮你闻闻吧。