目录
1. 遇到事情,倒着想
2. 在做任何事之前,先定义完成的标准
2.1 定义完成(DoD)
2.2 让 DoD 更好地发挥作用(个人层面)
2.3 让 DoD 更好地发挥作用(团队层面)
2. 在做任何需求或任务之前,先定好验收标准
2.1 功能列表式的
2.2 用户故事(User Story)式的需求描述方式
4. 尽早提交代码去集成
4.1 每日构建
4.2 持续集成
4.3 人类对工具是有偏爱的
5. 默认所有需求都不做,直到弄清楚再做
6. 在更大的范围内寻找“终”:扩大自己工作的上下文
6.1 角色的差异
6.2 跳出盲区
7. 在动手做一件事之前,先推演一番
8. 数字化:一种衡量“终”的方式
8.1 重视测量指标,重视数字
8.2 从数字出发
以终为始,就是在做事之前,先想想结果是什么样子的。概括地说,践行“以终为始”就是在做事之前,先考虑结果,根据结果来确定要做的事。
在今天的软件开发实践中,已经有很多采用了“以终为始”原则的实践:
测试驱动开发。测试是什么?就是你这段代码的“终”,只有通过测试了,我们才有资格说代码完成了。
持续集成。我们是要交付一个可运行的软件,倒着来想,最好的做法就是让软件一直处于可运行的状态,那就是持续地做集成。
什么叫完成?以始为终的终到底是什么?什么是理解偏差,如何消除理解偏差呢?答案就是:DoD!DoD的目的就是消除大家的理解偏差
DoD 这个概念本身并不复杂,它就是告诉我们怎样算是完成了,尽量减少因为理解偏差造成的各种浪费。具体怎么做呢?就是团队在开始工作前,先制定 DoD。以前面的场景为例,团队可以规定:
特性开发完成,表示开发人员经过了需求澄清、功能设计、编写代码、单元测试,通过了测试人员的验收,确保代码处于一个可部署的状态,相关文档已经编写完毕。
开发完成,表示开发人员编写好功能代码,编写好单元测试代码,编写好集成测试代码,测试可以通过,代码通过了代码风格检查、测试覆盖率检查。
大家都是聪明人,一旦 DoD 确定好了,谁该做什么事就一目了然了。
我们不仅要知道怎么用,还要知道怎样让 DoD 更好地发挥作用
DoD 是一个清单,清单是由一个个的检查项组成的,用来检查我们的工作完成情况。DoD 的检查项,就是我们开发产品所需的一系列有价值的活动。比如:编写代码、编写测试代码、通过测试人员验收等。什么样的活动是有价值的,也许每个团队的认识是不同的。但如果你的团队认为除了功能代码,其他都没价值,也许这是个信号,说明你的团队整体上是缺乏职业素养的,在这样的团队工作,前景并不乐观。
DoD 的检查项应该是实际可检查的。你说代码写好了,代码在哪里;你说测试覆盖率达标了,怎么看到;你说你功能做好了,演示一下。
DoD 是团队成员间彼此汇报的一种机制。别把“汇报”想复杂了,最简单的汇报就是说一句“这个功能做完了”。当我们有了 DoD,做事只有两种状态,即“做完”和“没做完”。在团队协作中,我们经常会听到有人说“这个事做完了 80%”,对不起,那叫没做完,根本没有 80% 做完的说法。
在团队层面,我们也可以定义 DoD。
某个功能的 DoD,比如:这个功能特性已经开发完成,经过产品负责人的验收,处于一个可部署的状态。
一个迭代的 DoD,比如:这个迭代规划的所有功能已经完成。
一次发布的 DoD,比如:整个软件处于可发布的状态,上线计划已经明确。
DoD 的思维在工作中用途非常广泛,比如,当我们需要和其他团队合作开发一个接口时,我们都知道第一步就是要把接口定义下来。
因为信息的传递是会衰减的,你不可能把你理解的信息 100% 传递给另外一个人,而这中间,如何传递,也就是如何描述将直接决定衰减的比例。
需求描述方式有哪些?
什么是功能列表式需求描述?很多公司的软件开发模式是基于功能列表的,这个列表“规定”了程序员要做的功能,各个组从产品经理那里领来开发列表,然后“照单抓药”开始写代码。但是,通常这种功能列表只是一些简单的描述,你并不能看到全局。
缺点:这种功能列表式的需求描述方式,将一个完整的需求敲成了碎片。只有所有功能全部开发完成,对接在一起的时候,才是“破镜重圆”的时刻。每个组在安排工作的时候,都会按照自己的理解进行功能排列。
一个完整的用户故事大致包含以下几个部分:
标题,简要地说明这个用户故事的主要内容,比如:注册用户使用用户名密码登录。
概述,简要地介绍这个用户故事的主要内容,一般会用这样的格式:As a (Role), I want to (Activity), so that (Business Value)意思就是:作为一个什么角色,要做什么样的事,以便达成一种怎样的效果。其中最重要的是,告诉别人为什么要做这件事,虽然只有一句话,却往往是很多人欠缺的思考,只知做,不知为何做。
详述,详细地描述这个用户故事的完整流程,我们会把操作流程、用户界面等信息都放到这里。比如:用户使用正确用户名和密码登录,就可以登录成功;如果密码不正确,则登录页面提示用户“用户名密码不正确”。基本上,看到这个部分,程序员就可以在心中描绘出这个用户故事的样子了。
验收标准,这个部分会描述一个正常使用的流程是怎样的,以及各种异常流程系统是如何给出响应的,这是程序员常常会欠缺的思考。它会把详述中很多叙述的部分变成一个具体的测试用例。
超出范围的部分,比如:第三方登录不在范围内,这个部分主要是限定人们不要进一步发散。
用户故事的关键点:验收标准,它可以清晰地定义出需求边界。验收标准非常重要的一环是异常流程的描述。大部分程序员都擅长解决正常流程,而异常流程则是最容易忽略的,也是产生扯皮的关键环节。既然容易扯皮,我们就在一开始把它定义清楚。怎么才算做完需求呢?验收标准说了算。
采用用户故事之后,我经常在写完了主要流程之后,再去看一下验收标准,为自己的开发查缺补漏。因为我知道,那是标准,达不成就不算任务完成。
如果你的团队采用用户故事的格式进行需求描述固然好,如果不能,在功能列表中,补充验收标准也会极大程度地改善双方协作的效率。
请注意,验收标准所给出实现细节应该是业务上的,程序员在这种问题上思考才是真正意义上的浪费时间,我们的发挥空间应该是在技术实现上。
如果想将每个程序员编写的代码很好地组合在一起,我们就必须做一件事:集成。
每日构建背后的逻辑很简单:既然一段时间累积下来的改动量太过巨大,那一天的时间,累积的改动量就小多了,集成的难度也会随之降低。
既然,我们认同了只要增加集成的频率,就可以保证在每次集成时有较少的改动量,从而降低集成难度。那问题来了?究竟要在开发后多久才进行一次集成呢?是半天、两个小时、还是一个小时呢?倘若这个想法推演到极致,是否就变成了只要有代码提交,就去做集成?
没错,正是基于这样的想法,有人尝试着让开发和集成同时进行,诞生了一个关于集成的全新实践:持续集成。
持续集成一个关键的思维破局是,将原来分成两个阶段的开发与集成合二为一了,也就是一边开发一边集成。之后人们更是以持续集成为基础,进一步拓展出持续交付。
持续集成服务器的发布,将持续集成从一项小众实践逐步发展成为今天行业的“事实”标准。
每日构建的概念虽然早早就提出来了,但在那个时期,行业里真正践行每日构建的公司并不多,其根本原因就在于,每日构建最初都是一些指导原则,缺乏工具的支持。而每日构建和持续集成最根本的区别在于构建时机,而这只是持续集成服务器的一个配置选项而已。
我们必须要有自己的独立思考,多问几个为什么,尽可能减少掉到“坑”里之后再求救的次数。
回到前面的主题,我们该怎么与产品经理交流呢?答案还在这个部分的主题上,以终为始。我们是要做产品,那就需要倒着思考,这个产品会给谁用,在什么场景下怎么用呢?
我们可以借鉴精益创业的思想。精益创业到底说的是什么呢?其实很简单。我们不是要面向不确定性创造新事物吗?既然是不确定的,那你唯一能做的事情就是“试”。精益创业的方法论里,提出“开发(build)- 测量(measure)- 认知(learn)”这样一个反馈循环。就是说,当你有了一个新的想法(idea)时,就把想法开发成产品(code)投入市场,然后,收集数据(data)获取反馈,看看前面的想法是不是靠谱。
既然是试,既然是不确定这个想法的有效性,最好的办法就是以最低的成本试,达成同样一个目标,尽可能少做事。精益创业提出一个非常重要的概念,最小可行产品,也就是许多人口中的 MVP(Minimum Viable Product)。简言之,少花钱,多办事。
许多软件团队都会陷入一个非常典型的误区,不管什么需求都想做出来看看,殊不知,把软件完整地做出来是最大的浪费。
产品经理是一个新兴职业,即便在 IT 这个新兴行业来看,也算是新兴的。因为从前的 IT 行业更多的是面向确定性的问题,所以,需要更多的是分析。只有当面向不确定性工作时,产品经理才成为一个行业普遍存在的职业。所以,在当下,产品经理并不是一个有很好行业标准的职位。
只有要跳出程序员的角色看问题,工作才会变得更加高效。扩大自己工作的上下文,别把自己局限在一个“程序员”的角色上。
我们一直在强调“以终为始”。所谓“终”,其实就是我们的做事目标。虽然大家工作在一起,朝着一个共同的大目标前进,但真的到了一个具体的问题上,每个人看到的目标却不尽相同。
不同角色工作上真正的差异是上下文的不同。这是什么意思呢?加入你在项目里是个普通程序员,一个打杂的,你只能关注到一个具体的任务,而项目主力开发心目中是整个系统。虽然写的代码都一样,但你看到的是树木,人家看到的是森林,他更能从全局思考。
同样,项目负责人的工作,虽然包括在项目组内的协调,但还有一部分工作是跨项目组的,他需要考虑你们项目组与其他组的互动。所以,他工作的上下文是在各组之间,包括技术和产品等方面。
再上升一个层面,部门负责人要协调内部各个组,同时要考虑部门之间的协调。而公司负责人考虑的上下文甚至要跳脱公司内部,进入到行业层面。
技术是一把利刃,程序员相信技术可以改变世界,但并不是所有问题都要用技术解决。有这样一种说法,手里有了锤子,眼里都是钉子。花大力气去解决一个可能并不是问题的问题,常常是很多程序员的盲区。之所以称之为盲区,是因为很多人根本看不见它,而看不见的原因就在于上下文的缺失,也就是说,你只在程序员的维度看问题。
多问几个为什么,交流一下是不是可以换个做法,许多困惑可能就烟消云散了。而能想到问这样的问题,前提就是要跳出程序员角色思维,扩大自己工作的上下文。
当你对软件开发的全生命周期都有了认识之后,你看到的就不再是一个点了,而是一条线。与别人讨论问题的时候,你就会有更多的底气,与那些只在一个点上思考的人相比,你就拥有了降维攻击的能力。
上线方案示例
开发任务示例
之前的项目之所以手忙脚乱,因为那时候只想了功能实现,却从来没考虑过上线,而且问题基本上都是出在上线过程中的。你想到了上次参加一个社区活动,其中的一个大牛提到了一个说法:“最后一公里”。
列出问题解决计划
先从结果的角度入手,看看最终上线要考虑哪些因素。
推演出一个可以一步一步执行的上线方案,用前面考虑到的因素作为衡量指标。
根据推演出来的上线方案,总结要做的任务。
面讲的内容一直是看到结果,结果是重要的。然而,通向结果的路径才是更重要的。
对比我们的工作,多数情况下,即便目标清晰,路径却是模糊的。所以,不同的人有不同的处理方式。有些人是走到哪算哪,然后再看;有些人则是先推演一下路径,看看能走到什么程度。
在军事上,人们将其称为沙盘推演,或沙盘模拟。军队通过沙盘模拟军事双方的对战过程,发现战略战术上存在的问题。这一思想也被商界借鉴过来,用来培训各级管理者。这个思想并不难理解,我们可以很容易地将它运用在工作中的很多方面。比如:
在做一个产品之前,先来推演一下这个产品如何推广,通过什么途径推广给什么样的人;
在做技术改进之前,先来考虑一下上线是怎样一个过程,为可能出现的问题准备预案;
在设计一个产品特性之前,先来考虑数据由谁提供,完整的流程是什么样的。
为数不少的产品经理在设计产品时,只考虑到用户界面是怎样交互的,全然不理会数据从何而来,造成的结果是:累死累活做出来的东西,完全跑不通,因为没有数据源。
今天谈到人工智能,人们主要会谈三件事:算法、算力和数据。算法几乎是行业共有的,而算力在云计算普及的今天也不再是稀缺资源,所以,数据几乎成了兵家必争之“物”。于是,我们看到的现象是各个公司都在努力地搜集各种数据,让数据成为自己的竞争力。所以,在大方向上,数据采集是一个行业共识。
我们更习惯的讨论方式依然是靠直觉。比如:增加了这个特性可能会让用户增长,做了这个调整应该会让系统的压力变小。在一些简单的情形下,或者说大家信息对称、知识背景相差无几的情况下,这样的讨论是很容易得到认同的。而当事情复杂到一定程度时,简单地靠感觉是很难让人相信的。
如果你认同了数据本身的价值,那么再结合“以终为始”的理念,我们就应该在着手做一件事之前,先来想怎么去测量。无论是在讨论产品特性,还是功能开发,“信口雌黄”是容易的,落到数字上,人们就会多想一下,这是对彼此的约束。
基于数字进行技术决策,从数字中发现问题,让系统更稳定。从数字上看,好的系统应该是“死水一潭”。出现波动尤其是大幅度波动,又不能给出一个合理解释的话,就说明系统存在着隐患。而让系统稳定,正是我们工作的一个重要组成部分。
全文完。
关注公众号,第一时间接收最新文章。如果对你有一点点帮助,可以点喜欢点赞点收藏,还可以小额打赏作者,以鼓励作者写出更多更好的文章。