本文信息来源:seangoedecke

在软件行业的核心地带,存在着一种“礼貌的谎言”。它大致是这样的:

估算软件项目需要多长时间非常困难,但并非不可能。一支技术精湛的工程团队只要投入时间和精力,就能学会掌握交付工作所需的时间,从而让其组织制定出良好的业务计划。

这当然是错误的。正如每一位经验丰富的软件工程师所知, 准确估算软件项目是不可能的 。这种礼貌的谎言与其众所周知的虚假性之间的张力,导致科技公司内部出现了许多奇怪的行为。

例如,许多工程团队使用 T 恤尺码而不是时间来评估工作量,因为对于相关的工程师来说,直接给出时间估算显得过于荒谬。当然,当这些估算结果向上提交给管理层时,这些 T 恤尺码会立即被转化为小时和天数。

或者,那些真心想要给出准确时间估算的软件工程师会采用一些荒唐的启发式方法 ,比如“将初始估算翻倍再增加 20%”。这基本上等同于放弃努力,直接说“把所有事情都估算为一个月”。

科技公司是否应该停止估算?我的指导原则之一是: 当一家科技公司在做一些看似愚蠢的事情时,他们很可能是有正当理由的 。换句话说,那些看起来不合理的做法,往往在组织中发挥着某种更基础、 难以言明的作用。那么,估算的真正目的是什么?作为一名软件工程师,你又该如何做好估算呢?

为什么估算是件不可能的任务

在深入探讨之前,我应该为我的核心假设做进一步的辩护。关于这一点,人们已经写过很多文章了,所以我将简明扼要。

我也承认,有时你确实可以准确地估算软件工作,前提是该工作已被透彻理解且范围非常小。例如,如果我知道部署一个服务 1 需要半小时,而我被要求更新一个链接中的文本,我可以准确地将工作估算为 45 分钟左右:5 分钟提交更改,10 分钟等待 CI,30 分钟进行部署。

但对于我们大多数人来说,大部分软件工作并非如此。我们在理解不透彻的系统中工作,无法预先准确预测必须做什么。大型系统中的大多数编程工作本质上是研究:识别现有技术、梳理出足够的系统架构以理解变更的影响,等等。即使是相当小的改动,在我们实际去查看之前,我们也根本不知道涉及哪些内容。

支持估算的教条认为,这些问题应该在计划过程中得到解决,以便讨论的每一项具体工作都被划分为足够小的范围,从而能够被准确估算。我对这种回答并不感冒。在我看来,这似乎是回到了软件架构那段糟糕的旧时光——当时由一名架构师预先规划好一切,而普通程序员只需机械地执行指令。现在没人这么做了,因为这行不通:必须赋予程序员做出架构决策的权力,因为他们才是真正接触代码 2 的人。即便这种方式行得通,那也只是将无法估算的部分提前到了计划会议中(而在会议上你当然无法编写或运行代码,这使得准确回答涉及的各类问题几乎变得不可能)。

简而言之:软件工程项目的主导因素并非已知工作,而是那些总是占据 90% 时间的未知工作。然而,只有已知工作才能被准确估算。因此,预先准确估算软件项目是不可能的。

估算并非源自工程师

估算并不能帮助工程团队更高效地交付工作。在我职业生涯中,许多产出最高的年份是在完全不进行估算的团队中度过的:我们要么是在做无论如何都必须完成的项目,因此并不真正需要估算;要么是在做随进展持续产出价值的项目,所以我们可以无限期地进行下去 3

从某种现实意义上来说, 估算甚至根本不是由工程师做出的 。如果工程团队对某位副总裁非常看重的项目给出了较长的估算时间,他们会被施压要求缩短时间(或者该工作会被交给另一个更“听话”的工程团队)。如果一个不受欢迎的项目——或者是为了给未来未计划的工作“留出空间”的项目——估算时间太短,团队通常会被鼓励增加时长,或者他们的经理会直接加上 30% 的缓冲时间。

这种情况的一个例外是那些在技术上不可能实现,或者确实极其困难的项目。如果一位经理始终顶住压力,不强迫团队给出“正确”的估算,这可能会向高层传递一个信号:也许这项工作终究是无法完成的。聪明的副总裁和总监会尽量避免承接技术上不可能完成的项目。

另一个例外是那些高层领导并不真正关心的部门。在一些无人问津的边缘部门,正式的估算流程往往能得到严格执行,因为没有哪位总监或副总裁想要介入并为了自己的目的去左右估算结果。这也是为什么一家科技公司的不同部门之间会存在截然不同的工程文化。你可以想象一下,当公司进行重组,这些团队被推到聚光灯下时会产生怎样的后果。

对于组织中的非工程师人员来说,估算是一种政治工具 。它们帮助经理、副总裁、总监和高管层决定哪些项目获得资金支持,哪些项目被取消。

是估算定义了工作,而不是工作决定了估算

关于估算的常规思维方式是:先确定一项提议的软件工作,然后去计算完成它需要多长时间。这完全搞反了。 实际上,团队通常会先确定估算的时间,然后再去研究在这一时间内可以完成什么样的软件工作。

假设你正在开发一个 LLM 聊天机器人,你的总监想要实现“与 PDF 对话”的功能。如果你有六个月的时间来完成这项工作,你可能会实现一个健壮的文件上传系统、一套用于对 PDF 内容进行分块和嵌入以实现语义搜索的流水线、一种将 PDF 页面提取为图像内容以捕获格式和图表的方法,等等。如果你只有一天的时间,你自然会寻找更简单的方法:例如,在客户端将 PDF 转换为文本并将其全部放入 LLM 上下文中,或者提供一个纯文本的“grep PDF”工具。

