所属阶段:第三阶段「工作流实战」(第 12-20 课) 前置条件:第 13 课(TDD 全流程) 本课收获:一次完整通过验证循环的代码提交
一、本课概述
代码写完了、测试通过了,能提交吗?在 ECC 的世界里,答案是不能。
测试通过只证明功能正确,但没有回答:代码风格规范吗?类型安全吗?有没有泄露密钥?有没有 SQL 注入?这些问题需要验证循环来回答。
本课回答三个问题:
- 验证循环有几步? --- 四步检查 + 一步提交
- 每步防范什么风险? --- 从逻辑错误到密钥泄露
- 失败了怎么办? --- 修复后从头重跑,没有捷径
学完本课,你将能独立完成一次从代码到提交的完整验证流程。
二、验证循环四步
2.1 全景图
yaml
┌────────────────────────────────────────────────────────┐
│ 验证循环 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────────┐ ┌──────────┐ │
│ │ TEST │ → │ LINT │ → │ TYPECHECK│ → │ SECURITY │ │
│ │测试 │ │风格 │ │类型检查 │ │安全检查 │ │
│ └──┬───┘ └──┬───┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ PASS? PASS? PASS? PASS? │
│ │ │ │ │ │ │ │ │ │
│ Yes No Yes No Yes No Yes No │
│ │ │ │ │ │ │ │ │ │
│ │ └─→ 修复 → 从头重跑 │ └─→ 修复 │ └─→ 修复 │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ 全部 PASS → 可提交 │
└────────────────────────────────────────────────────────┘
2.2 每步防范什么
| 步骤 | 检查内容 | 防范的风险 | 典型工具 |
|---|---|---|---|
| TEST | 单元/集成/E2E 测试 | 逻辑错误、边界错误、回归 | Jest、Vitest、Mocha、pytest |
| LINT | 代码风格、格式、反模式 | 风格不一致、潜在 Bug(未使用变量等) | ESLint、Prettier、Ruff、golint |
| TYPECHECK | 类型安全 | 类型不匹配、空值异常、接口不兼容 | tsc、mypy、go vet |
| SECURITY | 密钥泄露、注入、依赖漏洞 | 密钥泄露、SQL 注入、XSS、已知 CVE | security-reviewer Agent、npm audit |
2.3 为什么是这个顺序
顺序不是随意的,而是按发现成本从低到高排列:
- TEST 最先 --- 如果逻辑都不对,检查风格毫无意义
- LINT 第二 --- 风格问题最容易发现和修复
- TYPECHECK 第三 --- 类型错误可能需要修改接口,影响范围较大
- SECURITY 最后 --- 安全检查最严格,也最耗时
三、每步详解
3.1 TEST --- 测试通过
这一步在第 13 课已经详细讲过。要点回顾:
bash
# 运行所有测试
npm test
# 带覆盖率
npm test -- --coverage
# 要求:80%+ 覆盖率,所有测试 PASS
失败时:
- 修复实现代码,不是修复测试(除非测试本身写错了)
- 使用
tdd-guideAgent 辅助排查 - 检查测试隔离性 --- 是否有共享状态导致的耦合
3.2 LINT --- 风格检查
Lint 检查代码是否符合项目约定的风格规范:
bash
# JavaScript/TypeScript
npx eslint .
# Python
ruff check .
# Go
golangci-lint run
# Markdown(ECC 项目自身)
npx markdownlint-cli '**/*.md' --ignore node_modules
ECC 项目中的具体 Lint 配置:
- 使用
@eslint/jsflat config - Markdown 使用
markdownlint-cli - 所有 Lint 检查必须在提交前通过
失败时:
- 大部分 Lint 错误可以自动修复:
npx eslint . --fix - 手动修复后重新运行 Lint
- 不要用
// eslint-disable绕过检查(除非有充分理由且加注释说明)
3.3 TYPECHECK --- 类型检查
类型检查确保代码的类型安全:
bash
# TypeScript
npx tsc --noEmit
# Python
mypy .
# Go(内置)
go vet ./...
失败时:
- 类型错误通常意味着接口设计有问题
- 不要用
any(TypeScript)或# type: ignore(Python)绕过 - 如果确实需要绕过,加注释说明原因
3.4 SECURITY --- 安全检查
这是验证循环中最严格的一步。ECC 的 security.md 定义了 8 项强制安全检查:
css
提交前安全检查清单:
□ 无硬编码密钥(API Key、密码、Token)
□ 所有用户输入已验证
□ SQL 注入防护(参数化查询)
□ XSS 防护(HTML 已消毒)
□ CSRF 保护已启用
□ 认证/授权已验证
□ 所有端点有速率限制
□ 错误消息不泄露敏感数据
工具辅助:
bash
# 依赖漏洞扫描
npm audit
# 密钥扫描
git diff --cached | grep -i "api_key\|secret\|password\|token"
# 使用 security-reviewer Agent
# 会自动扫描 CRITICAL 安全问题
失败时 --- 安全响应协议:
- 立即停止 --- 不要继续提交
- 调用
security-reviewerAgent - 修复所有 CRITICAL 问题
- 轮换任何可能已暴露的密钥
- 审查整个代码库是否有类似问题
四、任何一步失败 → 从头重跑
这是验证循环最重要的规则:
TEST 失败 → 修复 → 重跑 TEST → LINT → TYPECHECK → SECURITY
LINT 失败 → 修复 → 重跑 TEST → LINT → TYPECHECK → SECURITY
TYPECHECK 失败 → 修复 → 重跑 TEST → LINT → TYPECHECK → SECURITY
SECURITY 失败 → 修复 → 重跑 TEST → LINT → TYPECHECK → SECURITY
为什么修复后要从头重跑?
因为修复一个问题可能引入新的问题:
- 修复类型错误可能破坏现有测试
- 修复安全问题可能改变代码逻辑
- 修复 Lint 错误可能改变代码格式影响行为
只有从头到尾全部 PASS,代码才是可提交的。
五、Conventional Commits 格式
验证循环通过后,就可以提交了。ECC 要求使用 Conventional Commits 格式:
5.1 格式
xml
<type>: <description>
<optional body>
5.2 类型速查表
| 类型 | 用途 | 示例 |
|---|---|---|
feat |
新功能 | feat: add slugify utility function |
fix |
Bug 修复 | fix: handle empty string in slugify |
refactor |
重构(不改行为) | refactor: extract regex patterns to constants |
docs |
文档 | docs: add JSDoc for slugify function |
test |
测试 | test: add edge case tests for slugify |
chore |
杂项(构建、依赖) | chore: update eslint config |
perf |
性能优化 | perf: cache compiled regex in slugify |
ci |
CI/CD | ci: add coverage check to GitHub Actions |
5.3 好的提交信息 vs 差的提交信息
bash
# BAD --- 描述做了什么(what)
git commit -m "update slugify.js"
# BAD --- 太笼统
git commit -m "fix bug"
# GOOD --- 描述为什么这样做(why)
git commit -m "fix: handle consecutive spaces in slugify to prevent double hyphens"
# GOOD --- 带正文补充上下文
git commit -m "feat: add input validation to slugify
TypeError is thrown for non-string arguments to fail fast
at the call site rather than producing unexpected results
from implicit type coercion."
六、代码质量清单
在验证循环之外,coding-style.md 还定义了一份代码质量清单。这不是自动化检查,而是人工确认:
提交前代码质量清单:
□ 代码可读、命名清晰
□ 函数短小(<50 行)
□ 文件聚焦(<800 行)
□ 无深层嵌套(>4 层)
□ 错误处理完备
□ 无硬编码值(使用常量或配置)
□ 无 mutation(使用不可变模式)
6.1 每项的判断标准
| 检查项 | 通过标准 | 常见违规 |
|---|---|---|
| 可读性 | 变量名表达含义,逻辑清晰 | 单字母变量、嵌套三元表达式 |
| 函数 <50 行 | 用行数计算,不含空行和注释 | 一个函数做太多事 |
| 文件 <800 行 | 200-400 行是理想范围 | 所有逻辑放一个文件 |
| 嵌套 <4 层 | if/for/while 的嵌套深度 | 用 early return 拍平 |
| 错误处理 | 每个可能失败的操作都有处理 | 空 catch 块、忽略 Promise rejection |
| 无硬编码 | 数字和字符串提取为常量 | if (retries > 3) 而非 MAX_RETRIES |
| 无 mutation | 使用 spread、map、filter 而非修改 | array.push() 而非 [...array, item] |
七、完整验证循环示例
用第 13 课写的 slugify 代码走一遍完整流程:
bash
# Step 1: TEST
node --test slugify.test.js
# ✓ 7 tests passed → PASS
# Step 2: LINT
npx eslint slugify.js slugify.test.js
# No errors → PASS
# Step 3: TYPECHECK(如果是 TypeScript 项目)
# npx tsc --noEmit
# 纯 JavaScript 项目可跳过此步
# Step 4: SECURITY
# 检查无硬编码密钥
grep -r "api_key\|secret\|password" slugify.js
# No matches → PASS
# 检查依赖漏洞
npm audit
# 0 vulnerabilities → PASS
# 全部 PASS → 可提交
git add slugify.js slugify.test.js
git commit -m "feat: add slugify utility with full test coverage
Implements URL-friendly text conversion with:
- Space to hyphen conversion
- Special character removal
- Consecutive hyphen collapsing
- Input type validation
Coverage: 100% (8/8 tests passing)"
八、本课练习
练习 1:完整验证循环(25 分钟)
用第 13 课写的 slugify 代码(或第 13 课练习中的 truncate 代码),完整执行一遍验证循环:
- 运行测试,确认全部 PASS
- 运行 Lint,修复所有问题
- 运行类型检查(如适用)
- 执行安全检查清单(逐项确认)
- 用 Conventional Commits 格式提交
记录每一步的输出和修复过程。
练习 2:故意失败(15 分钟)
在 slugify.js 中故意引入以下问题,然后尝试通过验证循环:
- 改变一个正则让测试失败
- 添加一个未使用的变量让 Lint 报错
- 硬编码一个假的 API Key 让安全检查报警
观察验证循环如何捕获每种问题。
练习 3:代码质量清单审查(10 分钟)
对照代码质量清单的 7 项,审查你在第 13 课写的代码:
- 函数是否 <50 行?
- 有没有硬编码值?
- 有没有 mutation?
- 命名是否清晰?
列出所有不符合项并修复。
练习 4(选做):审查一个开源项目
找一个你熟悉的开源项目的某个 PR,用 ECC 的代码质量清单和安全检查清单审查它。记录你发现了什么问题。
九、本课小结
| 你应该记住的 | 内容 |
|---|---|
| 验证循环四步 | TEST → LINT → TYPECHECK → SECURITY → 可提交 |
| 失败处理 | 任何一步失败 → 修复 → 从头重跑 |
| 安全检查清单 | 8 项强制检查(密钥、输入验证、注入、XSS、CSRF、认证、限流、错误消息) |
| Conventional Commits | <type>: <description> --- feat/fix/refactor/docs/test/chore/perf/ci |
| 代码质量清单 | 7 项人工确认(可读性、函数大小、文件大小、嵌套、错误处理、硬编码、mutation) |
| 安全响应协议 | 停止 → security-reviewer → 修复 → 轮换密钥 → 全局排查 |
十、下节预告
第 15 课:会话管理 --- 上下文、模型与持久化
代码写好了、提交了,但还有一个隐藏的问题:你的 AI 助手的上下文窗口是有限的。下节课我们将学习如何管理上下文窗口、选择合适的模型、在会话之间持久化状态。这些技能决定了你能否在大型项目中高效使用 ECC。
预习建议 :阅读 rules/common/performance.md,特别是 Model Selection Strategy 和 Context Window Management 两节。