“……我们的估算技术错误地将努力与进步相混淆,隐藏了人和月份可以互换的假设。”〜Frederick P. Brooks,Jr.
软件开发估算很难,而且不可靠。这不是一个新问题;我们几十年来一直在努力估算。然而,我们仍然坚持估算——它们提供了一种(很大程度上是错误的)安全感。
问题在于我们所做工作的性质。它通常需要推理和解决问题;我们需要坐下来思考问题,直到我们能够“弄清楚”。我们的估算试图为本质上不可预测的工作带来一定程度的可预测性。
举例来说,假设你熟悉国际象棋规则。如果我把棋盘放在你面前,正在对弈,我告诉你白棋三步就可以将死——你要花多长时间才能弄清楚这三步是什么?记住,你知道规则,知道棋子如何移动,也知道棋盘现在是什么样子。换句话说,你拥有人们想象你需要的所有信息.
一、为什么估算很难正确
对于软件项目,我们必须考虑许多因素,包括技术、人员、需求和外部依赖关系。其中每个因素都存在可变性。
技术本身就很复杂——有多种编程语言、库和工具。当我们把所有这些放在一起时,经常会出现意想不到的问题。原本只需五分钟就能升级库版本的更改可能会变成两天的努力,因为新库版本与某个地方的其他库不兼容,这意味着也需要更改。反过来,这需要额外的测试。一行代码中的拼写错误可能会导致数小时的调试。
人们的工作效率也并不总是一样的——估计假设我们的能力都是一样的,而且无论我们是否疲惫、沮丧或生病,我们都会以恒定的速度工作。但在现实世界中,情况并非如此。中断是常有的,有时有人需要花一两个小时来帮助同事(这并不是坏事)。
需求可能不明确,也可能随着新信息的出现而改变(而且应该如此)。如果开发人员开始实施新需求并发现有些东西不太合理,他们需要找人来为他们澄清。但如果那个人休假了,或者当天剩余时间都在开会怎么办?“等待时间”会导致整体延迟——这意味着围绕需求的一个问题就可能使估算无效。
外部依赖关系比需求变更更难控制——如果我们进入一个依赖外部供应商的世界,我们就要遵守他们的 SLA 来解决问题。如果外部依赖关系是 API,则意味着我们引入了多个额外的故障点——我们的服务器、供应商的服务器或两者之间的任何网络组件的任何问题都会导致延迟。
估算还会让人认为工作是可以分担的——如果估计开发某个功能需要 10 天,这是否意味着两个开发人员可以在 5 天内完成?或者 10 个开发人员可以在一天内完成?事实上,增加更多开发人员来尝试加快这一进程只会增加沟通负担,这可能会使情况变得更糟。
二、为什么利益相关者需要估算
不难理解为什么我们的利益相关者想要估算。归根结底,有人会为我们所做的工作买单。他们有预算,有最后期限,有客户需要满足,还有投资回报率需要计算。如果我们能告诉他们预期结果和时间,这个过程就会变得更容易。
在其他一些行业中,任务可以定义得足够明确,以便我们能够可靠地估计它们。如果我们运行一条组装小部件的生产线,并且我们知道组装一个小部件需要 10 分钟,那么我们知道我们可以在一小时内组装六个小部件。但是,我们的小部件(与我们的软件不同)是标准化的 – 因此除非生产线关闭,否则我们不太可能偏离常态。在其他行业中行之有效的相同思维不能扩展到软件。我们构建的每个创新解决方案都涉及解决一个新的、新颖的问题。我们可以借鉴过去的经验,但我们不是在运行生产线。
三、传统的估算方法
1.小时
这是不言自明的——我们估计某项特定任务需要花费一定数量的小时才能完成。实际上,人类在这方面很差劲,我们通常会犯错。这也很危险,因为不同团队成员对小时的估计各不相同——对于拥有 10 年 Java 经验的开发人员来说,需要两小时才能完成的任务,对于一个月前才开始学习 Java 的毕业生来说,很可能不会是两小时的任务。
2.故事点
这是Scrum提出的方法。
故事点数是将任务相互比较的相对度量单位。换句话说,我们将从一个代理任务开始,例如“添加一个包含五个字段的屏幕、一个 API 端点和一个数据库表”,并为其分配一个任意值(通常基于斐波那契数列)。如果我们的代理任务分配了五个故事点数,并且我们估计下一个任务——“添加一个包含十个字段的屏幕、两个 API 端点和一个数据库表”——我们可能会认为该任务稍微复杂一些,并为其分配八个故事点数。故事点数不代表天数、小时数或任何其他特定时间的指标——它们只是比较不同任务的一种方式。
然后,我们计算团队在冲刺过程中完成的故事点数,并以此确定团队的“速度”,这是一个指标,可以指示我们在冲刺期间可以完成多少故事点。该指标基于整个团队,而不是个人。
估算故事点的过程称为“规划扑克”,它发生在包括整个开发团队的待办事项整理会议期间。很多人反对故事点,但分配故事点的过程非常有价值,因为它允许整个团队讨论和理解一项任务。我个人认为这仍然是一种比试图估算小时数更好的方法。
四、替代方法
我们利用估算来创造一种可预测性。虽然估算既困难又不可靠,但还有其他方法可以创造可预测性。
可预测性可以来自定期的交付节奏——换句话说,我们定期向生产交付一些东西(即每两周的冲刺后部署一次)。虽然我们无法可靠地预测什么会投入生产,但我们几乎可以保证每两周会部署一些东西。由于我们将故事定义为增加实际业务价值的工作单元,这意味着我们正在不断向更好的状态迈进。
虽然开发工作通常不可分割,但我们可以通过为某个问题分配更多脑力来简化它——例如结对编程或群体编程。这不是分工,而是合作解决同一问题。这可以加快开发速度,因为实际工作是解决问题而不是打字——两个人更擅长解决问题。
透明度是关键——意外的惊喜是正常的,但作为开发团队,请确保您的利益相关者了解您的进展和遇到的问题。
将任务分解成小的、精细的单元。小段代码更容易开发、更容易测试,而且由于其范围有限,更容易预测。
如果您必须提供估算,请明确说明估算的前提条件。例如,您估计需要三天时间来实现一项功能,可能假设需求不会改变、不会有任何库冲突,并且所有外部 API 始终可用。这可能不现实,但通过明确说明,您也可以帮助利益相关者了解潜在的复杂性。
总之,估算很难。将其作为指导方针和目标,但请记住,您的估算可能会出错。不要试图让您的估算 100% 正确,而要专注于理解任务,逐步交付小部分工作,频繁交付价值,并对您的利益相关者保持透明。
原创文章,作者:xiaoyang,如若转载,请注明出处:https://docs.pingcode.com/baike/4601687