零容错设计原则(Fail Fast)
任何异常/失败/边界情况必须立即暴露,宁可崩溃不可静默。
参考:docs/KnowLedge/零容错设计原则.md(完整版)
哲学基础
软件熵增定律
错误被掩盖 = 系统熵增,错误被暴露 = 系统熵减。
每次静默吞没异常,系统就多一个不可见的不稳定点,累积到临界值后以不可预测的方式爆发。
失败传播定律
早期失败成本 = O(1) — 问题在发生处即时报 晚期失败成本 = O(n²) — 问题在 N 步后以诡异方式爆发失败越早暴露,修复成本越低。每延迟一层传播,排查复杂度平方增长。
确定性原则
系统行为应可预测。静默失败破坏可预测性——调用方以为操作成功,实际已失败,后续行为不可预测。
三种失败模式对比
| 模式 | 行为 | 适用场景 | 代价 |
|---|---|---|---|
| Fail Fast | 立即抛出异常 | 不可恢复错误、前置条件违例 | 调用方必须处理 |
| Fail Safe | 降级到安全默认值 | 用户输入校验、可选功能失效 | 可能隐藏问题 |
| Fail Graceful | 优雅降级,部分可用 | 非核心功能失效、第三方超时 | 实现复杂度高 |
零容错 = Fail Fast 的严格形式:在初始化、边界、数据完整性等关键路径上,拒绝 Fail Safe 的默认值替代策略。
三层检查体系
按契约式编程(Design by Contract)的三个维度组织:
前置条件检查(Precondition)— 调用方责任
方法被调用前必须满足的条件,不满足则拒绝执行。
| 规则 | 说明 | 异常类型 |
|---|---|---|
| 创建/工厂方法失败抛异常 | 工厂、构建器、DI 容器无法创建实例时抛异常,指明缺失的类型/配置/依赖 | InvalidOperationException |
| 查找/获取不到抛异常 | 查找、获取、解析方法找不到目标时抛异常,指明查找的键/名称/条件 | KeyNotFoundException/InvalidOperationException |
| 配置缺失报错 | 必要字段、类型、依赖缺失时在启动/初始化时抛异常,禁止默认值替代 | InvalidOperationException |
后置条件保证(Postcondition)— 实现方责任
方法执行后必须保证的状态,无法保证则拒绝静默返回。
| 规则 | 说明 | 异常类型 |
|---|---|---|
| 禁止空 catch | 所有 catch 块必须记录异常,禁止catch {}静默吞没 | 视场景而定 |
| 状态不一致立即暴露 | 内部状态校验发现不一致时立即抛异常,禁止尝试静默修复 | InvalidOperationException |
不变式维护(Invariant)— 全局责任
系统在任何时刻都必须保持的恒常条件。
| 规则 | 说明 | 异常类型 |
|---|---|---|
| 边界显式检查 | 参数 null、集合空、索引越界在方法入口处显式检查 | ArgumentNullException/ArgumentOutOfRangeException |
聚合架构设计规范
参考:
docs/KnowLedge/聚合架构设计规范:从三收拢点到多元聚合的工程范式.md(v3.0)
核心:让隐式的依赖变得显式,让分散的操作变得集中,让混乱的边界变得清晰。
定义与结构
聚合 = 边界 + 契约 + 实现
| 要素 | 含义 | 设计关注点 |
|---|---|---|
| 边界 | 职责范围 | 清晰/完整/无重叠 |
| 契约 | 对外接口 | 稳定/完备/可测试 |
| 实现 | 内部细节 | 可替换/可独立演化 |
拓扑结构:三种类型可嵌套组合(面→线→点)
| 类型 | 定义 | 适用场景 | 示例 |
|---|---|---|---|
| 点聚合 | 分散同类操作收敛到单一入口 | 外部依赖/数据流边界收敛 | EcsInputPort/CsgEntryPoint/WinFormsOutputPort |
| 线聚合 | 有序步骤编排为管线 | 流程编排/阶段式处理 | EcsRenderPipeline.ExecutePipeline() |
| 面聚合 | 模块公开能力收敛到入口面 | 模块能力出口收敛 | WorkflowMethodUsage |
设计规范
聚合点识别原则(何时创建聚合点):
- 外部依赖收敛:多组件依赖同一外部资源时,创建聚合点封装
- 数据流边界收敛:数据跨子系统流动时,在边界创建聚合点
- 能力出口收敛:模块对外提供多能力时,创建统一入口
- 变更热点收敛:频繁变更点收敛到聚合点中限制影响范围
聚合边界划分规范:
- 单一职责:一个聚合点只负责一个维度的收敛
- 边界内完整:能力必须完整覆盖该维度所有场景
- 边界间无重叠:聚合边界间不允许职责重叠
聚合间通信契约:
| 方式 | 适用场景 | 耦合度 |
|---|---|---|
| 方法调用 | 同步、同进程 | 编译时耦合 |
| 事件/委托 | 异步、解耦 | 运行时耦合 |
| 数据对象 | 跨边界传输 | 数据耦合 |
反模式与评估
从内聚度、收敛度、边界清晰度三个维度评估聚合质量:
| 反模式 | 症状 | 解决方案 |
|---|---|---|
| 上帝聚合(过度聚合) | 方法 >30,实现 >1000 行 | 拆分为多个单一职责聚合点 |
| 分散聚合(聚合不足) | 操作分散,无统一入口 | 创建统一输出聚合点 |
| 隐式聚合(无明确边界) | 边界不明确,越界操作 | 明确边界,禁止越界 |
| 循环聚合(循环依赖) | 聚合点 A ↔ 聚合点 B | 引入事件/委托打破循环 |
设计哲学
解耦:减少模块间直接依赖 聚合:将分散操作收敛到统一入口正确聚合不会增加耦合,而是将隐式分散的耦合转化为显式集中的耦合。
设计目标:高解耦 + 高聚合——模块间契约通信,模块内聚合收敛。
核心价值:可审计(关键操作经明确入口/出口)、可维护(变更影响被聚合边界限制)、可演化(内部实现可替换,对外契约不变)。三者相互促进,目标是在三者间找到适合项目阶段的最优平衡点。
文件读取策略
核心:一次读取,分阶段消化。让读取深度与分析深度匹配。
参考:docs/KnowLedge/文件读取策略.md(完整版)
上下文守恒定律
逐个读取 N 个文件的总消耗 = Σ(每个文件的上下文开销 + 往返开销)。批量读取 N 个文件的总消耗 ≈ max(文件开销) + 单次往返开销。当 N > 1 时,批量读取始终优于逐个读取。
推论:每减少一次往返,就多一份预算用于真正的分析。
信息分层理论
信息按密度分三层,分析阶段与信息层次必须匹配,不可跳跃:
| 层次 | 内容 | 对应阶段 |
|---|---|---|
| 元信息 | 路径、大小、语言类型 | 扫描 |
| 结构信息 | 类/函数签名、大纲 | 预览 |
| 细节信息 | 完整实现、算法逻辑 | 深入 |
约束:未评估信息域之前,不进行任何信息获取。未到达的分析阶段,不预加载其所需信息。
三阶段读取模型
| 阶段 | 目标 | 信息层次 | 约束 |
|---|---|---|---|
| 扫描 | 确定"有哪些文件需要关注" | 元信息 | 不读取任何文件内容 |
| 预览 | 批量获取结构信息,建立全局认知 | 结构信息 | 一次调用读取所有目标文件 |
| 深入 | 对选定文件进行完整分析 | 细节信息 | 仅对预览阶段确认为"需要深入"的文件执行 |
前置条件——信息域评估:进入三阶段之前,先评估所需信息的范围(单文件/单模块/跨模块/全项目)、类型(代码/配置/日志/文档/数据)、复杂度(简单/中等/复杂)和确定性(已知/模糊/未知)。
信息获取路径
两种基本路径:
- 链式追溯:沿调用链逐层追溯(函数调用链、项目依赖链、继承链),适用于理解数据流、评估变更影响。
- 平铺探索:按目录结构横向展开,只获取元信息和结构信息,适用于了解整体结构、模块划分。
四种读取策略
| 策略 | 定义 | 上下文效率 |
|---|---|---|
| 批量读取 | 一次调用读取所有目标文件 | ★★★★★ |
| 分阶段读取 | 按扫描→预览→深入逐层推进 | ★★★★☆ |
| 按需读取 | 仅当需要时才读取特定文件 | ★★★☆☆ |
| 流式读取 | 边读取边处理,不保留全量 | ★★★★★ |
策略选择:首次接触代码库→分阶段;修复已知 Bug→按需+批量;代码审查→批量;大文件/日志→流式;架构重构→分阶段+批量。
反模式
| 反模式 | 解决方案 |
|---|---|
| 盲目读取(无评估) | 先评估信息域,再选择策略 |
| 逐点读取(逐个读取) | 合并为批量读取 |
| 过度读取(只需头部却读全文) | 按信息层次分级读取 |
| 深度不匹配(扫描阶段加载细节) | 按三阶段模型匹配读取深度 |
设计哲学
先评估,后读取。 链式追溯,平铺探索。 扫描不预览,预览不深入。 一次读取,分阶段消化。