13.新系统免疫力建设
# 13.新系统免疫力建设
本篇定位:外科第四篇 · 预防医学——Greenfield 项目如何从 0 建立品质免疫力。
剧情节点:Day 86-90——OrderMonolith 交给小李接管。老陈立刻转向公司启动的新业务「次日达」,团队问:"这次能不能不生病?"预防医学开讲。
本篇病人:P-005 NextDaySvc 次日达新系统 · 从 0 搭建时如何守住品质。
承接经典:Robert C. Martin《架构整洁之道》/ Vaughn Vernon《实现领域驱动设计》/ Sam Newman《构建微服务》/ Google《Software Engineering at Google》第 3 部分。
本篇病案编号范围:A11-A15(架构类收尾) + 全系列预防性检查项
# 目录介绍
# 1. 急诊病例
# 1.1 新项目亦生病
Day 86,OrderMonolith 完成"90 天疗程"最后一次交接,小李正式接管。老陈端着新买的咖啡,被沈总在电梯口拦住:
"老陈,公司新业务'次日达(NextDaySvc)'正式立项,团队 6 人,你带。要求 8 周内 MVP 上线——但这一次,不能再走 OrderMonolith 的老路。"
老陈一口咖啡卡在喉咙里。他清楚知道:新项目最容易犯的错,就是重蹈旧项目所有的错——因为团队普遍相信"新代码总是干净的"。
老陈请出了他从 OrderMonolith 事故中学到的一句话:
"代码腐化不是老代码的专利——它从 Day 1 就在潜伏。"
Day 86 立项会上,团队 5 人(老王资深、小李轮岗、小张恢复、加两位新招工程师小周与小陆)签订了一份"品质公约",作为项目文化基石。
# 1.2 首周现坏味
老陈警惕地在 Day 91(正式开发第 5 天)做了一次预防性静态扫描,结果令人震惊:
| 度量项 | Day 91(新项目 5 天) | OrderMonolith 早期(Day 5,历史回溯) | 判定 |
|---|---|---|---|
| 圈复杂度 max | 8 | 5 | 已经在上升 |
| God Class(>500 行) | 1 个 OrderFacade 已达 340 行 | 0 | 预警 |
| 循环依赖 | 0 | 0 | 暂安全 |
| 未 mock 的 IO 单测 | 2 个 | 0 | 已经在腐化 |
| DTO 与 Domain 边界 | 未分层,直接透传 | 已分层(早期) | 重症 |
| 是否有 ADR | 无 | 无 | 传统病 |
老陈心里凉了半截:5 天,坏味道已经开始。新项目并不天然干净,它只是"病还没被发现"。
沈总在这次预扫描会议上敲桌:
"我们之前是给病人治病——现在要给健康人打疫苗。这就是本篇要解决的问题。"
# 1.3 本篇待答疑问
老陈在白板中央写下 5 个问号:
- 为什么新项目 5 天就有坏味道? 是能力问题还是习惯问题?
- 免疫力有哪些具体成分? 具体拆成哪些技术护栏?
- 哪些事必须在第 1 周做完,哪些可以推迟? 有没有节奏表?
- 架构师如何用"品质预算"约束未来 30 天? 预算怎么定?
- 组织层面如何让"预防医学"变成招聘、培训、传承的默认?
这 5 个问号将贯穿本篇。
"下集提要(本节):先看病理——新系统的六大早发病。你会发现它们和 OrderMonolith 90 天前遇到的是同一批病。"
# 1.4 一句话回顾
新项目也难逃生病——第 5 天就出现的坏味道,是免疫力建设最好的开场白。
# 1.5 核心要点
- Greenfield 不等于健康
- 坏味道从第 1 周就开始积累
- 免疫力必须从 Day 1 建立
# 1.6 带走清单
- [ ] Day 1 建立最小护栏
- [ ] Day 5 前完成 CI + 门禁
- [ ] Day 30 出第一次健康度报告
# 2. 病理诊断
# 2.1 六大早发病
老陈总结出新系统前 30 天最常出现的六大早发病(E1-E6):
| 编号 | 名称 | 典型症状 | 埋雷时间 |
|---|---|---|---|
| E1 | 无边界大类 | Facade / Service 一开始就承担 3+ 职责 | 第 1-3 天 |
| E2 | 透传 DTO | HTTP DTO 直入 Repository 或跨模块传递 | 第 3-7 天 |
| E3 | 无 ADR 决策 | 大决策口头达成,1 个月后没人记得为什么 | 第 5-10 天 |
| E4 | 假测试 | 测试全部 mock、无实际断言 | 第 5-10 天 |
| E5 | 配置蔓延 | 环境变量/开关到处散落,无统一 config schema | 第 10-15 天 |
| E6 | 观测缺失 | 无 metrics、无 traceId、无结构化日志 | 第 15-30 天 |
这六大病都符合三个特征:
- 潜伏期长:几周内不会崩,等到 3 个月后已成积重
- 修复成本指数上升:Day 5 修一次是 1 小时,Day 90 修同样问题是 1 周
- 具备"传染性":一个人破例就会有第二个人跟进
老陈画了一张"Boehm 缺陷成本曲线"(来自 Barry Boehm 经典研究):
修复成本
▲
│
│ ● 生产 (100x)
│
│ ● UAT (25x)
│
│ ● 系统测试 (10x)
│
│ ● 单测阶段 (3x)
│
│● 编码阶段 (1x)
└──────────────────────────────────────▶ 时间
结论:免疫力 = 让缺陷停在 1x 阶段。
# 2.2 A 系列病案登记
病案卡 A11:无边界大类(Big Ball of Mud 苗头)
- 症状:
OrderFacade340 行、Day 5 已复用于 3 个场景 - 危险等级:★★★★★(会长成 P-001)
- 首次出现:NextDaySvc Day 5
- 影响:3 个月后必然进入 P-001 状态
- 治疗手段:分层架构 + 单类 300 行硬约束 + Sonar 门禁
病案卡 A12:DTO 透传
- 症状:
CreateOrderRequest从 Controller 一路传到 Repository - 危险等级:★★★★☆
- 首次出现:NextDaySvc Day 5
- 影响:改一个字段影响整个链路
- 治疗手段:分层 DTO(HTTP DTO / Command / Domain / Entity)+ 转换器
病案卡 A13:无 ADR
- 症状:为什么选择 PostgreSQL 而不是 MySQL?无人能说清
- 危险等级:★★★☆☆
- 首次出现:NextDaySvc Day 6
- 影响:一年后决策无法审计
- 治疗手段:ADR (Architecture Decision Records) 模板 + Git 归档
病案卡 A14:观测缺失
- 症状:无 traceId、无 metric、无结构化日志
- 危险等级:★★★★★
- 首次出现:NextDaySvc Day 10
- 影响:上线后事故无法定位
- 治疗手段:第 1 周就接入 OpenTelemetry + 日志规范
病案卡 A15:假测试(承接 A03/A04 A11)
- 症状:测试全 mock、只测 mock、无真实断言
- 危险等级:★★★★☆
- 首次出现:NextDaySvc Day 5
- 影响:等到集成阶段才发现 bug
- 治疗手段:Test 金字塔占比强制 + Testcontainers 集成 + 变异测试
# 2.3 一句话回顾
新系统的六大早发病 + A11-A15 病案编号,是新项目最容易踩的坑。
# 2.4 核心要点
- 架构病比代码病更贵
- 早发病往往由团队习惯带来
- 编号让新项目也能沉淀经验
# 2.5 带走清单
- [ ] A11-A15 表贴到项目 wiki
- [ ] 架构评审必查六大早发病
- [ ] 新项目 Day 30 复盘早发病
# 3. 病因追溯
# 3.1 从零为何烂
Day 91 复盘会上,老陈问团队:"我们都从事故中活过来了,为什么 5 天又开始烂?"团队回答:
- 小李:"我以为新项目可以'快点写',规矩后面再补。"
- 老王:"业务方催得急,MVP 优先。"
- 小张:"我不知道要不要一开始就分层——教科书说 YAGNI。"
- 小周(新人):"我按前公司的习惯写的,那边就是 Controller 直接调 Repo。"
老陈把这四种心态归纳为新系统免疫失败四大心理根因:
| 根因 | 心态 | 破解方向 |
|---|---|---|
| N-Speed(速度诱惑) | "先跑起来再说" | 预设速度上限 + 品质预算 |
| N-Pressure(业务压力) | "MVP 优先" | MVP 定义包含品质 |
| N-YAGNI(过度援引) | "分层就是过度设计" | 区分结构必要 vs 提前抽象 |
| N-Habit(旧习惯) | "以前一直这样写" | 入职品质培训 + 结对编程 |
关键洞察:新项目并不会天然干净——它只是"病还没长出来"。免疫力必须从 Day 1 建立,因为Day 30 之后再补,成本已经是 10 倍。
# 3.2 免疫缺失症状
老陈用一个更形象的比喻:新系统的免疫缺失,就像不打疫苗的孩子。
症状 1:无抗体(Test/Contract 缺失)
- 没有测试守门 → 一改就出问题
- 没有 API 契约 → 上下游一动就崩
症状 2:无免疫记忆(ADR/Runbook 缺失)
- 没有决策记录 → 3 个月后无人知道为何这样设计
- 没有事故本 → 同样的错犯第二次
症状 3:无免疫细胞识别(分层/边界缺失)
- 没有分层 → 病灶迅速扩散
- 没有边界 → 一个模块的问题传染全系统
三大症状对应三个护栏:
- 抗体 → 测试 + 契约
- 记忆 → ADR + Runbook + Postmortem
- 识别 → 分层架构 + 防腐层
**"下集提要(本节):**病因清楚。下一节看治疗方案——免疫力五层护栏。"
# 3.3 一句话回顾
从 0 开始也依然会烂——因为免疫缺失的三大症状,与团队习惯高度相关。
# 3.4 核心要点
- 坏习惯会被搬进新项目
- 流程缺失是免疫缺失的第一信号
- 文化决定新项目的健康上限
# 3.5 带走清单
- [ ] 新项目 Day 1 就要有 CR 卡点
- [ ] 盘一下团队坏习惯清单
- [ ] 把文化红线写入项目 README
# 4. 治疗方案总纲
# 4.1 免疫力五层护栏
老陈画了一张"免疫力五层护栏"图,作为新系统 Day 1 的架构宪法:
┌─────────────────────────────────────────────────┐
│ Layer 5: 组织(招聘 · 培训 · 品质预算 · SLO) │
├─────────────────────────────────────────────────┤
│ Layer 4: 运行(观测 · 混沌工程 · 灰度 · 回滚) │
├─────────────────────────────────────────────────┤
│ Layer 3: 交付(CI 门禁 · 契约测试 · Preview) │
├─────────────────────────────────────────────────┤
│ Layer 2: 代码(分层架构 · 防腐层 · 契约测试) │
├─────────────────────────────────────────────────┤
│ Layer 1: 决策(ADR · MVP 定义 · 品质预算) │
└─────────────────────────────────────────────────┘
五层协同才能建立真正的免疫力。一个新项目在 Day 1 就应完成这五层的"疫苗接种"。
# 4.2 分层与契约
核心分层参考 Clean Architecture(Robert C. Martin):
外部
┌────────────────────────────────┐
│ Adapters(Controller/Kafka) │ ← HTTP DTO 只活在这层
├────────────────────────────────┤
│ Application(Use Cases) │ ← Command / Query
├────────────────────────────────┤
│ Domain(Entity + Value) │ ← 业务规则的家
├────────────────────────────────┤
│ Infrastructure(Repo/HTTP) │ ← 通过接口反向依赖
└────────────────────────────────┘
依赖方向铁律:外层依赖内层,内层永远不知道外层存在。
以 NextDaySvc 为例:
// ✅ 正确:Domain 定义接口
package com.nds.domain;
public interface OrderRepository {
Optional<Order> findById(OrderId id);
void save(Order order);
}
// Infrastructure 实现接口
package com.nds.infra.jpa;
@Repository
public class JpaOrderRepository implements OrderRepository {
// JPA 细节仅存在这里
}
分层 DTO 规范(对齐 A12):
| 层 | DTO 类型 | 目的 | 命名 |
|---|---|---|---|
| Adapter | CreateOrderHttpRequest | HTTP 边界 | *HttpRequest/Response |
| Application | CreateOrderCommand | 用例入参 | *Command / *Query |
| Domain | Order (Aggregate) | 业务实体 | 纯业务名 |
| Infrastructure | OrderEntity | 存储映射 | *Entity |
层间转换用 Mapper(MapStruct):
@Mapper
public interface OrderMapper {
CreateOrderCommand toCommand(CreateOrderHttpRequest req);
OrderEntity toEntity(Order order);
Order fromEntity(OrderEntity entity);
}
关键效果:改 HTTP DTO 字段,Repository 不受任何影响。
**"下集提要(本节):**总纲清楚。下一节住院医查房——新项目第 1 周就要建的 4 件事。"
# 4.3 一句话回顾
免疫力五层护栏 + 分层架构与接口契约,是新项目可复现的健康骨架。
# 4.4 核心要点
- 五层护栏覆盖代码 → 架构 → 契约 → 流程 → 文化
- 分层不清晰是所有腐化的起点
- 契约是模块之间的免疫屏障
# 4.5 带走清单
- [ ] 项目 Day 1 就定义分层与依赖方向
- [ ] 接口契约先行,实现在后
- [ ] 每层护栏都要有对应度量
# 5. 住院医查房
# 5.1 首周四件事
目标读者:新加入项目的初中级开发(小周、小陆),需要知道"入手就该做什么"。
四件事一览:
| 序号 | 事项 | 交付物 | 期限 |
|---|---|---|---|
| 1 | 代码脚手架 + 分层骨架 | 空 Controller/UseCase/Domain/Infra 各 1 个类 | Day 1-2 |
| 2 | CI 门禁 + 测试脚手架 | GitHub Actions + Jacoco + Testcontainers | Day 2-3 |
| 3 | PR/Issue/ADR 模板 | .github/ 目录三个模板 | Day 3 |
| 4 | 观测最小闭环 | 结构化日志 + traceId + 一个 hello metric | Day 3-5 |
这四件事的哲学:先把"跑不通品质门禁"变成"痛苦",让后续每一行代码天然被约束。
详细展开每一件事:
# 事项 1:分层骨架
com.nds/
adapter/
http/OrderController.java
application/
CreateOrderUseCase.java
domain/
order/Order.java
order/OrderRepository.java ← 接口
infrastructure/
persistence/JpaOrderRepository.java ← 实现
Day 1 就有 4 层,即使功能只有一个 hello world。
# 事项 2:CI 门禁
name: NDS PR Gate
on: [pull_request]
jobs:
quality-gate:
steps:
- uses: actions/checkout@v4
- name: Build & Test
run: ./gradlew build jacocoTestReport
- name: Coverage Gate
run: |
coverage=$(cat build/reports/coverage.txt)
if (( $(echo "$coverage < 80" | bc -l) )); then
echo "Coverage below 80%"; exit 1
fi
- name: Sonar (Clean as You Code)
run: ./gradlew sonar
- name: PIT Mutation Score
run: ./gradlew pitest
- name: PR Size Check
run: |
lines=$(git diff --numstat origin/main HEAD | awk '{sum+=$1} END {print sum}')
if [ $lines -gt 400 ]; then echo "PR too large"; exit 1; fi
# 事项 3:三大模板
PR 模板(.github/PULL_REQUEST_TEMPLATE.md):
### Why
### How
### Testing
### Risk
### Rollback
ADR 模板(docs/adr/000-template.md):
# ADR-XXX: [标题]
- Status: proposed / accepted / superseded
- Date: YYYY-MM-DD
- Author: @xxx
## Context
## Decision
## Alternatives Considered
## Consequences
Issue 模板:Bug / Feature / Chore 各一份。
# 事项 4:观测最小闭环
// 结构化日志 + traceId 自动注入
@Slf4j
@RestController
public class OrderController {
private final Counter orderCreatedCounter = Metrics.counter("nds.order.created");
@PostMapping("/orders")
public ResponseEntity<?> create(@RequestBody CreateOrderHttpRequest req) {
log.info("order.create.received orderKey={}", req.orderKey());
// ... 业务
orderCreatedCounter.increment();
return ResponseEntity.ok(...);
}
}
Day 5 交付验证:
- ☐ 空业务但 CI 通过
- ☐ Sonar 首次扫描:0 issue、覆盖率 100%(因为没代码)
- ☐ Grafana 上能看到
nds.order.createdmetric
# 5.2 PR 工单模板
关键原则:模板存在的意义是降低"该写什么"的心理负担。
PR 模板延伸字段(比第 12 篇更细):
### Why
问题背景与业务价值(1-3 句)
### How
- 涉及模块与关键改动点
- 关键类/方法
### Testing
- [ ] 单测新增/更新
- [ ] 集成测试
- [ ] 手工验证步骤
### Risk
- 破坏性变更:无 / 有(详述)
- 兼容性:向前兼容 / 需迁移
### Rollback
- 回滚方式:Git revert / 灰度关闭 / DB migration down
### Related
- Issue: #xxx
- ADR: adr/xxx.md
Issue 模板 - Bug:
### 环境
- 版本:
- 环境:dev / uat / prod
- 影响用户:
### 复现步骤
1.
2.
### 期望 / 实际
### 附件(日志/截图/traceId)
# 5.3 初级带走清单
- ☐ 入职 Day 1 先建 4 层目录
- ☐ CI 门禁不通过决不合并
- ☐ 每个 PR 用模板四段
- ☐ 每个 API 有 traceId
- ☐ 每个决策超过 30 分钟争论 → 写 ADR
- ☐ 分不清 DTO 层级 → 问老陈或看第 6 章
# 6. 主治查房
# 6.1 API 契约设计
目标读者:老王等资深工程师,需要为团队定接口设计规则。
API 契约五条硬规则:
规则 1:向后兼容优先
- 只加字段,不改字段类型
- 删字段 → 走 6 个月弃用期(Deprecated 标记 + 双写 + 告警)
规则 2:显式版本
/v1/orders
/v2/orders # 破坏性变更时新增
规则 3:Idempotency-Key(幂等键)
POST /v1/orders
Idempotency-Key: 4f89a-...
规则 4:错误码规范
{
"code": "NDS.ORDER.OUT_OF_STOCK",
"message": "Item xyz is out of stock",
"traceId": "abc-123"
}
规则 5:OpenAPI 契约
- 用 OpenAPI 3.0 定义
- 用 Prism 起 mock server 提前给上下游
- 用 Pact 做消费者驱动契约测试(对齐第 11 篇 T10)
跨语言对比:接口契约实现
| 语言 | 主流工具 | 关键点 |
|---|---|---|
| Java | springdoc + Pact JVM | 从代码生成 OpenAPI + 契约验证 |
| Go | swag + Pact Go | 注释生成 spec + Pact 消费者 |
| Python | FastAPI + schemathesis | 自动生成 spec + fuzz testing |
| TypeScript | tRPC / zod + Pact Node | 类型即契约 |
# 6.2 领域模型 + 防腐层
Vaughn Vernon 在《实现领域驱动设计》里说:
"Anti-Corruption Layer 是保护你的领域不被别人污染的最后一道墙。"
NextDaySvc 案例:与老 OrderMonolith 集成
问题:新系统需要读取 OrderMonolith 的 order 数据,但对方数据结构混乱。
错误方案:直接把 OrderMonolith 的 DTO 拉进来用。
正确方案(防腐层):
// domain/order/Order.java —— 我们自己的干净模型
public class Order {
private OrderId id;
private Customer customer;
private Money total;
private OrderStatus status;
// ...
}
// infrastructure/adapter/legacy/OrderMonolithClient.java
@Component
public class OrderMonolithClient {
// 调用 legacy API 拿"脏"数据
LegacyOrderDto fetchLegacy(String id);
}
// infrastructure/adapter/legacy/LegacyOrderTranslator.java
@Component
public class LegacyOrderTranslator {
// ⭐ 防腐层:翻译 legacy DTO → 我们的 Domain
public Order translate(LegacyOrderDto legacy) {
return Order.builder()
.id(new OrderId(legacy.getOid()))
.customer(new Customer(legacy.getUname()))
.total(Money.of(legacy.getAmt() / 100, "CNY")) // 分转元
.status(mapStatus(legacy.getSt()))
.build();
}
}
规则:Legacy 世界的一切"脏"永远不能穿过防腐层进入 Domain。
# 6.3 高级带走清单
- ☐ API 五条契约硬规则从 Day 1 生效
- ☐ 用 OpenAPI 3.0 定义 + Prism mock + Pact 契约
- ☐ 与遗留系统集成 → 强制防腐层
- ☐ 领域模型不含技术细节(JPA/HTTP/Kafka)
- ☐ Domain 定义接口,Infrastructure 实现
- ☐ 每季度回扫依赖方向:是否有内层引用外层?
# 7. 主任查房
# 7.1 品质预算与 SLO
目标读者:沈总这类架构师/PM,需要用组织层机制约束品质。
"品质预算(Quality Budget)" 概念来自 Google SRE:允许一定的不完美,但设定不可越界的上限。
NextDaySvc 品质预算示例:
| 维度 | 上限 | 触发动作 |
|---|---|---|
| 生产事故率 | 每月 ≤ 2 起 P2+ | 超限 → 冻结新需求 1 周 |
| 服务可用性 SLO | ≥ 99.9%/月 | 消耗 error budget 后停发布 |
| 单测覆盖率 | 增量 ≥ 80% | Sonar 门禁自动拦 |
| PIT 变异分数 | 增量 ≥ 0.7 | CI 自动拦 |
| 技术债比 | ≤ 5% | 每冲刺预留 20% 时间还债 |
| PR lgtm 率 | ≤ 15% | 周会 CR 高光 |
| 事故 MTTR | ≤ 30min | 观测 + Runbook |
品质预算的政治价值:当业务方催速度时,架构师可以指着预算说 "现在越界,将来必崩"。
沈总把这份预算做成一张仪表盘,钉在办公室:
NextDaySvc · Quality Dashboard Day 91 / 8 周
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
可用性 SLO 99.98% ████████████████░ 预算余额 84%
覆盖率(增量) 82.4% █████████████████ ≥80 ✅
变异分数 0.74 ████████████████░ ≥0.7 ✅
技术债比 2.1% ██████████████░░░ <5 ✅
LGTM 率(周) 11% █████████████████ <15 ✅
生产事故(30d) 0/2 █████████████████ 预算余额 100%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
状态:✅ 所有指标在预算内
# 7.2 组织免疫建设
免疫力必须组织化,否则一个人一走,团队又回到原点。三大机制:
机制 1:招聘筛品质基因
- 面试第 3 轮加"代码审查题":给应聘者一段真实历史 PR,让他 CR 30 分钟
- 观察三点:是否分级意见(nit/consider/must)、是否给方案、是否礼貌
- 结果 → 判断其"品质文化契合度"
机制 2:入职 30 天品质训练营
| 周次 | 内容 | 交付物 |
|---|---|---|
| Week 1 | 分层架构 + 防腐层 + 团队 Style Guide | 通过基础测验 |
| Week 2 | 测试金字塔 + Testcontainers + PIT | 独立写完 1 个 UseCase 全套测试 |
| Week 3 | CR 卡点 + 60 条清单 + 三句式 | 结对完成 3 次 PR |
| Week 4 | 观测 + Runbook + 事故复盘 | 参与 1 次故障复盘 |
机制 3:传承 —— 三个仪式
- 每月 ADR Review:全员回顾本月新决策
- 每季度 Postmortem 讲堂:过去 3 个月事故一次讲透
- 年度品质工坊:邀请外部专家 + 内部经验分享
关键洞察:技术护栏可以复制,品质文化只能培养。招聘、培训、传承是唯一路径。
# 7.3 架构师带走清单
- ☐ Day 1 就定品质预算 + SLO
- ☐ 每周仪表盘 → 品质状态可见
- ☐ 面试筛品质基因(不只筛技术)
- ☐ 30 天新人训练营 = 组织的疫苗
- ☐ ADR Review / Postmortem 讲堂 / 品质工坊 三仪式
- ☐ 每季度回顾"预算是否被消耗、为什么"
# 8. 术后康复曲线
# 8.1 首月度量对照
NextDaySvc Day 86-Day 116(30 天),关键指标:
| 度量项 | Day 91(第 5 天预警) | Day 116(30 天后) | 目标水位 | 判定 |
|---|---|---|---|---|
| 圈复杂度 max | 8 | 6 | ≤ 10 | ✅ |
| 单类 max 行数 | 340 | 185 | ≤ 300 | ✅ |
| 循环依赖 | 0 | 0 | 0 | ✅ |
| 未 mock 的 IO 单测 | 2 | 0 | 0 | ✅ |
| 覆盖率(增量) | 62% | 83% | ≥ 80% | ✅ |
| PIT 变异分数 | 0.48 | 0.76 | ≥ 0.7 | ✅ |
| ADR 数量 | 0 | 11 | ≥ 8 | ✅ |
| Sonar 阻断 issue | 6 | 0 | 0 | ✅ |
| lgtm-only PR 率 | 未监控 | 9.2% | ≤ 15% | ✅ |
| 生产事故(30d) | — | 0 | ≤ 2 | ✅ |
沈总在 Day 116 复盘会上说:
"30 天,0 事故,全预算未消耗——这就是免疫力。它不是没病,是把病挡在了 Day 5。"
# 8.2 老系统早期对比
老陈做了一张"两个项目同期指标对比":
| 指标 | NextDaySvc Day 30 | OrderMonolith 历史 Day 30 |
|---|---|---|
| 圈复杂度 max | 6 | 14 |
| 单类 max 行数 | 185 | 690 |
| 循环依赖 | 0 | 4 |
| 覆盖率 | 83% | 24% |
| 生产事故(30d) | 0 | 3 |
| ADR | 11 | 0 |
| CR 通过 lgtm 率 | 9.2% | 无度量 |
"这就是打疫苗和不打的差别。" 老陈把这两列对比投在大屏上,会议室鸦雀无声。
# 8.3 一句话回顾
30 天后与 OrderMonolith 早期的对比,是新项目免疫力建设投入产出比的直接证据。
# 8.4 核心要点
- 新项目 30 天的健康度可以量化
- 免疫力建设越早越省
- 早期投入 1,后期节省 10
# 8.5 带走清单
- [ ] Day 30 出健康度报表
- [ ] 与团队历史项目做基线对比
- [ ] 把健康度纳入季度指标
# 9. 病案归档
# 9.1 A 系列编号
| 编号 | 名称 | 关键指标 | 治疗手段 |
|---|---|---|---|
| A11 | 无边界大类 | 单类 > 300 行 | 分层 + 单类硬约束 + Sonar |
| A12 | DTO 透传 | HTTP DTO 穿透层 | 分层 DTO + MapStruct 转换 |
| A13 | 无 ADR | 决策无记录 | ADR 模板 + Git 归档 |
| A14 | 观测缺失 | 无 traceId/metric | Day 1 观测闭环 |
| A15 | 假测试 | Mock 无断言 | 金字塔占比 + PIT + Testcontainers |
# 9.2 全专栏连接
- N01-N05(命名类):Day 1 就通过 Style Guide 预防
- F01-F05(函数类):Day 1 Sonar Cognitive 门禁预防
- C01-C05(条件类):Day 1 分层 + 策略模式预防
- E01-E05(错误边界):Day 1 契约五规则预防
- T01-T12(测试类):Day 1 CI 门禁 + PIT 强制
- D01-D10(度量/债务类):Day 1 品质预算预防
- R01-R08(CR 类):Day 1 三层门禁自动执行
病案总览统计(截至本篇):全专栏共登记 62 个病案(N×5 + F×5 + C×5 + E×5 + T×12 + A×15 + D×10 + R×8 - 部分复用编号),构成完整的《代码疾病 ICD 手册》。
# 9.3 一句话回顾
A11-A15 病案 + 全专栏连接,就是新项目免疫力建设的最小执行合集。
# 9.4 核心要点
- 新项目也需要病案编号
- 编号让新项目沉淀成团队资产
- 归档是团队免疫力的复利
# 9.5 带走清单
- [ ] A11-A15 表进 CR 模板
- [ ] 新项目 Day 30 补充新编号
- [ ] 把编号命中率纳入季度指标
# 10. 综合案例串讲
# 10.1 病例真相揭晓
NextDaySvc 8 周 MVP 上线全流程真相:
- Day 86-90:项目启动 → 品质公约签订 + 五层护栏铺设
- Day 91:预防性静态扫描发现 5 大坏味道 → 立即修正
- Day 92-100:分层架构 + 防腐层落地 → 与 OrderMonolith 联调
- Day 101-115:核心业务 UseCase 开发 + 契约测试 + 变异测试
- Day 116:30 天中期健康检查 → 全部指标在预算内
- Day 130(预计):8 周 MVP 上线 → 打赌不会有 P1 事故
Day 116 的中期报告扉页写着:
"这不是新系统会不会生病的赌注——这是新系统能不能拒绝生病的证明。"
# 10.2 新服务首月轴
Day 86(周一)· 立项
- 品质公约签订 · 团队成员宣誓
- 5 层护栏方案通过
- 品质预算与 SLO 确定
Day 87(周二)· 脚手架 Day 1
- 4 层目录建立
- CI 门禁 v1 部署
- 观测最小闭环上线(Grafana 显示第 1 个 metric)
Day 88-90(周三-周五)· 脚手架完善
- PR/Issue/ADR 三模板启用
- OpenAPI 契约首版发布
- Testcontainers 集成
Day 91(周一)· 首次预防扫描
- 发现 A11-A15 五大坏味道
- 立即整改,Day 92 全部关闭
Day 92-100(第 2 周)· 与 legacy 集成
- 防腐层落地
- Pact 契约测试首个用例
- ADR-003(为何用 PostgreSQL 而非 MySQL)归档
Day 101-115(第 3-5 周)· 核心业务开发
- 5 个 UseCase 交付
- 变异测试分数稳定 ≥ 0.7
- 组织级:新人 2 周训练营首期开营
Day 116(第 6 周初)· 中期检查
- 品质仪表盘全绿
- 团队第一次感到"这项目跟以前不一样"
# 10.3 设计哲学回扣
Robert C. Martin 在《架构整洁之道》里说:
"The goal of software architecture is to minimize the human resources required to build and maintain the required system."(软件架构的目标是最小化构建与维护系统所需的人力。)
Vaughn Vernon 在《DDD》里说:
"Strategic design is where the value lives; tactical patterns are just tools."(战略设计才是价值所在;战术模式只是工具。)
Sam Newman 在《构建微服务》里说:
"A service that's not observable is a black box—it will fail in ways you cannot debug."
这三句话共同指向一件事:免疫力不是技术手段的堆砌,是决策与文化的沉淀。
"新系统免疫力"的核心哲学(老陈总结):
"最强的品质工程,不是治病救人,而是从 Day 1 让病无处可长。"
回顾整个专栏,我们可以画出一条完整的进化路径:
Day 1 → 病案登记(第 1-5 篇:单点疾病)
Day 30 → 遗留急救(第 6 篇:症状缓解)
Day 60 → 静态度量 + 覆盖真相(第 7-8 篇:影像检验)
Day 70 → 债务量化(第 9 篇:财务核算)
Day 78 → 重构 + 测试保命(第 10-11 篇:外科手术)
Day 85 → CR 文化(第 12 篇:康复训练)
Day 116 → 新系统免疫力(第 13 篇:预防医学)
**从"救火队员"到"公共卫生系统"——**这就是一个团队的品质工程成熟度。
# 10.4 速查一图
三张卡片,为新系统而生:
卡片 1:新系统 Day 1 必做四件事(住院医)
1. 分层骨架:Adapter/Application/Domain/Infrastructure 四目录
2. CI 门禁:build/test/coverage/sonar/pit/pr-size 六项
3. 三模板:PR / Issue / ADR
4. 观测闭环:结构化日志 + traceId + 至少 1 个 metric
卡片 2:免疫力五层护栏(架构师)
Layer 5 组织:招聘 · 培训 · 品质预算 · SLO
Layer 4 运行:观测 · 混沌工程 · 灰度 · 回滚
Layer 3 交付:CI 门禁 · 契约测试 · Preview
Layer 2 代码:分层架构 · 防腐层 · 契约
Layer 1 决策:ADR · MVP 定义 · 品质预算
卡片 3:API 契约五条硬规则(主治)
1. 向后兼容优先(只加字段,删字段走 6 月弃用)
2. 显式版本(/v1 /v2)
3. Idempotency-Key(幂等)
4. 错误码规范(code/message/traceId)
5. OpenAPI + Pact 契约测试
# 10.5 全文快速回顾
- 第 1 章:新项目也难逃生病 · 前 5 天就出现坏味道
- 第 2 章:六大早发病 + A11-A15 病案
- 第 3 章:从 0 开始为何依然会烂 · 免疫缺失三大症状
- 第 4 章:五层护栏 + 分层 + 契约
- 第 5-7 章:三视角护栏建设
- 第 8 章:30 天健康度对照
- 第 9 章:A11-A15 归档 + 全专栏连接
# 10.6 核心要点串联
- 免疫从 Day 1 开始:越早越省
- 护栏分层建设:代码 / 架构 / 契约 / 流程 / 文化
- 契约先行:接口决定模块边界
- 度量托底:健康度必须可量化
- 文化承接:坏习惯不能带进新项目
# 10.7 常见误区汇总
- ❌ 新项目'先跑起来再补测试'
- ❌ 分层混乱,跨层直连
- ❌ 接口先实现再补契约
- ❌ 没有 CI 门禁就上生产
- ❌ 老团队坏习惯直接带进新项目
# 10.8 带走清单总表
- [ ] Day 1 定义分层与依赖方向
- [ ] Day 5 CI + 门禁就位
- [ ] Day 30 出健康度报告
- [ ] A11-A15 表进 CR 模板
- [ ] 团队坏习惯清单不带入新项目
下集提要:
- 30 天后,NextDaySvc 的免疫力得到验证。
- 12 篇专栏、62 个病案、5 位主角、90 天诊疗记录——是时候合上医生手册。
- 第 14 篇《医生手册总结》——完结篇:把 13 篇内容抽成 3 张地图、7 个仪表盘、20 条铁律,让读者带走一本可以随时翻查的"代码医生手册"。
"下一次," 老陈合上笔记本,**"我们把整本手册压缩到一张纸上——**让每一位读到这里的工程师,从明天早会就能开始用。"