本篇要回答的问题:软件工程充满不确定性,传统工程的 “检查清单” 完全失效,那么到底靠什么管理质量?为什么单元测试与持续构建 / 发布是在不确定性中找确定性的两大抓手?
上一讲谈了版本管理中只读思想带来的确定性。本讲继续讨论质量管理的其他方面——它横跨整个软件工程生命周期,而其底层矛盾依旧:在高度不确定性中找确定性。
软件工程为何不能照搬传统工程
| 维度 | 传统工程 | 软件工程 |
|---|---|---|
| 设计占比 | 极少 | 持续发生,贯穿始终 |
| 重复性工作 | 占绝大部分时间,确定性强 | 即便编码也依赖个体创造力,不确定性强 |
| 质量管理手段 | 检查清单(Check List)即可 | 检查清单完全无法满足 |
| 工程性质 | 一个项目 | 无数个项目,生命周期数年至数十年 |
开发期 vs 维护期
把软件(或某项功能)的生命周期分为两段:
| 阶段 | 设计属性 | 时间 / 影响 |
|---|---|---|
| 开发期 | 更强的设计属性 | 时间跨度可能不长,但影响极大,基本决定维护期成本 |
| 维护期 | 仍有设计但工作量小一个数量级以上 | 时间长 |
关键判断:软件工程是需要极强预见性的工程——开发期恰如其分多投入一分精力,维护期就有十倍甚至百倍回报。设计质量至关重要,但执行不太可复制,可复制的只是设计范式与设计思维。
抓手一:单元测试
先做好自动化测试。常规手工测试的缺点:不具可回归性、效率低(一轮跑几天到一周)、为赶工只测典型数据、覆盖率低。
自动化测试与常规测试的风格差异(三大特征):
| 特征 | 含义 |
|---|---|
| 自动化、可回归 | 核心价值:可重复运行 + 提高覆盖率 |
| 静默(Quiet) | 没发生错误就不说话 |
| 执行安全受控 | 某案例失败不影响其他案例正常运行 |
自动化测试分两层,单元测试是重中之重,因为成本最低:
| 层次 | 级别 | 成本 |
|---|---|---|
| 单元测试 | 模块级 | 实施成本低(Go 等语言工具链内建支持) |
| 集成测试 | 系统级 | 代价更高 |
单元测试成本低的两个维度:
| 维度 | 说明 |
|---|---|
| 实施成本低 | 最容易做,部分语言原生支持 |
| 缩短问题发现周期 | 基本在 “问题现场” 发现,修复成本低;若拖到集成测试才发现,定位 + 回忆当初思路 + 解决要多花几倍到几十倍时间 |
关键判断:推广单元测试的真正障碍是认知问题——不要把它看作 “多做一件额外的事”,而是规范大家做测试的方法。其实人人都在验证代码(print、可视化界面、单步跟踪),但这些 “土” 方法代价不低、不可回归、无法固化已知 Bug。核心共识是:测试代码同样是开发成果,理应与功能代码同等地位、被保留下来。
抓手二:持续构建,持续发布
鼓励更小的发布、更短的发布周期、更高的发布频率,把发布负担降到最低。这与传统工程迥异,却被证明是应对不确定性的最佳方式:
| 高频交付的好处 | 原因 |
|---|---|
| 回滚代价低、影响面小 | 交付功能越少,单个功能不达标只回滚它、放行其他,不拖累整体交付效率 |
| 过程越练越熟 | 交付频率高 → 训练频繁 → 熟练度与执行效率高;交付成为习惯后被视为开发的一部分,绩效与功能线上表现挂钩,面向客户价值而非仅面向功能开发 |
高频交付对系统化建设要求更高,日构建 / 发布平台中需嵌入质量抓手:单元测试、覆盖率(code coverage)、静态检查(lint)、代码互审(code review)、灰度发布(gray release)、A/B 测试……
总结
软件工程与传统工程在质量管理理念上迥异乃至反其道而行之:传统工程靠检查清单,软件工程靠 “自动化单元测试” 把问题前移、靠 “持续构建持续发布” 把风险拆小。根因仍是——如何在高度不确定性中找到确定性。
先把"是什么"回答清楚
| 概念 | 一句话说明 |
|---|---|
| 开发期 vs 维护期 | 开发期设计属性强、影响大,基本决定维护期成本 |
| 自动化测试三特征 | 自动可回归、静默、执行安全受控 |
| 单元测试 | 模块级、成本最低、把问题在现场就发现的首要抓手 |
| 持续构建 / 发布 | 小步快跑:发布越小越频,回滚越省、熟练度越高 |
一句话速记
软件工程管不了确定性就管 “可回归”:用单元测试把 Bug 摁死在现场,用小步高频的持续发布把回滚代价压到最低——这就是在不确定中凿确定的两把凿子。
几条值得记住的判断
- 开发期多投一分,维护期回报十倍百倍——软件工程要有极强预见性。
- 推单元测试的瓶颈是认知:测试代码 = 开发成果,必须被保留。
- 高频交付让研发面向客户价值,而非 “做完功能就完事”。
思考题
回到你的团队:推单元测试推不动,到底是工具问题还是 “测试代码不算成果” 的认知问题?你们的发布是 “攒一大批功能一起上”,还是已经做到小步高频、出问题只回滚一个功能?


