name: 深度防御验证 description: 在数据通过的每一层进行验证,使bug不可能发生 when_to_use: 当无效数据在深层执行中导致失败时,需要在多个系统层面进行验证 version: 1.1.0 languages: all
深度防御验证
概述
当你修复一个由无效数据引起的bug时,在一个地方添加验证似乎足够了。但单一的检查可能会被不同的代码路径、重构或模拟所绕过。
核心原则: 在数据通过的每一层进行验证。使bug在结构上不可能发生。
为什么需要多层验证
单一验证: “我们修复了bug” 多层验证: “我们使bug不可能发生”
不同层捕获不同情况:
- 入口验证捕获大多数bug
- 业务逻辑捕获边缘情况
- 环境守卫防止特定上下文中的危险
- 调试日志在其他层失败时提供帮助
四层验证
第一层: 入口点验证
目的: 在API边界拒绝明显无效的输入
function createProject(name: string, workingDirectory: string) {
if (!workingDirectory || workingDirectory.trim() === '') {
throw new Error('工作目录不能为空');
}
if (!existsSync(workingDirectory)) {
throw new Error(`工作目录不存在: ${workingDirectory}`);
}
if (!statSync(workingDirectory).isDirectory()) {
throw new Error(`工作目录不是目录: ${workingDirectory}`);
}
// ... 继续
}
第二层: 业务逻辑验证
目的: 确保数据对操作有意义
function initializeWorkspace(projectDir: string, sessionId: string) {
if (!projectDir) {
throw new Error('工作空间初始化需要projectDir');
}
// ... 继续
}
第三层: 环境守卫
目的: 在特定上下文中防止危险操作
async function gitInit(directory: string) {
// 在测试中,拒绝在临时目录外进行git init
if (process.env.NODE_ENV === 'test') {
const normalized = normalize(resolve(directory));
const tmpDir = normalize(resolve(tmpdir()));
if (!normalized.startsWith(tmpDir)) {
throw new Error(
`测试期间拒绝在临时目录外进行git init: ${directory}`
);
}
}
// ... 继续
}
第四层: 调试工具
目的: 捕获上下文以供取证
async function gitInit(directory: string) {
const stack = new Error().stack;
logger.debug('即将进行git init', {
directory,
cwd: process.cwd(),
stack,
});
// ... 继续
}
应用该模式
当你发现bug时:
- 追踪数据流 - 坏值从哪里起源?在哪里使用?
- 映射所有检查点 - 列出数据通过的每一个点
- 在每一层添加验证 - 入口、业务、环境、调试
- 测试每一层 - 尝试绕过第一层,验证第二层捕获它
会话示例
Bug: 空的 projectDir 导致在源代码中执行 git init
数据流:
- 测试设置 → 空字符串
Project.create(name, '')WorkspaceManager.createWorkspace('')git init在process.cwd()中运行
添加的四层:
- 第一层:
Project.create()验证不为空/存在/可写 - 第二层:
WorkspaceManager验证projectDir不为空 - 第三层:
WorktreeManager在测试中拒绝在临时目录外进行git init - 第四层: 在git init之前进行堆栈跟踪记录
结果: 所有1847个测试通过,bug不可能重现
关键洞察
所有四层都是必要的。在测试中,每一层都捕获了其他层遗漏的bug:
- 不同的代码路径绕过了入口验证
- 模拟绕过了业务逻辑检查
- 不同平台上的边缘情况需要环境守卫
- 调试日志识别了结构性误用
不要只停留在一个验证点。 在每一层添加检查。