改造这笔账:工期怎么估、什么时候停手
改造项目的估算,毛病通常不是"估少了",而是估出来的数字无法被校准。
按模块估的工期——订单三个月、库存两个月——在开工之后就没有任何信息能告诉你它是否还成立。做到第三周,进度只能靠"感觉过半了"。等到能说出准确判断的那天,通常是超期那天。
我的做法是把估算单位换成批次,并且每批算四项成本。
按批次估,四项成本缺一不可
| 成本项 | 内容 | 常见漏法 |
|---|---|---|
| 取证成本 | 建起新旧比对的能力:黄金样本、双跑比对、给每条差异找原因 | 当成"已经有了",实际上要从零建 |
| 改造成本 | 真正写代码、迁数据、改配置 | 只有这一项被算进去 |
| 并行维护成本 | 新旧两套同时存活期间,需求做两遍、bug 修两遍 | 完全不算,或算进"改造成本"里 |
| 退役成本 | 旧实现下线、依赖迁移、监控与备份调整 | 项目计划里没有"删掉它"这个任务 |
最后一项被漏得最彻底。 大量改造项目的计划表结束于"切流 100%",于是旧系统以"已经没流量但不敢删"的状态长期存活,其维护成本按年计,而它从没进过预算。
估时要给区间,但给倍数不给百分比:基准 1,乐观 0.7,悲观 2,长尾情形 3。百分比区间(±15%)传达的是一种并不存在的精度;倍数区间直接承认了右偏——改造的失败方式是"少数批次吃掉全部余量",不是"每批都多两天"。
不确定性来源要按影响排序,而代码量几乎总是最小的那一项:
未知依赖 > 没写在文档上的约定 > 数据里的意外 > 代码量与语言版本。
绝大多数离谱的估算,都把主因排在了最后一项上("这个模块才八千行,很快")。八千行确实快,快的部分是打字,不是判断它有没有人在直连。
评审桌上两个别引用的数字
「平均每万行改造要 X 人日」——这种东西不存在。 我这次专门找过可引用的迁移生产率基准,公开一手来源查不到。能找到的邻近物都不覆盖改造:COCOMO II 与 ISBSG 面向新建类项目的估算模型与行业基线,不是"把一个正在跑的系统改成另一个样子"。所以方案里一旦有人给出"人日/千行"的单价,那是自己编出来的数,应该要求换成按批次算。
「遗留改造失败率 70%」——它的统计对象不是遗留改造。 这句话出自 Standish Group 的 CHAOS 报告,而那份报告统计的是全部 IT 项目,按预算、进度、范围三个维度划成成功 / 受挑战 / 失败三档;早期被广泛引用的约 70% 实际是"受挑战 + 失败"之和。它没有单独测过"遗留系统改造"这个类别。 把一份统计结果原封不动搬到另一个不相干的问题上,是我在《一个数字查不到源头时,说明什么》那篇里说的第三种错法。(另外那份报告的公开页面如今访问不稳定,这本身就该被当成慎引的信号。)
那拿什么说服评审?用你这台系统自己的三个可测数字:回滚演练的计时结果、双跑差异率有没有在稳定往下走、已经拿到可比对证据的批次占几成。 这三个都能当场核对,也不需要引用任何行业统计。
双维护成本要单独算出来给业务方看
并行期真正的代价是吞吐下降,而它有个可算的形状:
并行期额外成本 ≈ 并行时长 × 单位时间需求数 × 每需求重复实现系数
系数不是 2。只读改造接近 1.2,涉及数据写入的接近 1.8~2(同一个需求要在新旧两套实现各做一遍,还得各自回归一遍)。关键是这个系数必须由本团队的历史数据回归出来,不能用我给的数——我给这个区间的目的是让"这项必须算"这件事不被跳过。
业务方感到"变慢"通常滞后于并行期开始,且他们把原因归到"你们在搞重构"。这个说法一旦形成,项目就进入被动。所以提前谈三件事:
- 冻结低价值需求。 并行期不是全冻结,是按价值排序冻结。让业务方自己排,比技术侧拒绝有效。
- 业务侧参与验收。 让提需求的人看到证据链,"变慢"就会变成"我们在换东西"。
- 把并行期写进交付承诺。 明确告诉对方"这段时间这条线的需求吞吐会降 X 成,改造结束后恢复"。预告过的代价是共识,没预告的代价是失信。
停手的条件必须在立项时写下
立项时没人愿意谈"什么情况下中止",但这是最有价值的一栏。三个条件我认为必须有:
| 停手条件 | 为什么是它 |
|---|---|
| 同一批次连续两次比不出一致结果,且说不出原因 | 说明问题不在实现,在理解。理解错了继续投只会把差异越拉越大 |
| 回滚演练计时超过承诺值,或需另一个团队配合才能退 | 单向门项目不能并行推进多个批次,必须先补退路 |
| 范围外「没写在文档上的约定」条数超过事先约定的数 | 边界判断错了,实际范围比立项时大,要重开范围而不是加班 |
机制上有一个细节:停手评估要挂在固定节奏上(每批结束一次),不能挂在线上出事故时。 出事故时人的判断被沉没成本和恐慌双向拉扯,做出的通常是"再给两周"。
风险登记册:这七条我每次都列
| 风险 | 提前信号 | 缓解 |
|---|---|---|
| 知识断层(写的人已经不在了) | 代码里出现没人能解释的分支与魔法值 | 改造前先把现有行为录下来,不依赖回忆 |
| 没写在文档上的约定 | 盘点全靠读代码,没看线上真实调用 | 见 老系统改造:先证明能改,再谈怎么改 的那五样,一类一类从真实调用里查 |
| 数据里的意外 | 老库存在约束外的值(枚举外、超长、空串当 null) | 改造前跑一次全量画像,脏数据单独处理 |
| 组织记忆 | 一句"这个字段没人用"被当成事实写进方案 | 每个"没人用"必须带上证据种类和查它的时间 |
| 上游不配合发版 | 契约变更需要对方改,但排期不在你手上 | 兼容期按"对方可能永远不发"设计 |
| 并行期疲劳 | 同一个 bug 连续两次在新旧两侧各修一遍后没人说话 | 批次间留清理窗口,别连着开下一批 |
| 验收标准走样 | "一样"在不同会议上有不同定义 | 第一周就把标准写死,并让核对的人签字 |
第二行和第三行是同一类错误的两面:我们倾向用代码现状推断数据现状,用数据现状推断依赖现状。 这三个东西的分布互不相关,必须分别测。
进度对外只说三个数字
不说"完成了 60%",说这三条:
- 当前有几批是可回退的(出事能安全停下的范围)
- 有几批已经拿到对外证据(能被别人核对完成的部分)
- 有几批正在双跑但还没有结论(这部分是还没摸清的风险)
业务方看得懂这三行,也就能回答那两个真问题:现在能不能停,和还值不值得继续投。
对上汇报的顺序也是这个:先承诺批次与证据,等批次能站稳了再给日期。 反过来(先给日期再想办法)在改造类项目上基本注定失信,因为它把不确定性最高的部分——未知依赖——用最硬的形式承诺了出去。
一句收尾
改造的账不能只算成本账。成本账问"要花多少钱",风险账问"中途停下来要付多少"。 后者的数字通常更大,而且它才是决定要不要开工、什么时候该收手的那个。
一份只有甘特图的改造方案,没有回答过第二个问题。
本文作者:Aryee 发布时间:2026-09-24 20:57
本文出处:ARYEE.cn 固定链接:https://www.aryee.cn/archives/legacy-modernization-cost-stoploss.html
转载或引用请连这一行一起带走;文中的代码与结论按当时环境成立,组件升级后请以官方文档为准。