smell

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Smell — Architecture Bad Smell Detector

Smell — 架构坏味道检测器

Analyze a codebase to find violations of software architecture principles, anti-patterns, code "bad smells," and algorithmic complexity hotspots. Produce a comprehensive, actionable markdown report.
Knowledge base: This skill encodes architectural patterns, anti-patterns, code smells, and algorithmic complexity heuristics drawn from industry research and practice.

分析代码库,找出软件架构原则违规、反模式、代码「坏味道」以及算法复杂度热点问题。生成一份全面且可落地的Markdown报告。
知识库: 该技能整合了来自行业研究与实践的架构模式、反模式、代码坏味道以及算法复杂度启发式规则。

The Job

工作流程

  1. Understand the scope — ask what part of the project to analyze (full project, specific module, or recent changes)
  2. Scan the codebase using
    find
    ,
    grep
    , and
    Agent
    (Explore subagent) to gather evidence
  3. Identify architectural smells and anti-patterns
  4. Generate a detailed markdown report saved to
    tasks/smell-report-[timestamp].md
  5. Present a summary of findings to the user

  1. 明确分析范围 —— 询问用户需要分析项目的哪一部分(完整项目、特定模块或最近变更内容)
  2. 使用
    find
    grep
    Agent
    (Explore子代理)扫描代码库以收集证据
  3. 识别架构坏味道与反模式
  4. 生成详细的Markdown报告并保存至
    tasks/smell-report-[timestamp].md
  5. 向用户呈现发现结果的摘要

Step 1: Scope Clarification

步骤1:范围确认

Ask the user:
What scope should I analyze?
  A. Entire project (thorough, may take time)
  B. Specific module/directory: [please specify]
  C. Only recently changed files (git diff)
  D. Only architectural-level issues (skip low-level code smells)
If the user doesn't specify, default to option A for small projects (< 100 files) or C for large projects.

询问用户:
我应该分析哪些范围?
  A. 整个项目(全面分析,可能耗时较长)
  B. 特定模块/目录:[请指定]
  C. 仅最近变更的文件(git diff)
  D. 仅架构层面问题(跳过底层代码坏味道)
若用户未指定,小型项目(<100个文件)默认选择选项A,大型项目默认选择选项C。

Step 2: Evidence Gathering

步骤2:证据收集

Use the Explore subagent (
Agent
with
subagent_type: "Explore"
) to scan the codebase for architectural patterns and anti-patterns. Run multiple parallel explorations:
使用Explore子代理
subagent_type: "Explore"
Agent
)扫描代码库以识别架构模式与反模式。并行执行多项探索任务:

Exploration Commands

探索命令

Run these in parallel to gather evidence efficiently:
  1. Project Structure Scan: Map the directory tree, identify the architectural style (layered, modular monolith, microservices, etc.)
  2. Dependency Analysis: Find import/include patterns, check for circular dependencies, identify coupling hotspots
  3. Module/Component Scan: Identify God Objects (files > 500 lines), check cohesion, check single responsibility violations
  4. Pattern Detection: Look for known anti-pattern signatures (static cling, service locator abuse, leaky abstractions)
  5. Testing Scan: Check test coverage patterns, test file locations, test-to-code ratios
  6. Naming & Clarity Scan: Flag misleading names, overly generic names (Manager, Helper, Util), inconsistent naming conventions
  7. Complexity Scan: Detect algorithmic complexity hotspots — nested loops, N+1 queries, repeated scans, sort-in-loop, expensive recomputation in render paths
并行执行以下命令以高效收集证据:
  1. 项目结构扫描: 映射目录树,识别架构风格(分层架构、模块化单体、微服务等)
  2. 依赖分析: 查找导入/引用模式,检查循环依赖,识别耦合热点
  3. 模块/组件扫描: 识别上帝对象(文件行数>500),检查内聚性,检测单一职责原则违规
  4. 模式检测: 查找已知反模式特征(静态依赖滥用、服务定位器滥用、抽象泄漏)
  5. 测试扫描: 检查测试覆盖模式、测试文件位置、测试代码比例
  6. 命名与清晰度扫描: 标记误导性命名、过于通用的名称(Manager、Helper、Util)、不一致的命名规范
  7. 复杂度扫描: 检测算法复杂度热点 —— 嵌套循环、N+1查询、重复扫描、循环内排序、渲染路径中的昂贵重复计算

Key Heuristics

核心启发式规则

