Skip to content

Commit

Permalink
Software estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
oushu1huangweiyang1 committed Aug 5, 2024
1 parent 9e97613 commit d9126b8
Showing 1 changed file with 32 additions and 33 deletions.
65 changes: 32 additions & 33 deletions _posts/2024-07-09-software-estimation.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,70 +49,69 @@ toc_icon: "cog"
>
> **大数定律**:样本数量越多,则其[算术平均值](https://zh.wikipedia.org/wiki/%E7%AE%97%E6%9C%AF%E5%B9%B3%E5%9D%87%E5%80%BC "算术平均值")就有越高的概率接近[期望](https://zh.wikipedia.org/wiki/%E6%9C%9F%E6%9C%9B%E5%80%BC "期望")
在许多人看来,估算只是一个单点的数值,但更科学的理解应该是将其视为一个区间,也就是 \[最乐观估计,最悲观估计\]。最乐观估计假设天上掉馅饼,一切都顺利。最悲观估计假设天上下刀子,凡事都倒霉(想象一下你写的每行代码都有 bug)。
![image.png](https://note-1253446680.cos.ap-beijing.myqcloud.com/202407091603642.png){: .align-center .width-half}

直觉上,人们往往认为进度(完成时间)在这个区间内的概率大约呈正态分布。如上图所示,中点附近是概率最高的最可能的估计,两头是概率很低的最乐观估计和最悲观估计。

准确估算的困难有其客观性和主观性。
![image.png](https://note-1253446680.cos.ap-beijing.myqcloud.com/202407082056288.png){: .align-center .width-half}
然而《软件估算的艺术》中给出了一个更合理的曲线。如上图所示,这是一个偏态分布(skewed distribution)。理由是最乐观的情况是有限制的,而最悲观的情况是无限制的(例如项目过程中地球爆炸了,永远完不成了)。
客观上,估算值应该是一个概率分布的区间。如上图所示,实际项目完成时间在这个区间内的概率呈偏态分布(skewed distribution)——因为最乐观的情况是有限制的,而最悲观的情况是无限制的(例如项目过程中发生极端事件,导致永远无法完成)。

然而,在实际工作中,我们常常被要求提供一个单点估算值(设定 deadline)。这种以点表示区间的方法实际上是一种以偏概全,和赌博没有什么区别。又有谁能在赌博中战无不胜呢?无论是高进(周润发)、小刀(刘德华)还是阿星(周星驰),都不行!更何况你我。

如果可以的话,程序员最好以区间的形式告诉别人估算时间,包括最可能的时间,以及大约一个 σ 标准差(50% 把握)的较乐观和较悲观时间。然而,真实的困难在于程序员常常被要求提供一个保证完成的单点估算值。但从概率分布曲线上可以看到,任何一个单点的估算值都不能 100% 保证完成。这是客观存在的困难
因此,如果有可能,最好先以区间(\[最乐观,最悲观\]) 的形式提供估算值,随着项目的进展,事情逐步明了,再逐步缩小区间范围

除此之外,估算值还会受到主观人为因素的一些干扰。程序员在估算时可能会采取一些错误的估算方法:
估算除了存在这些客观上的困难,还会一些主观人为因素的干扰。程序员在估算时可能会采取一些错误的估算方法:
1. 即兴估算。会议上,领导拍脑袋安排任务,程序员也拍脑袋给出估算时间,拍胸脯说保证搞定。会后仔细分析,拍大腿暗道坏了,根本搞不定,最后只能拍屁股走人了 :)
2. 锚定估算。一个可能需要几个月时间的项目,领导故意问你两周能不能搞定。受锚定效应影响,程序员只敢给出三周 —— 比两周多一周的时间。
3. 乐观估算。程序员给出了最乐观估计,然而概率分布曲线告诉我们,这几乎是不可能的。
4. 逞强估算。为了表现自己,故意压低估算时间。很多刚毕业的年轻人喜欢这么干,我曾经也是如此,因此付出了很多惨痛的的代价。
5. 压力估算。领导说客户必须在某个时间点要。程序员无奈,只好修改估算值。
上述 1 ~ 4 属于估算方法不正确,5 属于没有坚持估算值。
2. 锚定估算。领导故意问能否在两周内完成需要几个月时间的项目,程序员受锚定效应影响,可能只敢给出三周 —— 比锚定的两周多一周。
3. 逞强估算。为了表现自己,故意压低估算时间。很多刚毕业的年轻人喜欢这么干,结果往往付出惨痛代价。
4. 压力估算。领导说客户必须在某个时间点要,程序员只能无奈修改估算值。

解决这些问题的办法是针对性的。我们只需做到两点:一是使用正确的估算方法,二是坚持第一点,一百年不动摇。
解决这些问题的办法是:一是使用正确的估算方法,二是坚持第一点,一百年不动摇。

首先说一下正确的估算方法。我认为,正确的估算方法包含两步,第一步是估算基本工作量,第二步是乘以一个风险系数,最终算出一个相对准确的估算值(其实大多数人应该也是这么认为的),再将这个估算值告诉领导和客户
我认为,正确的估算方法包含两步:第一步是估算工作量(通常以人日描述),第二步是将人日转化为自然日

估算基本工作量,一种常用的方法是拆解估算法:大任务拆解成小任务,先估算小任务的工作量,然后累加得出大任务的工作量。这相对于直接估算大任务总体的工作量会更准确一点,直接估算大任务偏差会很大,而估算小任务虽然也会有高有低,但当估算的小任务数量足够大时,估算会更加贴近期望值,这体现了大数定律
常用的估算方法是拆解估算法:将大任务拆解成小任务,先估算小任务的工作量,然后累加得出大任务的工作量。拆解的粒度要细,尽量细化到每个人日

在任务拆解上,我的经验是拆解的粒度一定要细,尽量细化到每个人日。这不仅会增加小任务的数量使得大数定律更有效,同时也有助于自己清晰项目的细节以避免意外的风险
拆解估算法相对于直接估算大任务总体的工作量会更准确一点。直接估算大任务偏差会很大,而估算小任务虽然也会有高有低,但当估算的小任务数量足够大时,估算会更加贴近期望值,这体现了大数定律

另一种估算方法来自《人月神话》。作者提供了一个估算基本工作量的经验法则
为了增强对估算结果的信心,我们也可以用其他思路交叉验证,例如《人月神话》中的经验法则
- 1/3 计划
- 1/6 编码
- 1/4 构件测试和早期系统测试
- 1/4 系统测试,所有的构件已完成
在我看来,考虑到实际情况,往往估算时计划已经完成,那么编码时间可以视做基本工作量的 1/4(而不是 1/6,剩余两部分同理)。也就是说,我们先估算下编码时间,然后乘以 4 得到总的工作量。

以上是第一步 —— 估计基本工作量,接下来第二步是给出一个合理的风险系数。
我们可以估算出最乐观和最悲观情况下的工作量,作为估算的结果区间。如果进一步需要提供一个单点估算值,我们不能直接使用区间中点。因为很多时候,最差情况比所谓的预期情况差很多。使用中点会导致不必要的高估。

一个著名的方法是 PERT 估算法(Program Evaluation and Review Technique,计划评审技术)。PERT 估算法除了需要估算最乐观和最悲观的时间,还要估算最可能的时间。然后运用估算公式:
> 公式 1: 估算时间 = (最乐观 + ( 4 * 最可能) + 最悲观 ) / 6
举个例子说明一下:假设一个项目最乐观需要 5 天,最可能需要 8 天,最悲观需要 15 天,那么单点估算时间 = (5 + 4 × 8 + 15) / 6 ≈ 9 天。

一种方式是按实际的工程日来给,比如假设一个工程日等于两个自然日。公式为:
> 公式 0:估算时间 = 工作量 * 2
然而考虑到最可能估算往往也是偏乐观的,那么就可以给最悲观估算增加些权重。改进版本的公式如下:

这个假设基于一周内去除开会,code review,团建,休假等等因素,平均只有 2.5 天的实际工作时间。当然,系数 2 是因人而异的,视情况调整。
> 公式 2: 估算时间 = (最乐观 + ( 3 * 最可能) + (2 * 最悲观) ) / 6
另一种方式是 PERT 估算法。公式为:
> 公式 1: 估算时间 = \[最乐观估计 + ( 4 * 最可能估计) + 最悲观估计 \] / 6
使用改进版公式,单点估算时间 = (5 + 3 × 8 + 2 × 15) / 6 ≈ 11.5 天,看起来更可靠。

第一步估出来的工作量可以视为最可能估计(当然你可以把它当做最乐观估计),然后再给出 1 个 σ 标准差的最乐观估计和最悲观估计,最后用公式计算得到估算时间。
完成第一步工作量估算后,第二步是将人日转化为自然日。转换公式如下:
> 公式 3:估算时间 = 工作量人日 * 自然日转换系数
考虑到最可能估计往往也是偏乐观的,那么就可以给最悲观估计增加点权重。优化版本的 PERT 估算法如下:
自然日转换系数可根据实际工作情况确定,例如每周实际工作时间(除去开会,其他人的 code review,休假等无关事项)为 2.5 天,那么自然日转换系数就是 2。假设第一步单点估算的工作量是 10 人日,那么最终需要的自然日就是 20 天(当然,这不包括周六日)。

> 公式 2: 估算时间 = \[最乐观估计 + ( 3 * 最可能估计) + (2 * 最悲观估计) \] / 6
以上就是我总结的一些估算方法。很明显,这些方法不是银弹(当然也不存在银弹),但相比前面提到的一些错误估算方法,这些方法的可靠性更高,值得一试。

掌握正确的估算方法后,我们还需要做好第二点,坚持它一百年不动摇
在掌握了这些估算方法后,我们还需要做好所谓的第二点 —— 坚持它们一百年不动摇

换句话说,原则上,估算结果不容谈判。话虽如此,很多时候领导和客户很可能不认可我们的估算结果,并会对我们施压。这时我们一定要坚持原则,不能妥协,也不能争吵。我们需要带上同理心和逻辑与领导沟通(同理心和逻辑是我认为的沟通能力最重要的两个工具)。
换句话说,估算结果不容谈判。话虽如此,很多时候领导和客户很可能不认可我们的估算结果,并会对我们施压。这时我们一定要坚持原则,不能妥协,也不能争吵。我们需要带上同理心和逻辑与领导沟通(同理心和逻辑是我认为的沟通能力最重要的两个工具)。

从同理心的角度,可以先思考领导和客户的需求是什么。通常来说,领导和客户需求是希望客户在某个时间点能够用上一些产品功能。从逻辑的角度,我们和领导以及客户的目标是一致的,绝对存在共赢的可能性。我们需要找到一些变通的方法实现目标。寻求变通方法可以利用另一个工具 —— 产品-进度-成本三角。
从同理心的角度,可以先思考领导和客户的需求是什么。通常来说,领导和客户需求是希望客户在某个时间点能用上一些产品功能。从逻辑的角度,我们和领导以及客户的目标是一致的,绝对存在共赢的可能性。我们需要找到一些变通的办法实现目标。这时可以拿出另一个工具 —— 产品-进度-成本三角。
![image.png](https://note-1253446680.cos.ap-beijing.myqcloud.com/202407101154350.png){: .align-center .width-half}

产品-进度-成本三角的含义是,如果想要提升进度,一种办法是牺牲产品(的功能或质量)—— 缩小功能 scope 或者允许一些非关键 bug,另一种办法是增加成本 —— 例如在项目早期增加人手。这两个办法都是空间换时间思想的一种体现。

当把这两个办法摆给领导和客户的时候,我相信一定能取得一些理解,最终共同讨论出可行的办法。如果不被理解,那么要么你得再锻炼下沟通能力(提升我提到的同理心和逻辑),要么考虑下请领导吃炒鱿鱼,把天赋带到下一家值得的公司 :)
当把这两个办法摆给领导和客户的时候,我相信能取得他们的一些理解,最终共同讨论出可行的办法。如果不被理解,那么要么你得再锻炼下沟通能力(提升同理心和逻辑),要么考虑下请领导吃炒鱿鱼,把天赋带到下一家值得的公司 :)

无论什么情况,请始终记住,使用正确的估算方法并坚持它。一旦妥协,必定会在成效和信任上受到损失。毫无疑问,这是更为惨痛的代价。

## 总结
本文探讨了准确估算的价值,分析了低估和高估的危害以及准确估算的困难,并提出了一些解决方法。尽管这些方法并不是银弹(也不存在银弹),但在估算准确性的提升方面绝对是有效的。希望对我的读者有所帮助
本文探讨了准确估算的价值,分析了低估和高估的危害以及准确估算的困难,并提出了一些解决方法。尽管这些方法并不是银弹,但能够提升估算的准确性。希望能对读者有所帮助

## 参考
1. 《软件估算的艺术》
Expand Down

0 comments on commit d9126b8

Please sign in to comment.