| name | coding-standards |
| description | 检测代码异味、反模式和可读性问题。在实现功能、评审代码或重构时使用。 |
通用编码标准
技术反模式(危险信号模式)
检测到以下任一模式时,暂停实现并记录:触发的模式、受影响的当前需求、最小的合规替代方案,以及恢复所需的验证。当替代方案消除该模式或有文档记录的需求证明保留该模式合理时,方可恢复。
代码质量反模式
- 相似代码编写 3 次或以上 —— 违反三次法则(Rule of Three)
- 单个文件中混杂多种职责 —— 违反单一职责原则(SRP)
- 在多个文件中定义相同内容 —— 违反 DRY 原则
- 未检查依赖关系就进行修改 —— 存在意外影响的可能性
- 用注释禁用代码 —— 应使用版本控制
- 错误抑制 —— 隐藏问题会形成技术债
- 过度使用类型断言(as) —— 放弃类型安全
设计反模式
- “暂时能用就行”的思维 —— 技术债的累积
- 补丁式实现 —— 对现有代码进行无计划的追加
- 对不确定技术的乐观实现 —— 假设未知要素“大概能行”就进行设计
- 对症式修复 —— 不解决根本原因的表面修复
- 无计划的大规模变更 —— 缺乏渐进式方法
基本原则
持续排查,直到依据能够确定在保持系统正确性和可维护性的前提下,以最低总复杂度交付所需的用户、运维或维护者价值的方案。
- 基于依据的重构范围 —— 只重构阻碍当前结果、被当前任务变更、或未通过适用质量检查的代码;使用保持行为不变的小步骤。对其他发现,连同其所属边界和依据一并报告,而不扩大当前变更范围
- 仅限当前需求的代码 —— 只有当当前需求、已验证的约束、或有依据支持的实质性风险要求时,才引入新的代码路径、能力、基础设施、抽象或推测性的边缘情况处理(YAGNI)
- 设计收敛 —— 以最小的设计增量交付当前所需的结果。在引入持久状态、公共或跨边界契约、行为模式、可复用抽象或组件拆分之前,先记录现有能力已经交付了什么、它们在当前结果上未能交付什么,以及为什么该新增是能弥合这一差距的最小方案
对每个被激活的层面综合评估总复杂度:用户决策、设置、模式、概念、输出、持久状态和实现路径,以及它们各自在 UX、运行时、实现、测试、文档和维护方面的成本。只比较各可行方案之间存在差异的维度。当能以更低的总复杂度交付相同的已确认价值和验证结果时,优先选择复用或不引入新机制。
注释编写规则
- 代码优先:命名、类型和结构是主要的表达媒介;只有在注释能传达代码无法表达的信息时才添加注释。犹豫不决时,改进命名而不是加注释
- 注释“为什么”,而非“是什么”:解释推理过程、权衡取舍、约束/边缘情况,或公共 API 契约
- 内容不过时:注释包含当前的推理、约束、边缘情况或 API 契约;开发历史由版本控制保留
- 长期有效:只写在任何阅读时刻都依然有效的内容
- 简洁性:将说明控制在必要的最低限度
错误处理基础
快速失败原则
在出错时快速失败,防止在无效状态下继续处理。传播该失败,或返回带有原始诊断上下文的显式类型化错误。
关于详细实现方法(Result 类型、自定义错误类、分层错误处理等),请参考特定语言和框架的规则。
三次法则 —— 代码重复的判断标准
根据 Martin Fowler《重构》一书处理重复代码的方式:
| 重复次数 | 处理方式 | 理由 |
|---|
| 第 1 次 | 内联实现 | 无法预测未来的变化 |
| 第 2 次 | 考虑未来的整合 | 模式开始出现 |
| 第 3 次 | 提取公共实现 | 模式已确立 |
提取公共实现的判断标准
适合提取公共实现的情况
- 业务逻辑重复
- 复杂的处理算法
- 很可能需要批量修改的部分
- 校验规则
应保持分离的情况
- 偶然一致(碰巧代码相同)
- 有可能朝不同方向演化
- 提取公共实现会显著降低可读性
- 测试代码中的简单辅助函数
变更边界与参考代表性
提示中给出的路径是调查的起点。当有依据表明仓库中的其他文件实现了被接受的结果、是必需的依赖或调用路径、或必须变更以维持受本次工作影响的契约时,将其纳入范围。调用方、使用方、测试、配置和数据流是有用的依据,而非必须逐项核查的清单。
在采用某种模式、API 或依赖时,检查具有相同职责和当前契约的相关功能及仓库中的其他使用之处。在该职责范围内优先选择兼容的实现。出现频率有助于定位候选方案,但并不能使某个模式因此具有权威性;当多种方案并存时,通过其调用方、生命周期和兼容性来区分当前模式与遗留或无关的模式。
从清单文件、锁文件和兼容的使用方中解析外部依赖版本。仅当这些来源无法解决影响兼容性或架构的选择时才上报处理。
常见失败模式及规避方法
模式 1:错误修复连锁反应
症状:修复一个错误导致产生新的错误
原因:未理解根本原因就进行表面修复
规避方法:修复前用五个为什么(5 Whys)找出根本原因
模式 2:放弃类型安全
症状:过度使用 any 类型或 as
原因:想要规避类型错误的冲动
规避方法:应用“类型安全基础”中关于依据的判断标准。
模式 3:测试不充分的实现
症状:实现后出现大量 bug
原因:忽视 Red-Green-Refactor 流程
规避方法:以能够展示所需结果的失败测试开始行为变更
模式 4:忽视技术不确定性
症状:引入新技术时频繁出现意外错误
原因:未事先调查,假设“照官方文档应该能行”
规避方法:
- 在任务文件开头记录确定性评估
- 当仓库依据、与版本匹配的一手资料,或可运行的本地检查都无法确认与结果相关的行为时,将确定性视为低;在实现前先创建能解决该行为问题的最小验证
模式 5:对现有代码调查不足
症状:重复实现、架构不一致、集成失败、采用过时模式
原因:实现前对现有代码理解不足;仅参考附近文件而未核实其代表性
规避方法:
- 实现前,使用领域、职责和配置模式相关的关键词搜索类似功能
- 发现类似功能 -> 当该实现满足当前契约时,复用或扩展它
- 类似功能属于技术债 -> 当它阻碍当前结果、由当前变更引起、或位于已确认范围内时予以修复;否则单独报告。当修复需要架构决策时创建 ADR
- 不存在类似功能 -> 按照现有设计理念实现新功能
- 将每个决策及其理由记录在当前工作流为其指定的产物中
- 参考代表性核查:参见上文“变更边界与参考代表性”一节
调试技巧
五个为什么 —— 根本原因分析
将每个回答追溯到已观察到的依据,直至找到一个修正后能防止原始故障的原因。记录每个问题、依据以及最终的因果链;当下一个回答将只是推测时停止,并指出还需要哪些依据。
类型安全基础
类型安全原则:类型收窄应以运行时检查或既有契约为依据。类型守卫保证的类型应与实际检查内容一致。
- 对结构尚未确定的输入使用
unknown,并验证使用方需要的属性。
- 使用泛型、联合类型或交叉类型表达类型关系及变体。
- 将基于已验证的 SDK 或框架契约的类型断言放在对应边界。当静态分析无法表达该契约时,将抑制限定于相关规则,并说明契约依据和断言的适用范围。
类型复杂度管理
- 字段数量:最多 20 个(超过则按职责拆分,外部 API 类型除外)
- 可选字段比例:最多 30%(超过则将必填/可选分离)
- 嵌套深度:最多 3 层(超过则扁平化)
- 类型断言:使用 3 次以上时应重新审视设计
- 外部 API 类型:放宽约束,按实际情况定义(在内部适当转换)
重构技巧
基本方针
- 小步前进:每次保持行为不变的重构后,确保最相关的适用测试和静态检查仍然通过
- 安全变更:一次只改变一个重构职责,并在进行下一个职责之前验证其可观测行为
- 行为保证:确保现有行为在过程中保持不变
实现流程:理解现状 -> 渐进式修改 -> 行为验证 -> 最终确认
优先级:删除重复代码 > 拆分大函数 > 简化复杂条件分支 > 提升类型安全
实现完整性保证
影响分析的必要流程
完成标准:完成全部 3 个阶段
1. 发现
Grep -n "TargetClass\|TargetMethod" -o content
Grep -n "DependencyClass" -o content
Grep -n "targetData\|SetData\|UpdateData" -o content
2. 理解
必须:阅读所有发现的文件,并将必要部分纳入上下文:
- 调用方的目的和上下文
- 依赖方向
- 数据流:生成 -> 修改 -> 引用
3. 判定
结构化影响报告(必须):
## 影响分析
### 直接影响:ClassA、ClassB(附理由)
### 间接影响:SystemX、ComponentY(附集成路径)
### 处理流程:输入 -> 处理1 -> 处理2 -> 输出
完成条件:在开始实现前,发现、理解和判定三个阶段都必须包含所需的依据。
未使用代码的删除规则
检测到未使用的代码时,在任务完成前确认是否有当前需求和可达的调用路径会用到它。
- 是 -> 将其接入该调用路径并验证需求
- 否 -> 删除它;版本控制会保留之前的实现
对象:代码、文档、配置文件
Red-Green-Refactor 流程(测试先行开发)
推荐原则:以因预期原因而失败的测试开始行为变更
开发步骤:
- Red:为预期行为编写测试(测试失败)
- Green:以最小实现使测试通过
- Refactor:在保持测试通过的同时改进代码
可直接验证的情况:
- 纯配置文件变更(.env、config 等)
- 仅文档更新(README、注释等)
- 生产环境紧急事故响应(事后必须补充测试)
测试设计原则
测试用例结构
- 测试由“Arrange(准备)”“Act(执行)”“Assert(断言)”三个阶段组成
- 测试名称应说明触发条件和可观测结果
- 一个测试用例只验证一种行为
测试数据管理
- 在专用目录中管理测试数据
- 定义测试专用的环境变量值
- 对测试中的凭据、令牌、个人数据和支付数据,使用合成的、非敏感的值
- 保持测试数据最小化,只使用与测试用例验证目的直接相关的数据
Mock 与 Stub 使用策略
推荐:在单元测试中对外部依赖进行 mock
- 优点:确保测试的独立性和可复现性
- 实践:对数据库、API、文件系统等外部依赖进行 mock
单元测试边界:对外部连接使用确定性的替代品;在为该契约选定的集成测试或 E2E 测试中,实际调用真实的外部边界
测试失败应对的判断标准
修正测试:预期值错误、引用了不存在的功能、依赖于实现细节、仅为测试而存在的实现
修正实现:合理的规格、业务逻辑、重要的边缘情况
两种解读在现有需求下都说得通:返回未解决的行为决策 —— 说明两种候选行为、能够裁定哪一种正确的来源,以及在不做选择之前应停止的条件
测试粒度原则
核心原则:只验证可观测行为
通过可观测边界进行测试:公共 API、返回值、异常、外部调用和持久化状态。只能通过这些可观测边界间接触及私有方法、内部状态和算法细节。
安全原则
安全默认值
- 通过环境变量或专用的密钥管理器存储凭据和密钥
- 对所有数据库访问使用参数化查询(预处理语句)
- 使用语言或框架提供的成熟加密库
- 使用密码学安全的随机数生成器生成安全关键值(令牌、ID、nonce)
- 使用标准协议对静态和传输中的敏感数据进行加密
输入与输出边界
- 在系统入口处校验所有外部输入的预期格式、类型和长度
- 根据渲染上下文(HTML、SQL、shell、URL)对输出进行适当编码
- 错误响应中只返回调用方所需的信息;详细诊断信息记录在服务器端日志中
访问控制
- 对所有处理用户数据或触发状态变更的入口点应用身份验证
- 对每次资源访问都进行授权校验,而不仅仅在入口处
- 只授予操作所需的最小权限(文件、数据库连接、API 作用域)
知识截止日期补充(2026-03)
- OWASP Top 10:2025 已从关注症状转向关注根本原因;新增了“软件供应链失效”(A03)和“异常情况处理不当”(A10)
- 最新研究表明,AI 生成的代码在访问控制方面存在缺陷的比例较高 —— 应将身份验证和授权列为高优先级评审对象
- OpenSSF 发布了《面向 AI 代码助手指令的安全导向指南》—— 建议使用针对特定语言的可执行约束,而非泛泛而谈的建议
- 详细的检测模式请参见
references/security-checks.md