CategorySmellDetection Heuristic
ArchitectureBig Ball of MudNo clear directory structure; everything in root or one flat folder; no separation of concerns
ArchitectureViolated Layer BoundariesInner layers importing outer layers; infrastructure code in domain/core layer
ArchitectureMissing ArchitectureNo
src/
,
lib/
,
core/
separation; SQL inline with UI code; HTTP handlers mixed with business logic
ArchitectureDistributed MonolithMicroservices sharing a database; services that can't deploy independently
ArchitectureAnemic Domain ModelModel/entity classes with only getters/setters and no behavior; all logic in services
ArchitectureCQRS Without NeedSeparate read/write models for simple CRUD; unnecessary complexity
CouplingCircular DependenciesModule A imports B, B imports A; detected via import graph analysis
CouplingContent CouplingOne module directly accesses another's internal/private members
CouplingCommon CouplingExcessive global variables/shared mutable state; singleton abuse
CouplingStamp CouplingPassing large data structures when only a few fields are needed
CohesionGod ObjectSingle class/module > 500 lines; > 20 public methods; handles unrelated concerns
CohesionShotgun SurgeryA single change requires touching 5+ files across unrelated modules
CohesionFeature EnvyMethod calls foreign class methods more than its own class methods
CohesionData ClumpsSame group of 3+ parameters appearing together in multiple method signatures
DesignLeaky AbstractionsImplementation details (DB queries, HTTP calls) exposed through interfaces
DesignStatic ClingExcessive use of static methods; static state that prevents testability
DesignService Locator AbuseDI container passed around instead of proper constructor injection
DesignViolated SOLIDSRP violations, OCP violations (switch/if-else chains on types), ISP violations (fat interfaces)
CodeDuplicated CodeIdentical/similar logic appearing in 3+ places; copy-paste patterns
CodeLong MethodMethods > 50 lines; deep nesting (> 3 levels)
CodeLong Parameter ListMethods with > 4 parameters
CodePrimitive ObsessionUsing strings/ints instead of domain types (e.g.,
string email
instead of
Email
type)
CodeMagic Numbers/StringsHardcoded literals without named constants
CodeComments as DeodorantExcessive comments explaining bad code instead of refactoring
CodeDead CodeUnused imports, unreachable code, commented-out blocks
TestingNo TestsModules with zero test coverage
TestingTest-Implementation CouplingTests that assert internal implementation details instead of behavior
TestingSlow TestsTests doing real I/O, database calls, network requests without mocking
NamingVague Names
Manager
,
Handler
,
Processor
,
Helper
,
Util
,
Service
,
Data
,
Info
used excessively without context
NamingInconsistent NamingSnake_case and camelCase mixed; different patterns for same concept
ComplexityNested Loops (O(n^2)+)Loop inside loop; forEach inside for; map inside map; nested iteration suggesting polynomial complexity
ComplexityRepeated Linear Scan
includes()
/
indexOf()
/
.find()
inside a loop; O(n*m) membership check on list instead of Set/Map
ComplexitySort-in-Loop
.sort()
or
sorted()
called inside iterative code; repeated O(n log n) when sort-once suffices
ComplexityN+1 Query PatternDatabase/API/HTTP call inside a loop;
fetch
/
query
/
execute
/
findMany
per iteration instead of batch
ComplexityRender-Path Recompute
.filter().map().sort()
chains in component render body; expensive transforms without memoization
ComplexityPairwise ComparisonNested iteration comparing every element with every other; O(n^2) when sort+two-pointer would be O(n log n)
ComplexityUnnecessary RecomputeSame expensive computation repeated without caching; missing
useMemo
/
memo
/lazy eval
ComplexityWrong Data StructureArray used where Set/Map would give O(1) lookup; List where Queue/Heap/Stack is natural fit

分类坏味道检测规则
架构大泥球架构无清晰目录结构;所有内容都在根目录或单一扁平文件夹;无关注点分离
架构层级边界违规内层导入外层;领域/核心层包含基础设施代码
架构缺失架构设计
src/
lib/
core/
分离;SQL与UI代码内联;HTTP处理器与业务逻辑混合
架构分布式单体微服务共享数据库;服务无法独立部署
架构贫血领域模型模型/实体类仅包含getter/setter,无业务行为;所有逻辑都在服务层
架构不必要的CQRS简单CRUD场景使用分离的读写模型;引入不必要的复杂度
耦合循环依赖模块A导入B,B导入A;通过导入图分析检测
耦合内容耦合一个模块直接访问另一个模块的内部/私有成员
耦合公共耦合过度使用全局变量/共享可变状态;单例滥用
耦合标记耦合传递大型数据结构,但仅需其中少数字段
内聚上帝对象单个类/模块行数>500;>20个公共方法;处理不相关的关注点
内聚霰弹式修改单次变更需要修改5个以上不同模块的文件
内聚特性依恋方法调用外部类的次数多于自身类的方法
内聚数据泥团同一组3个以上参数多次出现在方法签名中
设计抽象泄漏接口暴露实现细节(数据库查询、HTTP调用)
设计静态依赖滥用过度使用静态方法;静态状态导致无法测试
设计服务定位器滥用传递DI容器而非使用构造函数注入
设计SOLID原则违规SRP违规、OCP违规(基于类型的switch/if-else链)、ISP违规(臃肿接口)
代码重复代码相同/相似逻辑出现在3个以上位置;复制粘贴模式
代码过长方法方法行数>50;深层嵌套(>3层)
代码过长参数列表方法参数>4个
代码原始类型痴迷使用字符串/整数替代领域类型(例如用
string email
而非
Email
类型)
代码魔法数字/字符串未使用命名常量的硬编码字面量
代码注释掩盖坏味道过多注释解释糟糕代码而非重构
代码死代码未使用的导入、不可达代码、注释掉的代码块
测试无测试覆盖模块测试覆盖率为0
测试测试与实现耦合测试断言内部实现细节而非行为
测试缓慢测试测试执行真实I/O、数据库调用、网络请求而未做Mock
命名模糊命名过度使用无上下文的
Manager
Handler
Processor
Helper
Util
Service
Data
Info
命名命名不一致混合使用Snake_case与camelCase;同一概念使用不同命名模式
复杂度嵌套循环(O(n^2)+)循环嵌套;forEach嵌套forEach;map嵌套map;嵌套迭代表明多项式复杂度
复杂度重复线性扫描循环内使用
includes()
/
indexOf()
/
.find()
;使用列表而非Set/Map进行O(n*m)成员检查
复杂度循环内排序迭代代码中调用
.sort()
sorted()
;本可仅排序一次却重复执行O(n log n)操作
复杂度N+1查询模式循环体内执行数据库/API/HTTP调用;每次迭代执行
fetch
/
query
/
execute
/
findMany
而非批量操作
复杂度渲染路径重复计算组件渲染体内执行
.filter().map().sort()
链式操作;无缓存的昂贵转换
复杂度两两比较嵌套迭代比较每一对元素;本可使用排序+双指针实现O(n log n),却采用O(n^2)实现
复杂度不必要的重复计算相同昂贵计算重复执行而无缓存;缺失
useMemo
/
memo
/延迟求值
复杂度错误的数据结构使用Array而非Set/Map实现O(1)查找;使用List而非Queue/Heap/Stack

