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、动手实验 🎯

任务:为贯穿项目「团队任务清单」做一份维护计划。

  1. 盘点现状:列出你项目里四类维护各有哪些待办。
  2. 分类实践:各做一件事——

    • 纠错:修一个你之前发现的 bug(配回归测试);
    • 适应:升级一个过时的依赖并跑通测试;
    • 完善:加一个小而实用的功能(如按标题搜索);
    • 预防:给一个核心函数补单元测试,并做一次小重构。
  3. 画微笑曲线:为你项目估计当前处在曲线的哪个位置,画出你期望的走向,标注"靠什么维持在下沉区"。
  4. 试绞杀者模式:选一个模块,用新写法实现一个新入口,旧入口保留,逐步切换。
  5. 反思:你见过的"推倒重写"项目,成功了吗?为什么?

下一课:技术债与重构。

9、今天你带走的三句话

  1. 维护有四类:纠错 / 适应 / 完善 / 预防——别只做救火那一类。
  2. 维护成本有"微笑曲线":右高不是必然,靠持续的预防性维护压住。
  3. 对待遗留系统:理解为先,小步渐进(绞杀者),别推倒重写。

下一课:技术债与重构。

标签: 软件工程, 项目管理, 开发流程

添加新评论