软件项目开发全流程 · 第 29 课 · 维护的四种类型
1、上线之后,故事才过了一半
一个软件的生命周期里,开发只占一小部分,维护才是大部分。业界的经验数据是:维护成本可能占到总成本的 60%~80%。
但"维护"常被误解为"修 bug"。其实它是一个更广的概念。本课讲清维护的四种类型,以及那条著名的维护成本"微笑曲线"。
2、维护的四种类型
软件维护(Software Maintenance)标准分为四类:
| 类型 | 目的 | 触发 | 占比(经验值) |
|---|---|---|---|
| 纠错性维护 | 修 bug | 用户报告/监控发现 | ~20% |
| 适应性维护 | 适应环境变化 | 依赖/OS/浏览器/法规变了 | ~25% |
| 完善性维护 | 满足新需求/改进 | 用户提需求、要更好用 | ~50% |
| 预防性维护 | 防患于未然 | 重构、还技术债、升级 | ~5% |
逐一看:
① 纠错性维护(Corrective):修真实的功能错误。
"批量导入 1000 条时第 501 条报错。"
② 适应性维护(Adaptive):代码没坏,是外部环境变了。
"Chrome 升级后,我们的旧 API 被废弃了。"
"依赖库libx停止维护,必须迁移。"
"新法规要求,日志不能存 IP 地址。"
③ 完善性维护(Perfective):为了更好而改。
"加个导出 Excel 的功能。"
"把列表页加载优化到 1 秒内。"
"支持深色模式。"
④ 预防性维护(Preventive):现在没坏,但未来可能坏,提前处理。
"把这个上帝函数拆开,降低后续改动风险。"
"给核心模块补上缺失的单元测试。"
"升级到仍在维护的依赖版本。"提醒:完善性和预防性维护最容易在排期里被挤掉("没坏干嘛动它"),但它们恰恰决定系统的寿命和长期效率。
3、维护成本为什么会"爆炸"
经验定律:系统的维护成本,随时间和改动次数上升,而不是下降。
原因:
- 理解成本:新人对老代码越来越陌生,读代码的时间远超写代码。
- 耦合累积:改 A 影响 B,改 B 影响 C,牵一发动全身。
- 文档缺失:没人知道"当初为什么这么写"。
- 环境漂移:依赖、系统、配置越来越复杂。
"破窗效应":一处烂代码没人整理,很快整个模块都会变烂——因为大家都觉得"反正已经乱了"。
4、维护成本的"微笑曲线"
有个有意思的规律(Smile Curve of Maintenance):
维护成本
▲
│ 高 ┐ ┌ 高
│ │ ╲ ╱
│ │ ╲ ╱
│ 低 │ ╲________________╱
│ │ 持续改进/重构期
└────┴──────────────────────────────▶ 时间/迭代
上线后初期 中期 长期读法:
- 初期(左高):刚上线,bug 多、需求变更频繁,维护成本高。
- 中期(谷底):如果持续重构与偿还技术债,系统进入相对稳定、低成本运行的"甜蜜区"。
- 长期(右高):如果不做预防性维护,系统老化,任何改动都变得昂贵——成本重新飙升。
结论:左高是必然,右高是选择。 中间那道"下沉"靠的是持续的预防性维护(第 30 课的技术债管理)。
5、老代码 ≠ 烂代码
一个重要的心态:
老代码不是"无能前辈的垃圾",而是"当时约束下的最优解"。
你不了解的怪写法,背后可能是某个你不知情的兼容需求。
对待遗留系统(Legacy System):
- 先理解,再评判:读历史、问当事人、看提交记录。
- "海鸥式重构"是灾难:飞过来、胡乱改一通、留下烂摊子飞走。
- 小步渐进:用绞杀者模式(Strangler Fig)——新功能用新写法,旧部分逐步替换,而非"推倒重写"。
绞杀者模式:
旧系统 ◀── 逐步把功能"迁移"到新系统
┌───────────────┐ ┌───────────────┐
│ 旧模块 A │ → │ 新模块 A │
│ 旧模块 B │ → │ (新旧并存,逐步切换)│
│ 旧模块 C │ │ 旧模块 C │
└───────────────┘ └───────────────┘"推倒重写"为什么危险? 因为你会丢掉所有被验证过的边界处理和隐藏知识,然后重新踩一遍所有的坑(见下一课技术债)。
6、维护的可维护性:代码写给人看
可维护性(Maintainability) 的核心是:让别人(和未来的自己)能低成本地理解和修改。
提升可维护性的做法(第 16 课已部分涉及):
- 清晰的命名与结构、必要的注释(解释"为什么",不是"是什么")。
- 自动化测试网:改动有安全感。
- 文档:README、架构图、决策记录(ADR)。
- 依赖持续更新,别攒着。
- 统一规范:Lint/格式化自动化。
7、常见误区
| 误区 | 问题 | 正解 |
|---|---|---|
| 维护=修 bug | 忽视适应/完善/预防性 | 四类都要规划 |
| 只做救火式维护 | 永远在灭火,系统越来越烂 | 留出预防性维护的时间 |
| "没坏就别动" | 技术债累积、老化加速 | 定期重构与升级 |
| 推倒重写 | 丢隐藏知识、重踩旧坑 | 绞杀者模式,渐进替换 |
| 歧视老代码 | 破坏团队信任 | 理解历史语境 |
| 不留文档 | 维护成本暴涨 | 文档与代码同步维护 |
8、动手实验 🎯
任务:为贯穿项目「团队任务清单」做一份维护计划。
- 盘点现状:列出你项目里四类维护各有哪些待办。
分类实践:各做一件事——
- 纠错:修一个你之前发现的 bug(配回归测试);
- 适应:升级一个过时的依赖并跑通测试;
- 完善:加一个小而实用的功能(如按标题搜索);
- 预防:给一个核心函数补单元测试,并做一次小重构。
- 画微笑曲线:为你项目估计当前处在曲线的哪个位置,画出你期望的走向,标注"靠什么维持在下沉区"。
- 试绞杀者模式:选一个模块,用新写法实现一个新入口,旧入口保留,逐步切换。
- 反思:你见过的"推倒重写"项目,成功了吗?为什么?
下一课:技术债与重构。
9、今天你带走的三句话
- 维护有四类:纠错 / 适应 / 完善 / 预防——别只做救火那一类。
- 维护成本有"微笑曲线":右高不是必然,靠持续的预防性维护压住。
- 对待遗留系统:理解为先,小步渐进(绞杀者),别推倒重写。
下一课:技术债与重构。