Step 3: Report Generation

步骤3:报告生成

Generate the report in this structure:
markdown
undefined
按照以下结构生成报告:
markdown
undefined

Architecture Smell Report

架构坏味道报告

Project: [project-name] Scope: [scope description] Date: [date] Analyzer: smell skill (Ducc)

项目: [项目名称] 范围: [范围描述] 日期: [日期] 分析工具: smell技能(Ducc)

Executive Summary

执行摘要

[2-3 paragraph summary: architectural style detected, overall health assessment, and top 3-5 critical issues]

[2-3段摘要:检测到的架构风格、整体健康评估、前3-5个关键问题]

Architectural Style Detected

检测到的架构风格

[Identify the architectural style: Layered, Modular Monolith, Microservices, Hexagonal, Clean Architecture, or Big Ball of Mud]
[识别架构风格:分层、模块化单体、微服务、六边形架构、整洁架构或大泥球架构]

Style Expectations vs. Reality

风格预期 vs 实际情况

ExpectationRealityStatus
[e.g., Clear layer separation][what was found]✅/⚠️/🔴

预期实际状态
[例如:清晰的层级分离][发现的情况]✅/⚠️/🔴

Findings by Category

按分类整理的发现结果

🔴 Critical Issues (Must Fix)

🔴 关键问题(必须修复)

[Issues that fundamentally undermine architecture]
[从根本上破坏架构的问题]

🟡 Warnings (Should Fix)

🟡 警告(应该修复)