即使在每一行代码的层面,情况也是如此。当距离截止日期还有几周或几个月时,你可能会花大量时间空谈如何重构代码库,以使新功能尽可能优雅地融入其中。当你只有几个小时时,你通常会高度专注于寻找一个切实可行的方法。解决软件问题总是有许多不同的方式,因此工程师在如何完成工作方面拥有相当大的自主裁量权。

我是如何估算工作的

那么,考虑到这一切,我该如何进行估算呢?

在查看代码之前,我会尽可能多地收集政治背景信息。这个项目面临多大的压力?是一个随意的需求,还是我们必须想办法完成的任务?我的管理层期望得到什么样的估算?“CTO非常希望在一周内看到成果”与“我们正在为你的团队找点事做,而这个项目看起来挺合适”之间存在着巨大的差异。

理想情况下,我在查看代码时手中已经有了一个预估方案。我不会问自己“做这件事需要多长时间”——因为“这件事”可能有上百种不同的软件设计方案——相反,我会问自己“哪些方案可以在一周内完成?”

我花更多的时间担心未知因素,而不是已知因素 。正如我上面所说,未知的工作总是主导着软件项目。该功能需要触及的代码库中“黑暗森林”越多,我的估算就会越高——或者更具体地说,我就越需要将方案范围严格限制在已知的工作范围内。

最后, 我会带着风险评估去找我的经理,而不是给出一个具体的估算值 。我从不直说“这是一个为期四周的项目”。我会说类似这样的话:“我不认为我们能在一周内完成,因为 X、Y、Z 都必须进展顺利才行,而其中至少有一件事注定会比我们预想的要耗费更多精力。”理想情况下,我会带着一系列计划去找经理,而不仅仅是一个:

  • 我们直接处理 X、Y、Z,这可能一切顺利,但如果进展不顺,我们可能会被困在这里一个月。
  • 我们完全绕过 Y 和 Z,这会引入其他风险,但可能让我们赶上截止日期。
  • 我们从另一个更熟悉 X 和 Y 的团队引入帮助,这样我们就可以专注于 Z。

换句话说,我并不是“通过分解工作来确定需要多长时间”。我的管理层已经知道他们希望耗时多久。我的工作是找出能够匹配该估算的软件方案集。

有时这个集合是空的:无论你怎么切分,这个项目都是不可能完成的任务。在这种情况下,我的管理层需要聚在一起,想办法修改需求。但如果我总是说“这不可能”,我的经理们就会找别人来做估算。当我不得不说不可能时,我是在动用我平时通过提供务实估算所积累的信任。

针对一些反对意见

许多工程师对这种方法反感。原因之一是他们不喜欢在不确定的情况下进行估算,因此坚持要求预先解决所有未知问题。我在 《拒绝承诺的工程师》 和 《我如何向非技术领导者提供技术清晰度》 中对此写过很多文章,但简而言之,我认为这是一种懦弱的表现。如果你拒绝估算,你就是在强迫那些技术水平不如你的人替你进行估算。

有些工程师认为,他们的职责就是不断地抵制工程管理层,而帮助经理寻找技术上的折中方案则背叛了某种神圣的工程信托。我在 《软件工程师应该带点愤世嫉俗》 中写过这一点。如果你想在职业生涯中一直这样做,那也没问题,但我个人觉得,寻找与经理(他们几乎都是很友善的人)合作的方法会更有成就感。

其他工程师可能会说,他们很少感受到来自总监或副总裁要求修改估算的压力,这其实只是工程组织职能失调的迹象。也许吧!我只能代表我工作过的工程组织。但我怀疑,这些工程师其实只是想说他们在“聚光灯之外”工作,那里通常没有太多压力,团队可以采用任何他们想要的流程。这没什么不对。但我认为,这并不足以让你向那些确实感受到这种压力的工程师提供有用的建议。

总结

我认为软件工程估算普遍被误解了。

通常的观点是:经理提出某个技术项目,团队聚在一起计算构建需要多长时间,然后经理根据这些信息做出人员配置和规划决策。事实上,情况恰恰相反:经理在找团队时手里已经有了一个估算(尽管他们可能不会公开承认),然后团队必须弄清楚在那个估算范围内可能实现什么样的技术项目。

这是因为估算并非由工程团队发起,也不是为了工程团队而存在的。它们是管理者之间就计划工作进行博弈的工具。极少数情况下,当一个项目确实无法完成时,估算可以作为团队向上级传达这一事实的手段。但这需要信任。如果一个团队总是抵制估算,那么当他们真的遇到一个绝无可能的提议时,也不会有人相信他们。

当我进行估算时,我会先挖掘出经理预期的范围,然后才去查阅代码,弄清楚在那个时间内能完成什么。我从不给出一个死板的“两周”这样的数字。相反,我会提供一系列可能性,每种可能性都伴随着相应的风险,让我的经理去权衡取舍。

准确估算软件工作是不可能的。 软件项目的大部分时间都花在处理未知问题上,而根据定义,未知问题是无法提前估算的。因此,为了做好估算,你基本上必须忽略工作中所有已知的部分,转而尝试对未知问题的数量以及每个未知问题的棘手程度做出有根据的猜测。

编辑:我应该感谢读者 Karthik,他发邮件询问我关于估算的问题,从而让我意识到自己在这方面的见解比想象中要多得多。


  1. 对于那些看到这个时间感到畏缩的人,我的意思是:实际部署大约需要三分钟,而剩下的二十七分钟都在等待各项检查及格,或者等待监控指标变绿。

  2. 我在 《你无法设计自己不参与开发的软件》 中对此有更多论述。

  3. 例如,想象一下有一项任务是逐步优化某个大型 Rails API 的性能。我可以一直乐此不疲地做这类工作。