mcpField
C
cc-defensive-programming

cc-defensive-programming

github.com/ryanthedev开发38448 次安装3 周前更新
代码仓库

关于 cc-defensive-programming

用于检查代码是否符合防御式编程规范,或协助一致地落实这些规范的技能。重点包括边界输入验证、断言的恰当使用和明确的错误处理,并提供审查与实施模式。

主要功能

  1. 01检查验证与异常处理模式
  2. 02发现空 catch 块
  3. 03区分断言与运行时处理
  4. 04设计输入验证边界
  5. 05统一错误处理策略

适用场景

  1. 01审查代码中的防御式编程问题
  2. 02为外部接口添加验证
  3. 03规划断言和错误处理规则
  4. 04改进异步失败处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ryanthedev/code-foundations --skill cc-defensive-programming

安装后在 Claude Code 中输入/cc-defensive-programming确认已加载。

附带文件checklists.md

详细介绍

cc-defensive-programming

防御式代码可以避免小故障不断累积,最终变成悄无声息、难以诊断的问题。以下四项检查可以捕获那些会破坏数据、掩盖错误,而非直接导致程序崩溃的违规情况——几乎总是必须执行;如需例外,必须明确说明理由:

检查项原因
断言中不包含可执行代码断言在生产构建中会被编译掉,其中的代码也会随之消失
不允许空的 catch 块悄无声息地吞掉错误,使其在下游演变成更难处理的故障
在入口处验证外部输入未经验证的输入会导致安全漏洞和数据损坏
断言仅用于检查程序错误预期可能出现的运行时错误需要进行处理,而非使用断言(断言在生产环境中会被禁用)

共享阈值和信息隐藏的理由:Read(${CLAUDE_PLUGIN_ROOT}/references/cc-foundations.md)。

两条优先于教科书规则的原则

  • “内部团队 API”仍然属于外部接口。 任何跨越网络或进程边界的数据都是外部输入——即使来自你们团队自己负责的服务,也要进行验证。
  • 设置屏障可以减少重复验证,但不能取代纵深防御。 在屏障内部,你可以假定数据已通过验证——但安全关键路径(身份验证、加密、PII)除外,这些路径需要再次验证。屏障处的验证也可能存在漏洞。

外部输入 = 无法证明受当前代码路径控制的任何数据:用户输入、文件、网络/API/DB 响应、环境变量,以及来自任何其他服务的数据。

不适用的情况

  • 无副作用的纯函数(但仍须在系统边界处验证输入)。
  • 原型/探索性代码:在确定错误处理策略前限时开发。
  • 测试代码——测试替身有意违反生产代码模式。
  • 性能关键的内部循环,且经性能分析确认断言开销超过 5%。

无论以上情况如何,安全关键代码(身份验证、授权、加密操作、PII 处理)都不得豁免。如有疑问,请进行验证。

模式

CHECKER

针对代码执行防御式编程、断言和异常检查清单:Read(${CLAUDE_SKILL_DIR}/checklists.md)。每个检查项输出一行:| Item | Status | Evidence | Location |,状态 ∈ VIOLATION(缺少验证、空 catch、有副作用的断言)/ WARNING(处理方式不一致、缺少文档)/ PASS。

APPLIER

制定断言放置方案、错误处理策略、屏障架构和验证实现。搜索代码库中现有的错误处理模式(异常 vs 返回码 vs Result 类型、自定义异常类、日志约定)并遵循该模式——错误处理的一致性是让故障可调试的关键。完整门禁:Read(${CLAUDE_PLUGIN_ROOT}/references/pattern-reuse-gate.md)。

断言与错误处理

条件断言错误处理
不应发生(程序员错误)是否
可能在运行时发生 / 预期的错误输入否是
外部输入否是——始终验证
内部接口,同一模块是否
跨越信任边界的内部接口是是
公共 API 的前置条件违规是是
安全关键 / 高可靠性系统两者都用两者都用(纵深防御)

当某个情况确实不明确(“这是程序错误还是预期情况?”)时,请向领域专家澄清需求,而不要猜测。

正确性与健壮性

  • 正确性 — 绝不返回不准确的结果;宁可关闭,也不输出错误答案(安全关键型、金融、数据管道)。
  • 健壮性 — 即使结果偶尔不准确,也要继续运行(消费类应用、内部工具)。
领域倾向于关键问题
安全关键型(医疗、航空)正确性—
企业/B2B、金融、数据管道正确性错误数据会导致错误的业务决策吗?下游是否假设数据完整无误?
SaaS 平台平衡错误答案与服务不可用,哪种影响更大?
消费类应用、内部工具健壮性用户能否从崩溃中恢复?
实时系统视上下文而定过期数据比没有数据更好还是更糟?

护栏设计

  1. 找出外部接口(用户输入、文件、网络、API、服务间调用)。
  2. 在护栏边界处进行验证 — 在此处检查所有外部数据。
  3. 在护栏内部,使用断言检测内部错误(假设数据已通过验证)。
  4. 策略:外部边界 = 错误处理;内部 = 断言。

类级护栏:公共方法进行验证和净化;该类中的私有方法可以假设数据安全。

错误处理策略选项

选择一种策略并始终如一地应用 — 错误处理是一项架构决策。

策略适用场景
返回中性值显示默认值、非关键配置
替换为下一条有效数据有冗余机制的流式/传感器数据
返回上一个答案显示刷新、非关键缓存(绝不用于金融数据)
替换为最接近的合法值输入钳制、滑块范围
记录警告并继续非关键降级、功能标志
返回错误代码采用状态约定的 API、C 风格接口
集中式错误处理器统一日志记录、集成监控
显示错误消息面向用户的应用(不要泄露安全信息)
正常关闭安全关键型、会导致数据损坏的错误

现代错误传播

同步异常传播依赖同步调用栈;这些模式需要显式处理:

  • async/await — 未处理的拒绝会导致 Node 崩溃;应包装等待调用,并重新抛出领域级异常。
  • 回调 — 错误不会传播;使用以错误为先的 callback(error, result) 模式,或包装为 promise。
  • Promise.all — 首个拒绝会导致其他结果丢失;使用 allSettled,并决定是整体失败还是接受部分结果。
  • 事件处理器 / React — 同步抛出的异常会被静默吞掉;应显式记录,并为渲染错误使用错误边界。

对抗式编程(开发构建)

在开发期间让错误显现出来,以便尽早发现;在生产环境中则通过优雅恢复降低干扰。技术包括:让断言触发中止、用垃圾数据填充已分配内存和已释放对象、让 default/else 分支彻底失败、将错误日志通过电子邮件发送给自己。

证据

  • “垃圾进,垃圾出”已过时 — 生产软件必须验证或拒绝输入 [McConnell p.188]。
  • 错误处理是一项架构决策,必须始终如一地执行 [McConnell p.197]。
  • 在生产环境中修复错误的成本约为设计阶段的 100 倍 [IBM Systems Sciences Institute]。
  • 火星气候轨道器因单位不匹配而失踪 [NASA 1999] — 连续成功九个月并不意味着代码是安全的。

链接

之后下一步
验证完成Skill(code-foundations:cc-control-flow-quality)

评论

支持 Markdown