[Issues that degrade maintainability but don't block function]
[降低可维护性但不影响功能的问题]

🔵 Suggestions (Nice to Fix)

🔵 建议(值得修复)

[Minor improvements that would increase quality]

[提升代码质量的微小改进]

Detailed Findings

详细发现

Finding #1: [Title]

发现#1:[标题]

  • Category: [Architecture/Coupling/Cohesion/Design/Code/Testing/Naming/Complexity]
  • Severity: 🔴 Critical / 🟡 Warning / 🔵 Suggestion
  • Anti-Pattern: [Name of anti-pattern]
  • Location: [file:line references]
  • Principle Violated: [SOLID/DRY/KISS/etc.]
  • Description: [What was found and why it's a problem]
  • Evidence: [Code snippet or structure description]
  • Recommendation: [Specific fix, with refactoring approach]

  • 分类: [架构/耦合/内聚/设计/代码/测试/命名/复杂度]
  • 严重程度: 🔴 关键 / 🟡 警告 / 🔵 建议
  • 反模式: [反模式名称]
  • 位置: [文件:行号引用]
  • 违反原则: [SOLID/DRY/KISS等]
  • 描述: [发现的问题及其影响]
  • 证据: [代码片段或结构描述]
  • 建议: [具体修复方案及重构方法]

Dependency Graph Analysis

依赖图分析

[Summary of module dependencies, circular dependencies found, coupling hotspots]

[模块依赖摘要、发现的循环依赖、耦合热点]

Module Health Scorecard

模块健康评分卡

ModuleLinesGod Object RiskCouplingCohesionTest CoverageHealth
[name][N][Low/Med/High][Low/Med/High][Low/Med/High][% or N/A]🟢/🟡/🔴

模块行数上帝对象风险耦合度内聚度测试覆盖率健康状态
[名称][N][低/中/高][低/中/高][低/中/高][% 或 N/A]🟢/🟡/🔴

Smell Distribution

坏味道分布

CategoryCountCriticalWarningSuggestion
Architecture[N][N][N][N]
Coupling[N][N][N][N]
Cohesion[N][N][N][N]
Design[N][N][N][N]
Code[N][N][N][N]
Testing[N][N][N][N]
Naming[N][N][N][N]
Complexity[N][N][N][N]

分类数量关键警告建议
架构[N][N][N][N]
耦合[N][N][N][N]
内聚[N][N][N][N]
设计[N][N][N][N]
代码[N][N][N][N]
测试[N][N][N][N]
命名[N][N][N][N]
复杂度[N][N][N][N]

Refactoring Roadmap

重构路线图

Immediate Actions (This Sprint)

立即行动(当前迭代)

  1. [Actionable fix 1]
  2. [Actionable fix 2]
  1. [可落地的修复方案1]
  2. [可落地的修复方案2]

Short-Term (1-3 Months)

短期(1-3个月)

  1. [Structural improvement 1]
  2. [Structural improvement 2]
  1. [结构改进方案1]
  2. [结构改进方案2]

Long-Term (3-12 Months)

长期(3-12个月)

  1. [Architectural transformation 1]
  2. [Architectural transformation 2]

  1. [架构转型方案1]
  2. [架构转型方案2]

Appendix: Anti-Pattern Reference

附录:反模式参考

[A condensed reference of anti-patterns checked, with brief descriptions]

---
[检查过的反模式浓缩参考及简要描述]

---

Step 4: Save and Present

步骤4:保存与呈现

Save the report to
tasks/smell-report-[YYYY-MM-DD-HHmm].md
and present a brief summary to the user.

将报告保存至
tasks/smell-report-[YYYY-MM-DD-HHmm].md
,并向用户呈现简要摘要。

Anti-Pattern Knowledge Base

反模式知识库

This section documents the architectural anti-patterns and bad smells the skill knows about.
本节记录该技能识别的架构反模式与坏味道。

Architectural Anti-Patterns

架构反模式

Big Ball of Mud

大泥球架构

The most common de-facto architecture. A haphazardly structured, sprawling system with no perceivable architecture. Characterized by:
  • Promiscuous sharing of information between distant elements
  • Global or duplicated important state
  • Structure eroded beyond recognition or never defined
  • Repeated expedient repair ("duct tape and bailing wire")
  • Forces: Time pressure, cost, inexperience, complexity, change, scale
  • Remedy: Define architecture boundaries, refactor incrementally, apply SHEARING LAYERS, KEEP IT WORKING
最常见的实际架构。结构混乱、无明确架构的庞大系统。特征:
  • 不同模块间随意共享信息
  • 全局或重复的重要状态
  • 架构被破坏或从未定义
  • 反复临时修复(「胶带固定」)
  • 诱因:时间压力、成本、经验不足、复杂度、变更、规模
  • 修复方案: 定义架构边界、逐步重构、应用分层策略、保持系统可用

Distributed Monolith

分布式单体

Microservices that must be deployed together. Symptoms:
  • Services share a database
  • Synchronous chains of service calls
  • Changes require coordinated deployments
  • Remedy: Decouple data stores, introduce async messaging, enforce bounded contexts
必须一起部署的微服务。症状:
  • 服务共享数据库
  • 同步链式服务调用
  • 变更需要协调部署
  • 修复方案: 解耦数据存储、引入异步消息、实现限界上下文

Anemic Domain Model

贫血领域模型

Domain objects with only getters/setters (data bags), all logic in services. Violates:
  • "Tell, Don't Ask" principle
  • Rich Domain Model pattern from DDD
  • Remedy: Move behavior into domain objects, use domain services only for cross-aggregate operations
仅包含getter/setter的领域对象(数据袋),所有逻辑在服务层。违反:
  • 「Tell, Don't Ask」原则
  • DDD中的富领域模型模式
  • 修复方案: 将行为移至领域对象,仅在跨聚合操作时使用领域服务

God Object

上帝对象

A class that knows too much or does too much. Characteristics:
  • 500 lines or > 20 public methods
  • Handles unrelated concerns
  • Difficult to test in isolation
  • Single Responsibility Principle violation
  • Remedy: Extract cohesive groups of methods into dedicated classes
知晓过多或承担过多职责的类。特征:
  • 行数>500或>20个公共方法
  • 处理不相关的关注点
  • 难以独立测试
  • 违反单一职责原则
  • 修复方案: 将内聚的方法组提取到专用类中

Leaky Abstractions

抽象泄漏

Abstractions that expose implementation details. Signs:
  • Interface methods named after implementation (e.g.,
    SaveToPostgres
    ,
    FetchFromRedis
    )
  • Consumers catching implementation-specific exceptions
  • Configuration details exposed through abstractions
  • Remedy: Design interfaces from the consumer's perspective, hide implementation details
暴露实现细节的抽象。迹象:
  • 接口方法以实现命名(例如
    SaveToPostgres
    FetchFromRedis
  • 消费者捕获特定于实现的异常
  • 配置细节通过抽象暴露
  • 修复方案: 从消费者视角设计接口,隐藏实现细节

Static Cling

静态依赖滥用

Excessive use of static methods/state. Problems:
  • Untestable (can't mock static calls)
  • Hidden dependencies
  • Thread-safety issues with static state
  • Remedy: Use dependency injection, convert stateless statics to instance methods
过度使用静态方法/状态。问题:
  • 无法测试(无法Mock静态调用)
  • 隐藏依赖
  • 静态状态的线程安全问题
  • 修复方案: 使用依赖注入,将无状态静态方法转换为实例方法

Service Locator Abuse

服务定位器滥用

Using a service locator instead of dependency injection. Issues:
  • Hidden dependencies (dependencies not visible in constructor)
  • Runtime errors instead of compile-time errors
  • Testing difficulty
  • Remedy: Use constructor injection, register dependencies at composition root
使用服务定位器而非依赖注入。问题:
  • 隐藏依赖(构造函数中不可见)
  • 运行时错误而非编译时错误
  • 测试难度大
  • 修复方案: 使用构造函数注入,在组合根注册依赖

Violated Layer Boundaries (Clean/Onion/Hexagonal Architecture)

层级边界违规(整洁/洋葱/六边形架构)

In layered architectures:
  • Clean Architecture: Outer layers (frameworks) leaking into inner layers (use cases, entities)
  • Onion Architecture: Infrastructure concerns in domain core
  • Hexagonal Architecture: Business logic coupled to specific adapters instead of ports
  • Remedy: Apply dependency inversion, define clear port interfaces
分层架构中:
  • 整洁架构: 外层(框架)泄漏到内层(用例、实体)
  • 洋葱架构: 领域核心包含基础设施逻辑
  • 六边形架构: 业务逻辑与特定适配器耦合而非端口
  • 修复方案: 应用依赖倒置原则,定义清晰的端口接口

CQRS Overuse

CQRS过度使用

Applying CQRS to simple CRUD. Signs:
  • Separate read/write models for trivial data access
  • Event sourcing when events don't add business value
  • Unnecessary complexity
  • Remedy: Use CQRS only when read/write models genuinely differ or have different scaling needs
将CQRS应用于简单CRUD场景。迹象:
  • 简单数据访问使用分离的读写模型
  • 事件溯源未带来业务价值
  • 不必要的复杂度
  • 修复方案: 仅在读写模型确实不同或有不同扩展需求时使用CQRS

Vertical Slice Contamination

垂直切片污染

In Vertical Slice Architecture:
  • Cross-slice coupling (one feature directly calling another)
  • Shared service classes undermining slice independence
  • Remedy: Use events/messages for cross-slice communication, duplicate simple logic if needed
垂直切片架构中:
  • 跨切片耦合(一个功能直接调用另一个功能)
  • 共享服务类破坏切片独立性
  • 修复方案: 使用事件/消息进行跨切片通信,必要时复制简单逻辑

Coupling & Cohesion Smells

耦合与内聚坏味道

Circular Dependencies

循环依赖

Module A → Module B → Module A. Detected via:
  • Import graph analysis
  • "Cannot access before initialization" errors
  • Remedy: Extract shared interface/common module, apply dependency inversion
模块A → 模块B → 模块A。检测方式:
  • 导入图分析
  • 「Cannot access before initialization」错误
  • 修复方案: 提取共享接口/公共模块,应用依赖倒置

Content Coupling

内容耦合

One module directly modifying another's internal state. Signs:
  • Direct field access across module boundaries
  • friend
    /package-private abuse
  • Remedy: Use public APIs, encapsulate internal state
一个模块直接修改另一个模块的内部状态。迹象:
  • 跨模块边界直接访问字段
  • friend
    /包私有滥用
  • 修复方案: 使用公共API,封装内部状态

Common Coupling (Global State)

公共耦合(全局状态)

Multiple modules depending on shared global mutable state:
  • Global variables, singletons with mutable state
  • Ambient context (e.g.,
    CurrentUser
    static property)
  • Remedy: Parameterize, use dependency injection, make state explicit
多个模块依赖共享的全局可变状态:
  • 全局变量、带可变状态的单例
  • 环境上下文(例如
    CurrentUser
    静态属性)
  • 修复方案: 参数化、使用依赖注入、使状态显式化

Stamp Coupling

标记耦合

Passing entire data structures when only a few fields needed:
  • Functions receiving large DTOs but using one field
  • Remedy: Create focused parameters or smaller interfaces (ISP)
传递整个数据结构但仅需少数字段:
  • 函数接收大型DTO但仅使用其中一个字段
  • 修复方案: 创建聚焦的参数或更小的接口(ISP)

Shotgun Surgery

霰弹式修改

A single change requires modifications across many files:
  • Adding a field touches 5+ files in different modules
  • Remedy: Consolidate related behavior, apply Single Responsibility
单次变更需要修改多个文件:
  • 添加一个字段需要修改5个以上不同模块的文件
  • 修复方案: 整合相关行为,应用单一职责原则

Feature Envy

特性依恋

A method that uses another class's methods more than its own:
  • Method calls
    other.foo()
    ,
    other.bar()
    ,
    other.baz()
    with few self-calls
  • Remedy: Move the method to the class it envies
方法调用外部类的次数多于自身类:
  • 方法多次调用
    other.foo()
    other.bar()
    other.baz()
    ,很少调用自身方法
  • 修复方案: 将该方法移至它依赖的类中

Data Clumps

数据泥团

Same group of fields appearing together in multiple places:
  • (street, city, zip)
    appearing in 5 method signatures
  • Remedy: Extract into a value object
同一组字段多次出现在不同位置:
  • (street, city, zip)
    出现在5个方法签名中
  • 修复方案: 提取为值对象

Code-Level Smells

代码层面坏味道

Long Method

过长方法

  • Methods > 50 lines (or whatever suits the language)
  • Deep nesting > 3 levels
  • Multiple levels of abstraction mixed
  • Remedy: Extract methods at same abstraction level, compose
  • 方法行数>50(或根据语言调整)
  • 深层嵌套>3层
  • 混合多个抽象层级
  • 修复方案: 提取同一抽象层级的方法,进行组合

Long Parameter List

过长参数列表

  • Methods with > 4 parameters
  • Boolean flags controlling behavior
  • Remedy: Introduce parameter object, split method, remove flag arguments
  • 方法参数>4个
  • 控制行为的布尔标志
  • 修复方案: 引入参数对象、拆分方法、移除标志参数

Duplicated Code

重复代码

  • Identical or near-identical logic in 3+ places
  • Copy-paste with slight variations
  • Remedy: Extract shared method, apply Template Method or Strategy pattern
  • 相同或几乎相同的逻辑出现在3个以上位置
  • 复制粘贴并略有修改
  • 修复方案: 提取共享方法,应用模板方法或策略模式

Primitive Obsession

原始类型痴迷

Using primitives instead of domain types:
  • string
    for Email, PhoneNumber, URL
  • int
    for Money, Age, Quantity
  • decimal
    without Currency context
  • Remedy: Create value objects with validation and behavior
使用原始类型替代领域类型:
  • string
    表示Email、PhoneNumber、URL
  • int
    表示Money、Age、Quantity
  • 无货币上下文的
    decimal
  • 修复方案: 创建带验证和行为的值对象

Magic Numbers/Strings

魔法数字/字符串

  • Hardcoded literals without explanation
  • if (status == 3)
    instead of
    if (status == Status.COMPLETED)
  • Remedy: Extract named constants or enums
  • 无解释的硬编码字面量
  • 使用
    if (status == 3)
    而非
    if (status == Status.COMPLETED)
  • 修复方案: 提取为命名常量或枚举

Comments as Deodorant

注释掩盖坏味道

  • Comments that explain what code does (code should be self-documenting)
  • Commented-out code blocks
  • "TODO" comments accumulating without resolution
  • Remedy: Refactor to make code clear, delete dead code, track TODOs as issues
  • 注释解释代码功能(代码应自文档化)
  • 注释掉的代码块
  • 未解决的「TODO」注释堆积
  • 修复方案: 重构代码使其清晰、删除死代码、将TODO作为问题跟踪

Dead Code

死代码

  • Unused imports, variables, functions
  • Unreachable branches
  • Commented-out code in version control
  • Remedy: Delete it (git history preserves it if needed)
  • 未使用的导入、变量、函数
  • 不可达分支
  • 版本控制中注释掉的代码
  • 修复方案: 删除(git历史会保留必要内容)

Testing Smells

测试坏味道

No Tests

无测试覆盖

  • Modules with zero test coverage
  • Business logic without unit tests
  • Remedy: Write characterization tests first, then add behavior tests
  • 模块测试覆盖率为0
  • 业务逻辑无单元测试
  • 修复方案: 先编写特征测试,再添加行为测试

Test-Implementation Coupling

测试与实现耦合

  • Tests asserting internal method calls, private state, or implementation details
  • Tests breaking on refactoring without behavior changes
  • Remedy: Test through public APIs, assert behavior not implementation
  • 测试断言内部方法调用、私有状态或实现细节
  • 重构未改变行为但测试失败
  • 修复方案: 通过公共API测试,断言行为而非实现

Test Environment Dependency

测试环境依赖

  • Tests depending on file system, network, database, system clock without mocking
  • Non-deterministic tests (flaky tests)
  • Remedy: Use test doubles, control environment, use DI
  • 测试依赖文件系统、网络、数据库、系统时钟而未Mock
  • 非确定性测试(不稳定测试)
  • 修复方案: 使用测试替身、控制环境、使用依赖注入

Complexity Smells (Algorithmic Anti-Patterns)

复杂度坏味道(算法反模式)

Complexity smells indicate code whose runtime grows inefficiently with input size. These are not mere "micro-optimizations" — they are algorithmic choices that cause real performance degradation at scale.
复杂度坏味道表示代码运行时随输入规模增长效率低下。这些不是单纯的「微优化」—— 而是会导致大规模性能下降的算法选择。

Nested Loops (O(n^2) and Worse)

嵌套循环(O(n^2)及更差)

Two or more loops nested inside each other, producing polynomial complexity.
  • Detection:
    for
    /
    while
    inside another
    for
    /
    while
    ;
    forEach
    /
    map
    inside
    forEach
    /
    map
    ; loop containing another loop (any depth)
  • Impact: O(n^2) for double-nested, O(n^3) for triple; explodes with moderate data sizes
  • Remedy:
    • Build a Map/Set index for the inner collection → O(n+m)
    • Sort + two-pointer approach → O(n log n)
    • Group/bucket data before iterating
    • Sweep-line for interval/range problems
  • Correctness checks: Does order matter? Are there duplicate keys? Is the original picking first/last/all matches?
两个或多个循环嵌套,产生多项式复杂度。
  • 检测:
    for
    /
    while
    嵌套;
    forEach
    /
    map
    嵌套;循环包含另一个循环(任意深度)
  • 影响: 双嵌套为O(n^2),三嵌套为O(n^3);中等数据规模下性能急剧下降
  • 修复方案:
    • 为内部集合构建Map/Set索引 → O(n+m)
    • 排序+双指针方法 → O(n log n)
    • 迭代前分组/分桶数据
    • 区间/范围问题使用扫描线算法
  • 正确性检查: 顺序是否重要?是否有重复键?原逻辑是否选择第一个/最后一个/所有匹配项?

N+1 Query Pattern

N+1查询模式

A database query, API call, or I/O operation inside a loop body.
  • Detection:
    fetch()
    /
    axios()
    /
    query()
    /
    execute()
    /
    findMany()
    /
    findOne()
    /
    findUnique()
    /
    select()
    /
    where()
    inside any loop construct
  • Impact: 1 + N round-trips instead of 1; network latency multiplied by item count
  • Remedy:
    • Batch fetch by IDs:
      SELECT * FROM x WHERE id IN (...)
      then join in memory
    • Use ORM eager-loading /
      include
      /
      preload
      / DataLoader
    • Bulk API endpoints accepting arrays
    • Preserve: auth filters, tenancy isolation, ordering, pagination, error semantics
  • Correctness checks: Don't fetch records the original per-item logic wouldn't authorize; preserve missing-record behavior
循环体内执行数据库查询、API调用或I/O操作。
  • 检测: 循环结构内使用
    fetch()
    /
    axios()
    /
    query()
    /
    execute()
    /
    findMany()
    /
    findOne()
    /
    findUnique()
    /
    select()
    /
    where()
  • 影响: 1+N次往返而非1次;网络延迟乘以项数
  • 修复方案:
    • 按ID批量获取:
      SELECT * FROM x WHERE id IN (...)
      然后在内存中关联
    • 使用ORM预加载 /
      include
      /
      preload
      / DataLoader
    • 接受数组的批量API端点
    • 保留:权限过滤、租户隔离、排序、分页、错误语义
  • 正确性检查: 不要获取原单一项逻辑不会授权的记录;保留缺失记录的行为

Repeated Linear Scan (Missing Index)

重复线性扫描(缺少索引)

Linear search (
includes
,
indexOf
,
.find
,
in_array
) inside a loop, where a Set/Map would give O(1) lookup.
  • Detection:
    .includes()
    /
    .indexOf()
    /
    .find()
    /
    .findIndex()
    /
    in_array()
    /
    contains()
    inside a loop body
  • Impact: O(n*m) instead of O(n+m) — each iteration scans the entire collection
  • Remedy: Build a
    Set
    (for membership) or
    Map
    (for key→value lookup) once before the loop
  • Correctness checks: Does equality semantics change after Set conversion? JavaScript object identity vs. value equality; Python hashability
循环内使用线性搜索(
includes
indexOf
.find
in_array
),而Set/Map可实现O(1)查找。
  • 检测: 循环体内使用
    .includes()
    /
    .indexOf()
    /
    .find()
    /
    .findIndex()
    /
    in_array()
    /
    contains()
  • 影响: O(n*m)而非O(n+m) —— 每次迭代扫描整个集合
  • 修复方案: 循环前构建
    Set
    (用于成员检查)或
    Map
    (用于键值查找)
  • 正确性检查: 转换为Set后相等语义是否改变?JavaScript对象标识 vs 值相等;Python可哈希性

Sort-in-Loop

循环内排序

Sorting inside a loop body, repeating O(n log n) work unnecessarily.
  • Detection:
    .sort()
    /
    sorted()
    /
    sort()
    inside any iterative block
  • Impact: O(k * n log n) instead of O(n log n) — sort repeated k times
  • Remedy:
    • Sort once outside the loop
    • Maintain a heap (PriorityQueue) if incremental top-K is needed
    • Use binary search/insertion into sorted collection
  • Correctness checks: Is each intermediate sorted state externally observable? Does comparator depend on loop-local state?
循环体内排序,重复执行不必要的O(n log n)操作。
  • 检测: 迭代块内使用
    .sort()
    /
    sorted()
    /
    sort()
  • 影响: O(k * n log n)而非O(n log n) —— 排序重复k次
  • 修复方案:
    • 循环外排序一次
    • 若需要增量Top-K则维护堆(PriorityQueue)
    • 使用二分查找/插入有序集合
  • 正确性检查: 每个中间排序状态是否可外部观察?比较器是否依赖循环局部状态?

Render-Path Recompute (UI Complexity)

渲染路径重复计算(UI复杂度)

Expensive data transformation (filter→map→sort chains) inside UI component render bodies, recomputed on every render.
  • Detection:
    .filter().map().sort().reduce()
    chains inside React/Vue/Svelte component function bodies; inside
    function Component()
    or
    const Component = () =>
    in JSX/TSX
  • Impact: Re-derivation on every state change even if inputs unchanged; jank with large collections
  • Remedy:
    • useMemo
      /
      computed
      /
      derived
      with correct dependency arrays
    • Move derivation to selectors, loaders, or server-side
    • Virtualize long lists (windowing)
    • Stabilize callbacks and object props only when child renders are affected
  • Correctness checks: Dependency arrays must include every semantic input; memoization must not hide mutations of mutable inputs
UI组件渲染体内执行昂贵的数据转换(filter→map→sort链式操作),每次渲染都重新计算。
  • 检测: React/Vue/Svelte组件函数体内使用
    .filter().map().sort().reduce()
    链式操作;JSX/TSX中的
    function Component()
    const Component = () =>
  • 影响: 即使输入未变更,每次状态变更都重新推导;大型集合导致卡顿
  • 修复方案:
    • 使用
      useMemo
      /
      computed
      /
      derived
      并配置正确的依赖数组
    • 将推导移至选择器、加载器或服务端
    • 虚拟长列表(窗口化)
    • 仅在影响子组件渲染时稳定回调和对象属性
  • 正确性检查: 依赖数组必须包含所有语义输入;缓存不能隐藏可变输入的突变

Pairwise Comparison

两两比较

Comparing every element with every other element using double-nested iteration.
  • Detection: Two nested loops iterating the same or similar collections, comparing pairs
  • Impact: O(n^2) for pair matching, overlap detection, conflict checking, nearest-neighbor
  • Remedy:
    • Sort + two-pointer for pair/range matching
    • Sweep-line for interval overlaps
    • Spatial hashing or grid bucketing for proximity
    • Union-find for connectivity
  • Correctness checks: Order stability; tie-breaking in equality cases
使用双重嵌套迭代比较每一对元素。
  • 检测: 两个嵌套迭代遍历相同或相似集合,比较元素对
  • 影响: 配对匹配、重叠检测、冲突检查、最近邻等场景为O(n^2)
  • 修复方案:
    • 排序+双指针进行配对/范围匹配
    • 区间重叠使用扫描线算法
    • 邻近性检测使用空间哈希或网格分桶
    • 连通性检测使用并查集
  • 正确性检查: 顺序稳定性;相等情况的平局处理

Unnecessary Recompute (Missing Memoization)

不必要的重复计算(缺少缓存)

Same pure computation repeated with same inputs without caching.
  • Detection: Identical function calls with same arguments in hot paths; repeated expensive transforms; recursive calls without memoization
  • Impact: Linear/polynomial wasted work; especially bad with recursive Fibonacci-style patterns (O(2^n) → O(n) with memo)
  • Remedy: Add memoization/caching with proper invalidation; use
    lru_cache
    /
    memoize
    /
    useMemo
    as appropriate
相同纯计算使用相同输入重复执行而无缓存。
  • 检测: 热点路径中相同参数的重复函数调用;重复的昂贵转换;无缓存的递归调用
  • 影响: 线性/多项式的无用计算;递归斐波那契式模式尤其糟糕(O(2^n) → 缓存后O(n))
  • 修复方案: 添加带正确失效策略的缓存;适当使用
    lru_cache
    /
    memoize
    /
    useMemo

Wrong Data Structure

错误的数据结构

Using a suboptimal data structure for the access pattern.
  • Detection:
    • Array/List used for frequent membership tests → should be Set
    • Array/List used for key-value lookups → should be Map/Object
    • Array used as queue with
      shift()
      /
      pop(0)
      (O(n) per dequeue) → should use proper Queue
    • Sorted insertion into array (O(n) per insert) → should use Heap
  • Remedy: Replace with the data structure whose complexity matches the access pattern:
    • Set → O(1) has/add/delete
    • Map → O(1) get/set
    • Heap → O(log n) push/pop for priority
    • Queue/Deque → O(1) enqueue/dequeue
针对访问模式使用次优的数据结构。
  • 检测:
    • 使用Array/List进行频繁成员检查 → 应使用Set
    • 使用Array/List进行键值查找 → 应使用Map/Object
    • 使用Array作为队列并调用
      shift()
      /
      pop(0)
      (每次出队O(n)) → 应使用专用Queue
    • 使用Array进行有序插入(每次插入O(n)) → 应使用Heap
  • 修复方案: 替换为复杂度匹配访问模式的数据结构:
    • Set → O(1)哈希/添加/删除
    • Map → O(1)获取/设置
    • Heap → O(log n)入队/出队(优先队列)
    • Queue/Deque → O(1)入队/出队

What NOT to Flag

无需标记的情况

  • Cold paths: Complexity that only runs on startup, config loading, or tiny N (< 100) is rarely worth fixing
  • Intentional tradeoffs: Clear, readable O(n) code where O(n log n) would add complexity with no measurable gain
  • Already optimized: Map/Set already in use; batch loading already implemented; memoization already present
  • 冷路径: 仅在启动、配置加载或小数据量(<100)时运行的复杂度问题,通常无需修复
  • 有意的权衡: 清晰可读的O(n)代码,使用O(n log n)会增加复杂度但无明显收益
  • 已优化: 已使用Map/Set;已实现批量加载;已添加缓存

Design Principle Violations

设计原则违规

SOLID Violations Checklist

SOLID原则违规检查清单

  • S (SRP): Class/module has multiple reasons to change → God Object smell
  • O (OCP): switch/if-else chains on type codes → Strategy/Polymorphism needed
  • L (LSP): Subclass changes behavior of base class unexpectedly → Check pre/post conditions
  • I (ISP): Fat interfaces with methods clients don't use → Split interfaces
  • D (DIP): High-level modules depending on low-level details → Introduce abstractions
  • S(SRP): 类/模块有多个变更原因 → 上帝对象坏味道
  • O(OCP): 基于类型码的switch/if-else链 → 需要策略/多态
  • L(LSP): 子类意外改变基类行为 → 检查前置/后置条件
  • I(ISP): 客户端不使用的臃肿接口 → 拆分接口
  • D(DIP): 高层模块依赖低层细节 → 引入抽象

Other Principle Violations

其他原则违规

  • DRY Violation: Same knowledge repeated in multiple places
  • KISS Violation: Over-engineered solutions; premature abstractions
  • YAGNI Violation: Code for hypothetical future requirements; unused abstractions

  • DRY违规: 同一知识在多个地方重复
  • KISS违规: 过度设计的解决方案;过早抽象
  • YAGNI违规: 为假设的未来需求编写代码;未使用的抽象

Edge Cases & Fallback

边缘情况与回退策略

ScenarioHandling
User doesn't specify scopeDefault to recent changes (
git diff
) for repos > 200 files, full analysis otherwise
Project has no clear architectureReport "Big Ball of Mud" with evidence, recommend incremental refactoring
Empty/monorepo projectReport that architecture analysis requires code; ask user to specify module
Language not supportedReport general structural observations; note language-specific checks are limited
Report file path conflictsAppend
-2
,
-3
, etc. to filename
User wants a quick checkRun only Critical-level scans, skip Code and Naming categories
User wants only one categoryFocus analysis on that category, skip others

场景处理方式
用户未指定范围仓库文件>200个时默认最近变更(
git diff
),否则默认全面分析
项目无清晰架构报告「大泥球架构」并提供证据,建议逐步重构
空项目/单体仓库报告架构分析需要代码;请用户指定模块
不支持的语言报告通用结构观察结果;说明语言特定检查受限
报告文件路径冲突文件名后追加
-2
-3
用户需要快速检查仅运行关键级扫描,跳过代码和命名分类
用户仅需分析一个分类聚焦该分类分析,跳过其他分类

Report Output Example

报告输出示例

🔍 Architecture Smell Analysis Complete

Project: goal-workflow
Style: Modular Monolith (with some layering violations)
Files Analyzed: 47
Health: 🟡 Fair

Critical: 3  |  Warnings: 6  |  Suggestions: 9

🔴 Critical Issues:
  1. Anemic Domain Model — `models/` classes have only getters/setters,
     all logic in `services/`. Violates DDD Rich Domain Model principle.
  2. N+1 Query Pattern — `services/order.ts:142` fetches user per order in loop;
     should batch-load users by IDs (O(n*m) → O(n+m)).
  3. Static Cling — `util/ApiClient.ts` uses all static methods,
     making consumer code untestable.

🟡 Warnings:
  1. God Object — `services/workflow.ts` at 847 lines handles too many concerns
  2. Nested Loop O(n^2) — `analytics.ts:89` pairwise comparison of events;
     sort+two-pointer would be O(n log n)
  3. Leaky Abstraction — `repositories/user.ts` exposes MongoDB query syntax
  4. Duplicated Code — validation logic duplicated across 4 controllers
  5. Circular Dependency — `auth` ↔ `user` modules depend on each other
  6. Magic Numbers — ~23 hardcoded values without named constants

Full report: tasks/smell-report-2026-05-27-1530.md
🔍 架构坏味道分析完成

项目:goal-workflow
风格:模块化单体(存在部分层级违规)
分析文件数:47
健康状态:🟡 一般

关键问题:3  | 警告:6  | 建议:9

🔴 关键问题:
  1. 贫血领域模型 —— `models/`类仅包含getters/setters,
     所有逻辑在`services/`中。违反DDD富领域模型原则。
  2. N+1查询模式 —— `services/order.ts:142`在循环中逐个获取用户;
     应按ID批量加载用户(O(n*m) → O(n+m))。
  3. 静态依赖滥用 —— `util/ApiClient.ts`全部使用静态方法,
     导致消费代码无法测试。

🟡 警告:
  1. 上帝对象 —— `services/workflow.ts`有847行,承担过多职责
  2. 嵌套循环O(n^2) —— `analytics.ts:89`中事件两两比较;
     排序+双指针可实现O(n log n)
  3. 抽象泄漏 —— `repositories/user.ts`暴露MongoDB查询语法
  4. 重复代码 —— 验证逻辑在4个控制器中重复
  5. 循环依赖 —— `auth` ↔ `user`模块相互依赖
  6. 魔法数字 —— 约23个硬编码值未使用命名常量

完整报告:tasks/smell-report-2026-05-27-1530.md