上周在公司内部做了个十五分钟的演讲,题目是实施行为驱动开发(Applying Behavior driven development)。参加会议的是各个研发中心的QA精英,算是公司内部的QA文化大交流吧。
迅雷开发
在会上我介绍了组里原有的迅雷开发模式,并且与我现在推广的BDD进行了对比。这是我第一次把迅雷模式推向大众,本以为会引起共鸣,没想到大家都板着脸,不知道是不是我讲太快,还是表情太严肃。脸色难看是一定的,头天晚上四点多才睡,PPT改了又改。躺下了,想想不对,起床再改。台下苏州的、杭州的、合肥的大家远道而来,我若是不精心准备,大家只怕连火车票都觉得冤枉了。会后听到一个姐姐说,觉得BDD不错,回去要跟老板建议使用,我颇欣慰。
会后有人问我,为什么将组里原有的模式取名为迅雷。我说有三点:1,快;2,强大;3,不持久。如果试着给迅雷开发模式下个定义,那么大概是:以快速反应为前提,短期发布为重点,提高客户满意度为最终目标,但以代码质量与技术债务为代价的开发模式。(即:先把包给客户用,不满意可以patch,大不了给你派个人,守在你边上,出了问题现场解决)
迅雷开发案例分析1:紧急需求
客户突然奇想,产生灵感。项目经理立刻开始行动,把手下开发人员叫到办公室,面授机宜。开发马上开始找资料,找工具,找第三方插件,勉强将若干东西拼凑起来后,立刻向经理展示成果,在客户、经理、开发人员三者满意后,再要求测试人员开始测试。因为跳过了需求,设计等等阶段,其可测试性、可维护性几乎为零。但测试此时也没有其他办法,只能硬着头皮上。在通过几轮测试后,确定现有的包已经满足了客户的初步需求,即公开发布。
短期内,这种紧急需求会极大地提高客户满意度。但对长期产品质量却带来不可估量的破坏。
- 思想债务:开发人员认为,粗浅的尝试与不经过缜密思考的创新是好事,是即满足客户又让老板开心的行为,只要东西勉强拼起来,工作就算完成。至于质量问题,完全由测试人员来负责。以至于,我推行BDD半年后,仍然听到人说,真怀念当年,客户一旦发现问题,就跟老板一起骂测试人员的日子。可见其影响之深远。
- 技术债务:短期内向庞大的项目中塞入的代码,在之后的发布中会成为回归测试的难点。因为没有可用性与可测试性,很可能没有办法加入自动化回归测试,很难保证在产品线上的发布质量。
迅雷开发案例分析2:常规需求
常规需求中的迅雷模式,仍以快为前提,虽然也要经过传统的瀑布流程,但为了快,省去了需求文档、设计文档,仅有一张图片或一页纸的粗略描述。我曾经硬着头皮参与走查(review)过这种所谓的文档,其内容自相矛盾、描述含糊不清,即让两个开发人员对着这份文档编码,做出的东西完全不同。而测试人员只能根据这样的文档来进行测试用例的编写。
恶果分析:
- 大量测试用例与真实软件不匹配,导致测试人员拒绝参加设计讨论,因为讨论了也没效果。
- 多模块交互时,因为文档的不明确,接口不匹配,不能集成在一起,而这些问题又只能在集成测试时才会发现,从而导致每一个发布,都要经历5~7次的回退,即开发人员发布给测试人员的包,由于缺陷(bug)太多,而被要求重新发布。在忙碌的回退、与重新发布中,开发人员拼命修复缺陷(bug),测试人员拼命手动测试,寻找缺陷(bug)。为了节约浪费,而精简掉的文档,反而造成了浪费。
- 长远来看,过于忙碌的测试周期,导致新增自动化测试的滞后,代码重构的滞后,从而导致技术债务的累计。
行为驱动开发的解决之道
说完了迅雷,自然要介绍新方法,行为驱动开发的好处。
- BDD中,开发与测试共同书写行为说明(behavior spec),即模块的工作方式为,接收输入A,反馈输出B,所以行为说明成了开发发布新包的自验证工具,只有当编码通过了验证,才能发布给测试人员。这就解决了常规需求中的沟通问题。
- BDD中,行为说明会明确地记录,如何进行结果的验证,即开发在编码时一定要留有验证的接口,这就提供了可测试性。
- BDD后,省去了开发人员的手工实验时间,只要行为说明可以执行,那么完成编码后,只需激活BDD,就可以知道本次修改是否满足预期的行为说明,而迅雷模式里,开发人员则需要手动验证。
演讲结束后,大家询问了若干关于BDD的问题。如:如果客户对需求讲解十分明确,是否应该邀请客户一起书写行为说明;如果行为说明过分复杂,是否会造成该文件难以维护;等等。大部分的问题,是对于BDD是否能够全面开展的担忧。
回答问题时,并不觉得,回到座位上,忽然想起,刚才那场面,似曾相识。三年前,我曾大力推广TDD。(BDD与TDD的关系,点我)。但组里的开发人员一致反对,老板甚至称我为,读了几本书就以为书上东西可行的,不成熟的工程师。之后,自己在家里写Unit Test,读单元测试的书籍,读Robert C. Martin(人们常说的鲍勃大叔,Uncle Bob)的Clean Code。在读鲍勃大叔的书时,知道了大叔参与的项目Fitnesse,于是去研究Fitnesse,在组里推广后,再次被开发人员反对,原因为学习成本过高。而后,通过Fitnesse,又找到了今天的Cucumber。
算起来,从TDD,到Fitnesse,花了1年,从Fitnese到Cucumber,花了3个月,从Cucumber到BDD,花了半年(在推广cucumber的初期,我不敢说这是BDD的工具,怕引起开发人员的反对,而只是把它当做自动化工具推广开来)。近2年的推广过程中,遇到了无数的质疑,忽地,我意识到,大家拒绝新东西的理由,十分相似。
敏捷精神与笨蛋
- 推广TDD时,有人给我转发了一封业界大牛的博客,论述为什么TDD不可能找到所有问题(why unit test can't cover 100% problem)
- 推广Fitnesse时,又有人举例说某某情况下,现有方法就好过fitnesse
- 推广BDD,也常有人举例说,看吧,这个case,BDD做不了。
我生来不是口齿伶俐,喜欢辩论的聪明人,所以遇到这种情况,我常败的落花流水。但直到这一刻,我忽然意识,原来大家跟我,都错了。因为讨论的点,不对。到所谓TDD,BDD,或其他任何敏捷实践,其目的是提供效率,减少浪费,而不是成为传说中的银弹(silver bullet)替大家解决软件开发中的所有问题。因此,判断一个方法是否可行的依据是:只要这个实践,这个方法,可以解决我们每天遇到的十个问题中的一个,那么它就是值得尝试的;如果更好些,能解决十个中的三个到五个,那么它就是值得推广的。提高50%的生产率的方法,我们要做,提高1%的方法,我们也要做。在敏捷的世界里,所有的实践、方法,都是一个度。用对了,用好了,我们就更快,更好,更敏捷了,哪怕只是1%的敏捷,每天的1%,一年也可以省下3天来。千万不要因为一个例子,或者一个情景的不适用,而抛弃敏捷。
在敏捷的世界里,只有一个是绝对的,那就是敏捷的信念。要不要更快,要不要更好,哪怕只是比原来快1%,比原来好0.5%。想通了这个道理,有生以来,第一次因为自己的愚笨而感到开心。聪明的人们,一直忙着找例子反对,这也就是为什么BDD这个实践,是在我这个笨蛋的手里渐渐成形的原因吧。