{"name":"防御式编程","id":"软件工程-软件设计-代码质量-防御式编程","content":"# 防御式编程\n\n## 防御的本质\n\n### 问题根源：不确定性的系统性入侵\n\n软件系统本质上运行在一个**不完全可控的环境中**，其核心风险来源于：\n\n* 不可信输入（Untrusted Input）\n* 状态漂移（State Drift）\n* 时序不确定性（Timing Uncertainty）\n* 外部依赖不稳定（Unstable Dependencies）\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\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### 时间维度（What stage）\n\n```text\n事前（Prevention） → 事中（Detection & Handling） → 事后（Recovery & Learning）\n```\n\n### 系统层级（Where）\n\n```text\n数据层 → 领域层 → 控制层 → 系统层\n```\n\n### 二维矩阵模型\n\n|     | 事前（预防）        | 事中（处理）   | 事后（恢复/治理） |\n| --- | ------------- | -------- | --------- |\n| 数据层 | 输入验证、Schema约束 | 数据清洗、兜底值 | 数据修复、补偿   |\n| 领域层 | 不变量设计、类型系统    | 断言、状态校验  | 状态回滚      |\n| 控制层 | 接口契约、幂等设计     | 异常处理、重试  | 流程补偿      |\n| 系统层 | 隔离设计、限流       | 熔断、降级    | 自动恢复、监控   |\n\n## 失败模型（Failure Model）\n\n### 失败分类（按本质）\n\n| 类型   | 本质      | 示例     |\n| ---- | ------- | ------ |\n| 输入错误 | 非法或污染数据 | 参数非法   |\n| 状态错误 | 不变量被破坏  | 数据不一致  |\n| 时序错误 | 顺序/并发问题 | 并发覆盖   |\n| 资源错误 | 资源耗尽    | OOM、超时 |\n| 依赖错误 | 外部系统失败  | RPC失败  |\n\n### 失败属性\n\n| 维度   | 分类         |\n| ---- | ---------- |\n| 可恢复性 | 可恢复 / 不可恢复 |\n| 确定性  | 确定性 / 随机性  |\n| 影响范围 | 局部 / 全局    |\n\n### 映射关系\n\n```text\n失败类型 → 防御策略 → 恢复机制\n```\n\n例如：\n\n* 输入错误 → 验证 → 拒绝\n* 依赖错误 → 熔断 → 降级\n\n## 核心机制体系\n\n### 输入控制（Untrusted Input Control）\n\n**本质：信任边界控制**\n\n#### 原则：\n\n* 所有外部输入默认不可信\n* 输入必须转换为\"内部语义\"\n\n#### 机制：\n\n* Schema 校验\n* 类型系统（如 Null Safety）\n* DTO → Domain 转换\n\n`外部语义（不可信）→ 翻译层 → 内部语义（可信）`\n\n防止：**语义污染（Semantic Corruption）**\n\n### 状态约束（State Defense）\n\n**本质：不变量守护**\n\n不变量是系统在任何时刻都必须保持为真的陈述，一旦为假则系统进入未定义状态\n\n#### 机制：\n\n* 断言（Assertions）\n* 不变量检查（Invariant Check）\n* 不可变对象（Immutable Object）\n\n#### 原则：\n\n* 不变量是系统正确性的唯一来源\n* 一旦破坏，必须立即中断\n\n### 控制流防护（Runtime Control）\n\n**本质：失败传播控制**\n\n#### 策略：\n\n| 场景    | 策略        |\n| ----- | --------- |\n| 可恢复错误 | 重试        |\n| 临时错误  | 延迟        |\n| 不可恢复  | Fail-fast |\n| 高风险依赖 | 熔断        |\n| 非核心功能 | 降级        |\n\n### 隔离机制（Isolation）\n\n**本质：阻断错误传播**\n\n#### 模式：\n\n* Anti-Corruption Layer（ACL）\n* Bulkhead（舱壁隔离）\n* 数据隔离（DTO/VO）\n\n#### 目标：\n\n> 防止局部错误演变为系统性故障\n\n### 自恢复与治理（Recovery & Governance）\n\n**本质：系统自愈能力**\n\n#### 机制：\n\n* 自动重试\n* 健康检查（Probe）\n* 自动重启\n* 数据补偿\n\n## 工程闭环\n\n### 完整闭环模型\n\n```text\n防错设计（Design-time）\n        ↓\n防御式编程（Runtime Protection）\n        ↓\n容错系统（Fault Tolerance）\n        ↓\n可观测性（Observability）\n        ↓\n系统演进（Evolution）\n```\n\n### 关键反馈机制\n\n* Metrics（指标）\n* Logs（日志）\n* Tracing（链路）\n\n转化为：\n\n* SLO（服务目标）\n* Error Budget（错误预算）\n\n驱动：\n\n* 架构优化\n* 防御策略调整\n\n## 防御 vs 防错 vs 容错\n\n| 概念    | 阶段  | 本质     |\n| ----- | --- | ------ |\n| 防错设计  | 设计期 | 避免错误产生 |\n| 防御式编程 | 运行期 | 控制错误传播 |\n| 容错系统  | 系统级 | 保证系统存活 |\n\n三者关系：\n\n```text\n预防 → 控制 → 生存\n```\n\n## 成本与决策模型\n\n### 防御成本\n\n* 性能开销\n* 代码复杂度\n* 认知负担\n\n### 健壮性 vs 正确性权衡\n\n防御式编程的核心权衡在于**健壮性与正确性的取舍**：\n\n| 概念 | 定义 | 核心行为 |\n|------|------|----------|\n| **健壮性 (Robustness)** | 系统在异常输入或环境下仍能运行，哪怕输出不准确或不完整 | 包容错误，继续运行 |\n| **正确性 (Correctness)** | 永不返回错误结果，一旦出现异常则不返回结果或终止程序 | 拒绝错误，精确失败 |\n\n**核心矛盾：**\n\n* 健壮性追求\"程序不崩溃\"\n* 正确性追求\"结果不出错\"\n* 两者往往相互矛盾——高度健壮的系统可能返回似是而非的结果，高度正确的系统可能频繁拒绝服务\n\n### 决策原则\n\n| 场景     | 策略              |\n| ------ | --------------- |\n| 核心链路   | 强校验 + Fail-fast |\n| 非核心链路  | 降级优先            |\n| 高风险输入  | 强验证             |\n| 内部可信调用 | 弱防御             |\n\n核心思想：\n\n> 防御不是越多越好，而是\"在正确的位置防御选择正确的防御方式\"。\n\n## 现代演进趋势\n\n### 静态化防御\n\n* 类型系统（Type System）\n* 编译期检查（Compile-time Safety）\n\n减少运行时防御成本\n\n### 云原生自愈\n\n* 自动扩缩容\n* 健康检查 + 重启\n\n### 可观测性驱动设计\n\n* 防御策略基于数据调整\n* 从\"被动监控\" → \"主动优化\"\n\n### 契约驱动系统\n\n* OpenAPI / GraphQL\n* Schema-first\n\n输入防御前移\n\n### 关联内容（自动生成）\n\n- [/软件工程/架构/系统设计/可观测性.md](/软件工程/架构/系统设计/可观测性.md) 可观测性是防御式编程第四层治理的技术基础，通过指标、日志、链路实现运行时状态感知\n- [/软件工程/微服务/服务治理/服务容错.md](/软件工程/微服务/服务治理/服务容错.md) 服务容错是运行时防护层在分布式系统的延伸，熔断、降级、隔离等机制是防御策略的工程实例\n- [/软件工程/架构/系统设计/可用性.md](/软件工程/架构/系统设计/可用性.md) 可用性是防御式编程的核心目标之一，MTBF/MTTR 模型与防御闭环密切相关\n- [/软件工程/领域驱动设计.md](/软件工程/领域驱动设计.md) 防腐层（ACL）是防御式隔离机制在 DDD 中的模式起源，体现不变量保护思想\n- [/软件工程/软件设计/代码质量/防错设计.md](/软件工程/软件设计/代码质量/防错设计.md) 防错设计是防御式编程的互补理念，分别对应错误预防与错误容忍两个维度\n- [/软件工程/软件设计/代码质量/编码规范.md](/软件工程/软件设计/代码质量/编码规范.md) 编码规范是防御式编程在编码层面的落地指导，异常建模与日志规范是其重要组成\n- [/计算机网络/网络安全/Web安全.md](/计算机网络/网络安全/Web安全.md) Web 安全是输入验证的安全维度延伸，信任边界与纵深防御原则在两者中均有体现","metadata":"tags: ['软件工程', '计算机系统', '可靠性', '异常处理', '安全边界', '代码质量']","hasMoreCommit":false,"totalCommits":4,"commitList":[{"date":"2026-03-25T17:04:43+08:00","author":"MY","message":"docs(defensive-programming): 重构防御式编程文档完善理论体系","hash":"a9ee72b1940b37031b2862d8dce60a348c2ecd58"},{"date":"2026-02-12T14:07:03+08:00","author":"MY","message":"doc: 整理标签","hash":"290b3e8ad18f48832ac282290238d020fc030a88"},{"date":"2025-11-20T17:33:21+08:00","author":"MY","message":"docs(architecture): 完善防御式编程文档内容","hash":"b04c33dbc72c5fc69f7d27670ffe3c6bc6bd5a8d"},{"date":"2021-09-22T17:01:14+08:00","author":"cjiping","message":"➕新增 防御式编程","hash":"93279317eb857cff16bf52d4879d57058f1ceb78"}],"createTime":"2021-09-22T17:01:14+08:00"}