@Lenciel

The Importance of Deploy As Will

最近公司里面两个比较资深的开发兄弟在我座位旁边进行了一场关于「代码优化到什么程度才算好」的争论。

他们一起工作的项目是一个比较小的 python 模块(几百行的规模吧),用来在嵌入式设备对接入的手机进行一些操作。其中一个人希望把这部分代码重构到「如果需求有这样那样的改变能够承受。并且即便不是我们两个来继续这个模块,任何一个人拿到都能很容易的扩展和维护」;而另一个人则认为「这个模块的规模很小不需要那么大精力做重构,并且在需求出现的时候再开始在现有代码基础上重构比先设想可能的需求来重构有意义」。

他们争的时候都有眼神投射到小弟这边,但是我没有加入:因为其实两个人的说法都还挺有道理的,他们的分歧我感觉是因为背景不同:一个是在我大 M 出道的(慢工出细活的平台中间件公司),一个是在互联网公司出道的。

追求品质是成为优秀dev的不二法门

首先,作为一个 dev,最优秀的品质大概就是一直想要优化自己的产出(扎克伯格的致员工信里面特别强调了这个很多次)。程序员的产出可以优化的东西是很多的:大到设计、算法、接口、自动化测试和部署,小到变量名、函数名、注释等等。自觉地重构和优化可以给你在技能和思考方式上带来很大的提升。而在自己入行的早期有幸遇到一个严格要求品质的 mentor 逼着被动的追求重构和优化,并且挺过来(挺过来很重要,要有学习能力并且有胸怀),更是能在工作方式和思考方式上得到很多非常正面的影响。我大 M 在我呆过的公司里面,这方面绝对是做得最好的。

什么时候够好要看你的deploy成本

但是,就这个项目而言,我个人是比较同意后面这位弟兄的看法的。软件项目可以做的重构和优化几乎是没有止境的,如何来衡量什么时候就「够好了」,业界其实有很多标准。但是我自己最喜欢的是 Martin Fowler 在一个演讲的时候提到的例子。他说:

假设你被要求设计一个电脑控制的手枪,要求在50米内自动瞄准并击中目标。需求只有这么一个。一种做法是设计一个复杂的系统,采集并计算各种可能的变量(风速、海拔、温度等等),以这些变量为基础瞄准并最后击发。还有一种是设计一个简单的系统,可以快速的击发,并且能够统计每一击距离目标多远。然后它根据收集回来的距离数据校正并迅速击中目标。

你可能会因为上下文觉得第二种方式当然是最好的,但其实上面两种方式是没有绝对的最优的:决定性的因素在于子弹的价钱。如果一个测量风速的模块都贵得可以买一车的子弹了,那么谁更好是显而易见的。

对于软件项目而言,Martin Fowler 的例子中的目标就是你的用户,子弹的价钱就是你软件的 deploy 成本(当然,不要忘记了健全的用户反馈机制也很重要)。如果我们在造一个高可靠性的系统,比如发射火箭,显然是没法承受射出去一颗不行再来一颗的;如果我们在做一个小模块或者是小项目,那么一开始就很完美地设计并不断重构它,可能性价比确实不高。

对于 Web 开发者,理解 Martin Fowler 的例子显得特别重要。一般来说网站上线的初期(一年左右),是属于 deploy 成本比较低的时候。这时候在线的用户一般是抱着试玩的心态,对新功能的渴望远远超过对稳定性的要求,并且能够给出很多反馈意见。这个阶段迅速的 deploy 新功能,迅速的处理反馈并设计下一个新功能非常重要,而有一定时间的宕机或者回退用户并不那么在乎。所以那位互联网公司出道的兄弟有他那样的想法,也就不足为奇了。

到了用户量上去,或者重要的用户进场之后,deploy 的成本就变得很高了。这个时候如果没有一整套严格的测试和运维流程,可能系统就玩不转。

结论

对于我司而言,目前和很长一段时间内的大多数产品都处于子弹不那么贵的阶段。个人感觉目前我们的 CI 和收集处理反馈这两方面是需要加强的,只有做到了”deploy as will”,我们才有底气来以做互联网的方式来开发我们自己的产品。

而从长期来看,全面的提高项目品质,不仅需要 dev 自己有重构的自觉性,还需要我们有健全的融入到 CI 的测试以及成熟的运维团队。

The myth of productivity

在从公司辞职出来的之前,我们对创业的期望是不降低大家的生活质量。我们对自己这么说,对我们拉入伙的兄弟们也这么说。这里的生活质量当然除开收入之外,很大的一方面就是不加班。

但是实际上的情况是:五一之前整个公司度过了一个非常特别的时期:产品团队不停地根据用户的输入,修改产品需求;服务器端和客户端两个开发组都疯狂加班,彻夜不眠;测试每天没有东西可以测试。

假期我回忆了一下自己参与过的所有的软件项目,大到 IBM 的存储或者 Ericsson 的基站,小到自己做着玩的一些 prototype,有跨时区的几个团队合作的,也有每天都可以互相抛媚眼的死党一起撸的,它们有一个共同的特点:居然没有一个是能够按照预估的时间交付的。

假期我和一个老一辈无产阶级革命家聊起了这个问题:每次一个项目出现这样那样的情况,不能按时交付,我们都反思、开会、总结,希望下一个项目能吸取所有的经验,不再犯同样的错误。为什么最后的结果还是一样?

他推荐了 Daniel Kahneman 的Thinking, Fast and Slow。这是一本心理学著作,探讨了人类认知的很多方面,其中有不少观点挺值得软件开发从业人员思考的,特别是想不明白为什么我们做的 estimation 永远不准的软件从业人员。

原因一:开发软件面向的问题域在你深入之前是不完全可知的

