red-flags
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRed Flags Diagnostic
风险点诊断
When invoked with $ARGUMENTS, scope the scan to the specified file or directory. Read the target code first, then run every flag below against it. Each flag points to a deeper lens from Clairvoyance (https://clairvoyance.fyi). This skill works best when the full collection is installed.
A red flag is a signal, not a diagnosis. It tells you something is wrong but not why. Each flag below points to a deeper lens that identifies the root cause.
调用时传入$ARGUMENTS,可将扫描范围限定为指定文件或目录。先读取目标代码,再针对代码运行以下所有风险点检查。每个风险点指向Clairvoyance(https://clairvoyance.fyi)中的更深入分析视角。完整安装相关工具集后,该功能的效果最佳。
风险点是一种信号而非诊断结果,它仅提示存在问题但不说明原因。以下每个风险点都指向一个可识别根本原因的深入分析视角。
When to Apply
适用场景
- Before merging a PR or completing a design review
- When code "feels wrong" but the specific problem is unclear
- When evaluating unfamiliar code for design quality
- When asked for a "red flags check" or "design diagnostic"
- 合并PR或完成设计评审前
- 感觉代码“有问题”但无法明确具体问题时
- 评估陌生代码的设计质量时
- 用户要求进行“风险点检查”或“设计诊断”时
The Red Flags
风险点列表
Structural (4)
结构类(4项)
1. Shallow Module
1. 浅层模块
Interface isn't much simpler than implementation.
- Check: → deep-modules
- Could a caller skip this module and do the work directly?
- Signals:
- More public methods than meaningful internal state
- Abstract class with only one implementation and no prospect of more
- Layer that exists "for testability" but adds no abstraction value
- A split that created more total interface surface than the original
- Error handling code longer than the happy path
- Excessive exceptions in a method signature
接口并未比实现简单多少。
- 检查项: → deep-modules
- 调用者是否可以跳过该模块直接完成工作?
- 信号特征:
- 公开方法数量多于有意义的内部状态数量
- 抽象类仅有一个实现,且无新增实现的可能
- 为“可测试性”而存在但未提供任何抽象价值的层级
- 拆分后产生的总接口面比原接口更大
- 错误处理代码比正常流程代码更长
- 方法签名中包含过多异常类型
2. Pass-Through Method
2. 透传方法
Method forwards arguments to another with a similar signature, adding zero logic.
- Check: → deep-modules, abstraction-quality
- Does removing the method lose any behavior?
- Signals:
- Method takes N parameters, passes N-1 unchanged
- Constructor injects collaborators just to delegate
- Class API mirrors its dependency's API
- Wrapper adds one behavior, delegates everything else
- "Wrapper" or "Adapter" classes that add no functionality
- Many thin layers providing the same abstraction
- Decorator with nineteen pass-throughs for one behavior
方法将参数转发给另一个签名类似的方法,未添加任何逻辑。
- 检查项: → deep-modules, abstraction-quality
- 删除该方法是否会丢失任何行为?
- 信号特征:
- 方法接收N个参数,其中N-1个直接透传
- 构造函数注入协作对象仅为了委托调用
- 类的API与其依赖的API完全镜像
- 包装类仅添加一个行为,其余全部委托
- 未添加任何功能的“Wrapper”或“Adapter”类
- 多层提供相同抽象的薄层级
- 19个方法透传、仅一个方法有自定义行为的装饰器
3. Conjoined Methods
3. 耦合方法
Two separate pieces of code that can only be understood together.
- Check: → module-boundaries
- Do you flip between two pieces of code to understand either?
- Signals:
- Method A sets up state that method B reads with no interface between them
- Splitting a method produced fragments that each require the others to make sense
两段独立代码必须结合在一起才能被理解。
- 检查项: → module-boundaries
- 是否需要在两段代码间反复切换才能理解其中任意一段?
- 信号特征:
- 方法A设置的状态需要方法B读取,但两者之间无接口关联
- 拆分方法后产生的片段必须结合其他片段才有意义
4. Temporal Decomposition
4. 时序分解
Structure follows execution order, not knowledge ownership.
- Check: → information-hiding
- Are boundaries drawn around "steps" rather than "knowledge domains"?
- Signals:
- Module named after a step in a process (Reader, Processor, Writer sharing format knowledge)
- Decomposition by execution order rather than by knowledge
结构遵循执行顺序而非知识归属。
- 检查项: → information-hiding
- 是否是围绕“步骤”而非“知识领域”划分边界?
- 信号特征:
- 模块以流程中的步骤命名(如Reader、Processor、Writer共享格式知识)
- 按执行顺序而非知识领域进行分解
Boundary (4)
边界类(4项)
5. Information Leakage
5. 信息泄露
When a design decision leaks across module boundaries, changing that decision often forces changes in every module that knows about it. The most dangerous leaks are invisible, where two modules share knowledge but no interface acknowledges the dependency.
- Check: → information-hiding
- If this format/protocol/representation changes, how many modules need editing?
- Signals:
- Two files that must always be edited together
- Serialization/deserialization logic split across boundaries
- Two modules changing in lockstep with no visible API dependency
- Comments saying "don't forget to also update X"
设计决策跨模块边界泄露,修改该决策往往需要修改所有知晓该决策的模块。最危险的泄露是隐形的:两个模块共享知识但无接口承认这种依赖关系。
- 检查项: → information-hiding
- 如果该格式/协议/表示方式发生变化,需要修改多少个模块?
- 信号特征:
- 两个必须始终同步编辑的文件
- 序列化/反序列化逻辑跨边界拆分
- 两个模块同步变更但无可见API依赖
- 注释中包含“别忘了同时更新X”的提示
6. Overexposure
6. 过度暴露
API forces callers to handle things they almost never need.
- Check: → general-vs-special, pull-complexity-down
- Must callers configure or know about rarely-used features to use common ones?
- Signals:
- Getter/setter pairs exposing internal representation
- API requiring callers to pass values they don't understand
- Config docs that say "use the default unless you know what you're doing"
- Setup code that repeats across every call site
- Builder requiring 10+ configuration calls
- API with 5+ parameters when most callers pass the same values for 3
- Method signature with 3+ exception types
- Caller must catch an exception the module could have resolved
- New parameter added to an already-long parameter list
API强制调用者处理几乎永远不会用到的内容。
- 检查项: → general-vs-special, pull-complexity-down
- 调用者是否必须配置或了解极少使用的功能才能使用常用功能?
- 信号特征:
- 暴露内部表示的Getter/setter对
- API要求调用者传递其不理解的值
- 配置文档中写有“除非你知道自己在做什么,否则请使用默认值”
- 每个调用点重复出现的设置代码
- 需要10+次配置调用的Builder
- API包含5+个参数,其中大多数调用者为3个参数传递相同值
- 方法签名包含3+种异常类型
- 调用者必须捕获模块本可以自行解决的异常
- 向已较长的参数列表中添加新参数
7. Repetition
7. 重复代码
Same logic appears in multiple places. The next change of this type will require edits everywhere.
- Check: → code-evolution
- Would the next change of this type require edits in multiple locations?
- Signals:
- Same change pattern applied in multiple places
- Copy-pasted code with minor modifications
- All callers wrapping the same call in identical try-catch blocks
- Same constant or logic duplicated across many files
相同逻辑出现在多个位置。下次修改此类逻辑时需要在所有位置进行编辑。
- 检查项: → code-evolution
- 下次修改此类逻辑时是否需要在多个位置进行编辑?
- 信号特征:
- 多个位置应用相同的变更模式
- 复制粘贴后仅做微小修改的代码
- 所有调用者对同一调用包裹完全相同的try-catch块
- 相同常量或逻辑在多个文件中重复
8. Special-General Mixture
8. 通用-特殊混合
General mechanism contains knowledge specific to one use case.
- Check: → general-vs-special
- Does this module have branches or parameters serving only one caller?
if
- Does this module have
- Signals:
- Boolean parameter that changes behavior for one caller
- branch added for one specific caller's needs
if - Method name encoding a use case (e.g., )
formatForEmailDisplay - Method designed for exactly one use case when a general-purpose method could replace several
- "Utility" module that knows details of its callers
通用机制中包含特定用例的知识。
- 检查项: → general-vs-special
- 该模块是否存在仅服务于一个调用者的分支或参数?
if
- 该模块是否存在仅服务于一个调用者的
- 信号特征:
- 为单个调用者修改行为的布尔参数
- 为单个特定调用者需求添加的分支
if - 编码了用例的方法名(如)
formatForEmailDisplay - 为单一用例设计方法,而通用方法可替代多个此类方法
- 了解调用者细节的“工具类”模块
Documentation (2)
文档类(2项)
9. Comment Repeats Code
9. 注释重复代码信息
All information in the comment is obvious from the adjacent code.
- Check: → comments-docs
- Does the comment add anything a competent reader wouldn't get from the code alone?
- Signals:
- Comment using the same words as the entity name
注释中的所有信息都可从相邻代码中直接获得。
- 检查项: → comments-docs
- 注释是否为有能力的读者提供了代码本身未包含的信息?
- 信号特征:
- 注释使用与实体名称相同的表述
10. Implementation Documentation Contaminates Interface
10. 实现细节污染接口文档
Interface comment describes implementation details. Signals a leaky abstraction.
- Check: → comments-docs, abstraction-quality
- Would the comment change if the implementation changed but behavior stayed the same?
- Signals:
- Comment describes how in the interface instead of what
- Interface comment mentions internal data structures or algorithms
接口注释描述实现细节,标志着抽象存在泄露。
- 检查项: → comments-docs, abstraction-quality
- 如果实现变更但行为保持不变,注释是否需要修改?
- 信号特征:
- 接口注释描述的是实现方式(how)而非功能(what)
- 接口注释提及内部数据结构或算法
Naming & Abstraction (4)
命名与抽象类(4项)
11. Vague Name
11. 模糊命名
Name so imprecise it doesn't convey useful information.
- Check (isolation test): → naming-obviousness
- Seen without context, could this name mean almost anything?
- Signals:
- Thin or generic names like ,
data,info,tmpat module scopeval - Non-specific container return types where a named class would be self-documenting
- Method name that doesn't predict what the method does
- Thin or generic names like
命名过于不精确,无法传达有用信息。
- 检查项(隔离测试): → naming-obviousness
- 脱离上下文时,该名称是否几乎可以指代任何事物?
- 信号特征:
- 模块级别的模糊或通用名称,如、
data、info、tmpval - 返回非特定容器类型,而命名类可实现自文档化
- 方法名称无法预测方法的功能
- 模块级别的模糊或通用名称,如
12. Hard to Pick Name
12. 难以命名
Struggling to find a precise name isn't a vocabulary problem. It's design feedback.
- Check: → naming-obviousness
- Is the item doing one thing but conflating multiple concepts? Doing multiple things but only implying one?
- Signals:
- Name implies a higher-level concept than the implementation honors
难以找到精确的名称并非词汇问题,而是设计问题的反馈。
- 检查项: → naming-obviousness
- 该对象是否在做一件事但混淆了多个概念?或者做了多件事但仅暗示了一件?
- 信号特征:
- 名称暗示的概念级别高于实现实际达到的级别
13. Hard to Describe
13. 难以描述
Complete documentation must be long and qualified. Short descriptions come from well-designed abstractions.
- Check: → comments-docs
- Can you describe what this does in one sentence without qualifications?
- Signals:
- Long, qualifying interface comment ("does X, except when Y, unless Z")
- Method with no interface comment (nothing to say, or too much?)
完整的文档必须冗长且带有诸多限定条件。设计良好的抽象只需简短描述即可。
- 检查项: → comments-docs
- 你能否用一句话且不带限定条件描述其功能?
- 信号特征:
- 冗长且带有限定条件的接口注释(“执行X操作,但Y情况除外,除非满足Z条件”)
- 无接口注释的方法(无话可说,或要说的太多?)
14. Non-obvious Code
14. 难以理解的代码
This is the meta-flag because every other flag on this list is a specific cause of non-obvious code. When someone reads the code for the first time, they might not be able to tell what it does or why it does it.
- Check: → naming-obviousness
- Would a competent developer reading this for the first time understand it?
- Signals:
- Two different names for the same concept in the same module
- Same name meaning different things in different contexts
- Short names used far from their declaration
- Variable reused to mean different things mid-function
- Code where bugs keep appearing despite fixes
- Method with visible archaeological layers of organic growth
- Callers routinely reading the implementation to understand the interface
这是元风险点,因为列表中的所有其他风险点都是导致代码难以理解的具体原因。当有人首次阅读代码时,可能无法判断其功能或实现原因。
- 检查项: → naming-obviousness
- 有能力的开发者首次阅读该代码时能否理解?
- 信号特征:
- 同一模块中同一概念有两个不同名称
- 同一名称在不同上下文中含义不同
- 短名称在远离其声明的位置使用
- 变量在函数中途被重用以表示不同事物
- 修复后仍不断出现bug的代码
- 带有明显逐步迭代痕迹的方法
- 调用者通常需要阅读实现才能理解接口
Process (3)
流程类(3项)
15. No Alternatives Considered
15. 未考虑替代方案
Design chosen without comparing meaningfully different approaches.
- Check: → design-it-twice
- Were at least two fundamentally different approaches evaluated?
- Signals:
- "This is obviously the right approach" with no alternatives documented
- Design document with no "alternatives considered" section
- Two alternatives that are minor variations of each other
- A design chosen because it was first, not because it was compared
- Interface defended as "the only way"
选择设计方案时未对比显著不同的实现思路。
- 检查项: → design-it-twice
- 是否至少评估了两种根本不同的实现思路?
- 信号特征:
- 认为“这显然是正确的实现思路”但未记录任何替代方案
- 设计文档无“替代方案考虑”章节
- 仅为微小变体的两种替代方案
- 因先想到而选择的设计方案,而非经过对比后选择的
- 接口被辩护为“唯一可行的方式”
16. Tactical Momentum
16. 战术性推进
Changes optimize for speed over design quality.
- Check: → strategic-mindset, code-evolution
- Does this change leave the system better or just different?
- Signals:
- PR description with no design decisions
- New feature bolted on rather than integrated
- "Smallest possible change" treated as sufficient
- TODO comments marking known shortcuts
- "Workaround for..." comments
变更优先考虑速度而非设计质量。
- 检查项: → strategic-mindset, code-evolution
- 该变更会让系统变得更好还是仅仅不同?
- 信号特征:
- PR描述中未提及任何设计决策
- 新功能是直接附加而非集成到系统中
- 将“最小可行变更”视为足够的解决方案
- 标记已知捷径的TODO注释
- 包含“针对...的临时解决方案”的注释
17. Catch-and-Ignore
17. 捕获并忽略
Error handling that suppresses or discards errors without meaningful action.
- Check: → error-design
- Does the catch block do real work, or just make the compiler happy?
- Signals:
- Catch block that only logs and rethrows
- Caller handles an error by doing nothing or returning a default
- A module that silently discards all errors from an external dependency
错误处理仅抑制或丢弃错误,未采取有意义的行动。
- 检查项: → error-design
- catch块是否执行了实际工作,还是仅为了让编译器通过?
- 信号特征:
- 仅记录日志并重新抛出异常的catch块
- 调用者通过不执行任何操作或返回默认值来处理错误
- 静默丢弃外部依赖所有错误的模块
Canary Flags
预警风险点
Hard to Pick Name, Hard to Describe, Non-obvious Code and No Alternatives Considered surface during writing, before code review. Catch them early and the structural flags never materialize.
难以命名、难以描述、_难以理解的代码_和_未考虑替代方案_会在代码编写阶段(代码评审前)显现。尽早发现这些问题,结构类风险点就不会出现。
Review Process
评审流程
- Identify scope: file, module, PR diff, or class
- Scan all flags: For each: CLEAR, TRIGGERED, or N/A. If triggered: location, principle violated, candidate fix
- Structure a report: Group findings by category (Structural, Boundary, Documentation, Naming/Abstraction, Process). Summarize flags triggered, critical issues and recommended actions.
- Follow the arrows: For each triggered flag, pull in the indicated lens for deeper analysis
- Check for syndromes: Multiple triggered flags may share a root cause. See for named clusters. A syndrome points at an architectural issue. Fixing the root cause resolves all flags in the cluster.
references/flag-interaction-map.md - Prioritize: Boundary flags compound over time and infect adjacent code, so fix those first. Canary flags are the cheapest to act on. Structural flags require refactoring but affect a bounded area.
- Recommend: Create a report with prioritized, actionable fixes tied to specific principles.
- 确定范围:文件、模块、PR差异或类
- 扫描所有风险点:针对每个风险点标记为CLEAR(无风险)、TRIGGERED(已触发)或N/A(不适用)。若已触发:记录位置、违反的原则、候选修复方案
- 生成结构化报告:按类别(结构类、边界类、文档类、命名/抽象类、流程类)分组整理发现的问题。总结已触发的风险点、关键问题和建议措施。
- 深入分析:针对每个已触发的风险点,使用指定的视角进行更深入的分析
- 检查综合征:多个已触发的风险点可能共享同一根本原因。请参阅了解已命名的问题集群。综合征指向架构层面的问题,修复根本原因可解决集群中的所有风险点。
references/flag-interaction-map.md - 确定优先级:边界类风险点会随时间扩散并影响相邻代码,因此应优先修复。预警风险点的修复成本最低。结构类风险点需要重构,但影响范围有限。
- 提出建议:生成包含按优先级排序的可操作修复方案的报告,并关联到具体原则。