可以通过编写软件完美解决一个问题的前提是,我们对问题域了解得「足够深入」,以至于我们可以细致而精确地告诉计算机「如何」解决一个问题。

但是矛盾的地方在于,一般我们了解到这个程度的问题,都已经有现成的软件或者是库了。需要我们进行开发的总是来自一些新需求:引入不确定性的那些新需求。

新需求引入的不确定性是多方面的:第三方接口提供者不能按时提供可靠的接口,所以你要自己做适配;选定的数据库服务器之间不能互联互通需要 VPS 提供商开通 3306 端口互访。当然,不那么具体但是绝对会遇到的不确定性一般来自客户:产品 release 了,但是他们发现自己需要的并不他们最开始描述的这个东西,他们要这里那里做一些「小改动」…

这其实也是历史上钻出来那么多 specification 文档的原因:有一些管理层希望能通过在文档阶段对需求足够细化来避免不确定性对项目的影响。但结果大家都知道了,细化的文档被整个软件行业唾弃的原因是越来越多的证据说明,如果你掌握的细节足够多,你就该直接去写软件。如果你掌握的细节不够多,那么写文档也没足够细的可能。

有趣的地方在于,无论做工程师的时候大家对估开发时间多么的不屑,一旦到了管理层,你工作的核心就是估开发时间。而且有不少前一个月还在为没有按时 delivery 睡不着的苦逼工程师,一升到管理层就无比相信自己估的开发时间了。无论项目的实际情况如何,他们都会 push 整个团队苦干蛮干,这就是另外一个问题了。

原因二:过度自信和效率神话

这次雅安地震那位预测四川多少多少年不会有大地震的专家又成了笑柄。这当然不是专家第一次或者最后一次因为错误的预测成为笑柄。Kahneman 在书里面专门花了一些篇幅写「专家」的预测为什么在大多数情况下是毫无用处的,最核心的三点在于:

  • 事实证明专家的预测常常会出错
  • 但作出预测的专家会对自己有绝对的自信
  • 即便后来发现自己的预测是错误的,专家对自己的自信不会减少

最后这一点特别有趣。即便事实证明预测是错误的,即便明白只是人类认知中必然可能出现的问题,专家仍然会对自己的预测继续充满自信。原因何在?

系统I/系统II以及我们是如何做预估的

Thinking, Fast and Slow里面 Kahneman 的解释了人类其实有两套决策系统:系统 II 负责谨慎、理性、分析性的思考;系统 I 复杂快速、基于模式、基于直觉的思考。

重要的是,在进化的过程中,一个主要变化就是系统 II 慢慢少被使用了:耗时长的系统,仅仅在极其少的必须的情况下被唤醒。但是这里有个显而易见的矛盾是,如果没有经过思考,你怎么知道应该使用系统 I 还是系统 II 呢?

这就是做预估的时候总是估不准的根本原因。做预估的时候,因为你是要在没有仔细分析(甚至一般也没用仔细分析的输入)的情况下使用系统 I 来做出判断。所以你的预估「一个任务需要花多少时间」的时候,其实多半是在根据「这个任务你有多少自信」。

所以,一般来说我们报这个任务我需要 3 天的时候,其实是因为「这个东西看起来非常简单,而且我十分清楚如何做」。如果报这个任务我需要 3 个月,则是因为「这个东西看起来很难,我也不知道怎么做,但是我相信我能搞懂是怎么做」。

避免凭直觉做预估就能得到准确预估吗?

你看到这里肯定会觉得,为了避免这些虚幻的估计,我们应该通过各种手段使用系统 II 来通过仔细地分析得到准确的数据。

Bravo!恭喜你发明了「瀑布开发流程」。基本上来说”在开始编码之前我们先编写文档”就是为了让你切换到系统 II。但是为什么使用瀑布的项目也会失败?

说白了,还是软件开发在初始阶段即使使用系统 II 也不能做出精确的判断:知道的太少,变化的太多。那么究竟该怎么办?

什么样的预测是比较有效的?

Kahneman 和其他一些专家通过研究,得出了什么时候做预测是比较保险的:

「To know whether you can trust a particular intuitive judgment, there are two questions you should ask: Is the environment in which the judgment is made sufficiently regular to enable predictions from the available evidence? The answer is yes for diagnosticians, no for stock pickers. Do the professionals have an adequate opportunity to learn the cues and the regularities?」

这里的”adequate opportunity”意味着大量的实践经验用于可控的周期内的稳定环境中,并且具备了反馈机制可以随时修正准确度。以此为根据,0-12 个小时的 task,如果这些 task 一被建立就能立刻得到执行,那么:

  • 在这么短的时间内,虽然仍然有可能会出现变化,基本环境应该是稳定的
  • 你可以很快的得到结果并且知道自己估计的准确度

在这种情况下,你是尽可能的先利用系统 I 开始工作,并且通过迅速得到的反馈来修正自己的结果,达到目标。

打破效率神话

创业团队出现过于乐观的估计除开过度自信之外,还有很重要的一个原因是因为相信效率神话。Evernote,AnyDo,OmniFocus 等等 GTD 工具和各种关于同时做 n 件事情还每件都做好的江湖传说很容易把焦头烂额的创业团队坑进去。接受你不可能做出一个准确的预估然后向客户承诺的事实,转而思考如何在规定时间内最大化的输出对客户有用的价值时,关于效率需要牢记下面的事实:

接受现实,摒弃对效率神话的膜拜,用心思考在有限的时间内如何最大化的输出对用户有价值的东西,比任何流程、方法论、工具都要重要。这一方面在团队内部倡导了一种科学并且诚实的做事方式,一方面会让你更能分清工作任务和资源的优先级。它最大的好处是让你专心地根据实际的优先级做出判断,把精力放到最关键的事情上去。

这,是对整个团队最重要的事情。