试验驱动开发——“后敏捷”之道
 

2010-04-01 作者:郑柯译 来源:infoQ Sebastien Auvray

 

测试驱动开发(TDD)和行为驱动开发(BDD)现在已经成为广泛应用的软件开发技术。然而,仅仅遵循BDD和TDD还是可能导致丧失业务机会,甚至可能对业务产生负面影响。TDD和BDD有两个无法回答的问题:如何衡量应用的使用状况?如何得到客户的反馈?

传统的用户调研方式并不一定完全具有说服力,可能要占用应用提供者和客户很多时间,而且会受到偏见影响。Nathaniel Talbott在RubyConf 2009大会中的演讲中提出了自己最初的想法:业务应该采纳TDD在开发中的方式,为客户提供反馈:

软件开发主要的问题在于正确识别要解决的问题,从而避免“造成浪费的生产机器”。为此,我们需要一种新的方式来衡量事实,而不是意见(或自大),这样一来,我们就能更好地衡量我们的应用在真正工作时的使用状况了。

TDD是为了设计并验证代码。EDD以跟踪目标的方式来检查业务是否正常工作。
EDD框架基于A/B测试,该测试起源于市场调研方法,会将基线受控样本与多种单个变量的测试样本进行对比,以判断哪两种选择会提升响应率。

Assaf Arkin是EDD框架Vanity的作者,他这样描述EDD:

EDD是基于事实的软件开发。CEO们告诉自己的小姨子、小舅子们一些公司里的故事,由此而产生的意见和看法会成为一些软件的需求来源。EDD与此类开发方式完全相反。EDD从想法开始,为了衡量这些想法,EDD会征集真实人群的反馈:你的客户、网站的访问者、使用自己开发的软件的人等等。EDD以迭代的方式寻找证据。

TDD和BDD提供的工具能够帮助我们改善代码质量,并保证我们的代码能够完成规格说明的要求,而EDD帮助我们找出要开发哪些特性,以及从何入手:它帮助我们发现将会成为规格说明的东西。

使用Vanity这个Rails插件,A/B测试可以通过以下5个步骤完成:

  1. 定义一个A/B测试:
    # experiments/price_options.rb
    ab_test "Price options" do
      description "Mirror, mirror on the wall, who's the better price of all?"
      alternatives 19, 25, 29
      metrics :signup
    end
    
  2. 为用户展示不同的选择:
    <h2>Get started for only $<%= ab_test :price_options %> a month!</h2>
  3. 使用track!方法衡量转换程度:
    class SignupController < ApplicationController
      def signup
        @account = Account.new(params[:account])
        if @account.save
          track! :signup
          redirect_to @acccount
        else
          render action: :offer
        end
      end
    end
  4. 生成报告:

  5. 观察收集的数据,衡量表单的效率:

为了了解更多EDD相关的内容,InfoQ与Assaf Arkin进行了交流:

InfoQ:你是如何产生EDD这个想法的?是在为自己的新项目apartly尝试了A/Bingo之后?还是通过Nathaniel的演讲?

Nathaniel提出了EDD,我就是咖啡喝多了。

在RubyConf几周前,Nathaniel逗留在旧金山,我们一起吃了午饭。那时,我正在为Apartly设置一系列试验。我使用A/Bingo分割测试,Google Analytics做某些度量,用其他东西做数据库查询。

设想一下,数据来自三个不同的地方,我得把它们弄到一起,生成报告。这可不容易,因为Google Analytics不知道A/B测试,而A/B测试也不知道Google Analytics。每个试验中还存在代码测试路径的问题。这时你要如何测试你的试验和衡量指标呢?

喝过咖啡后,Nathaniel把他要演讲的内容给我做了一个“电梯演讲”。听起来就像我当时正在做的,不过他已经提出了方法论,而我正在想办法东拼西凑。

然后他提到了重点部分。EDD是一个概念框架,一种通过试验思考、构建、度量和精化代码的方式。如果已经有了一个实际的框架能够完成纯体力活,这样我们仅仅写少数几行代码就能编写试验,那该多好?我听到之后,脑子里马上就有声音在不停告诉我:“官人我要~~”

从那时起,这个声音就一直在我脑中回荡,到RubyConf之前,我用不长的时间开发完成了一个框架。它必须是功能最小化、但是切实可行的EDD框架,带有足够好的文档,并在生产环境中使用一段时间。除非我相信它能在生产环境中使用,否则我不奢望别人使用这些代码。

这就是Vanity产生的故事。

InfoQ:目前主要是什么在驱动你的开发?测试?行为?试验?这个比率跟项目的成熟度有关么?

我把EDD和TDD放在一起用,而且无法想象只用一个是什么状况。

我们是一个小创业公司,有很多雄心壮志,很多想法。把这些想法转化成完美的产品和可行的市场,需要一段时间。我们早期的一些直觉可能是对的,一些可能需要调整,有些方法可能被证明不靠谱。这是创业公司的常态。成功的关键在于快速迭代,在钱花光之前发现完美的产品和市场组合。

那就得像忍者那样写代码。用最小的付出得到产出,这样就能测试当初的直觉正确与否,验证想法是否可行。

我们没有时间让代码过度工程化,以应对所有的“万一”情况。大多数情况下,6个月的时间内,我们就会在发展方向上做出改变,因为市场告诉我们这么做,而且突然间我们就得丢掉不需要的功能了。那时,你就会对自己当初没有过度开发感到庆幸。

做到精益的另一方面在于去除多余的库存。我们不能承受垃圾代码和死亡特性的拖累。我们移除特性的速度和添加的速度一样快。

看清脚下的路,这让我们能够自由试验不同的想法,因为犯错的后果没多严重。只要你没有进行大批量的前期开发,或是承诺在特性上维护多年,你就能随意尝试不同的东西。如果一种试验没有成功,扔掉它,再试试别的吧。

要想这么做,代码必须易于改变,易于调试,而且足够可靠,才能做到持续部署。我们需要好的测试套件,以保证不出问题。现在我们的代码与测试之比为1:3.4。我们有单元测试、功能测试和基础测试,它们在后台持续运行,这要感谢强大的持续集成服务器软件Autotest,它帮我们发现开发机器上的bug,还能在预发布服务器上运行,以应对部署方面的问题。

因此,这些防线防止我们把有问题的代码送出去。TDD在控制代码质量上就扮演这样的角色,并允许我们试验新想法,快速做出产品变更。但是你如何判断改变什么呢?哪些想法值得探索?

我们都从直觉开始,但仅有直觉永远不够。从纽约时报上读到创业公司的故事,看起来总是创始人们有了一个好主意,然后马上就挖到了第一桶金。这些故事让人感觉很好。可实际上,创始人们有无数的主意,其中大部分都是垃圾,有一些还算可以,只有最好的才能被人记住。成功的创业公司会倾听市场,然后追随少数几个可以胜出的想法。

我们采取迭代的方式开发,但是我们的迭代不是为了完成下一个特性或是推进特性列表的开发。迭代是为了尝试,更多地了解客户,再使用这些知识判断下一个迭代要做什么。我们的进度度量使用Eric Ries所称的“经验证的学问”。

你的客户最关心哪些特性?哪些变化能让他们更开心?哪些功能没人关注,你可以放心移除?如果同一件事情有两种方式可以完成,你会采取哪一种?

EDD可以回答这些问题。它把一个想法放到实际情况中,查看反应情况,以此测试这个想法在实践中的实际情况。EDD和TDD是互补的,没有TDD,我们无法完成准时(Just-in-time)开发、快速迭代和多种试验。没有EDD,我们也许能开发出质量极高、刀枪不入的代码,可是没有人用。EDD能帮我们找到一款杰出软件的秘密配方。
InfoQ:你认为EDD可以用在任何类型的软件开发之中么?有没有想过它是否适用于过度工程化的Java工程项目,或是类似于你之前在Intalio开发的应用?它是否仅仅适用于高访问量的网站?

人们有个印象:A/B测试讲的是渠道、转化率和登陆页面【译注1】。市场研究的相关人员已经多年使用统计方法来分析和细分市场。他们把这些实践带到Web上,让我们无法逃避阅读A/B测试和登陆页面优化。

A/B测试不仅仅是登录表单。实际上,大多数试验与登录表单或是市场活动没什么关系。

作为软件开发人员,我们的工作不仅仅是构建功能特性并确定它们能正常工作。重点在于构建有用的功能,人们会使用这些功能并从中受益。如果你是软件开发人员,你是否仅仅为了构建而构建,还是为了某个客户而构建呢?你是否愿意开发没有人会去用的代码?还是愿意开发很多人都觉得有用的代码?

我们种很多人都有兼职项目,因为这让我们对某款软件的某个部分负有完全的责任,而且对我们的每次决策要完全承担其后果。

我可以用一个问题总结我们在Apartly上的开发过程:“它能拨动指针吗?"

我们对好几个度量指标感兴趣,比如注册数(获得)、邀请数(推荐)、订阅数(收入)等等。这些都是指针。使用我们所能获得的有限资源而做的一切,都要在这些度量指标的某一个上取得成果。也许我们能得到更多的注册人数,也许是更多的回头访客,也许是Twitter上更多的击节赞叹。

不仅每个人都能看到这些指标,而且它们也已经被植入到开发过程之中。度量指标和试验是代码库的一部分,它们被签入到源代码控制系统种,并经历测试和预发布过程。

测试有限开发会让人先写一个失败的测试,然后开发必要的代码以通过测试。与之类似,我们会先从一个基线指标开始,然后编写代码让这个指标向期望的方向变化。(一般都是向上的,不过有些指标,比如每分钟的WTF个数【译注2】,一定是要向下的。)

能否把这样的方法应用到大规模流量网站之外的应用?总是有一个度量指标能够说明问题的。当你用消息队列方式替换同步交互之后,能否改善响应时间?是否降低服务器在高负载下的故障发生几率?是否更易于部署新的服务?简而言之,是否有任何可度量的效应,或是以前浪费的工作量现在看起来更好了?

如果没有任何可度量的结果,那就会导致启动很多开发工作,因为解决问题听起来很有趣,而且继续存在,因为无法证明它所导致的效率低下,同时已经成本已经沉没下去了。只要引入度量指标,有趣工作的定义就变化了。突然之间,某些工作变得有趣,因为你能看到后果。

Nathaniel提出的EDD框架需求列表的第二点就是“各个层面都能访问得到”。不能只是面向客户。我们希望在软件栈的各个层面都能度量。而且每个组件都要负责,证明它的价值。
InfoQ:很难衡量TDD和BDD的ROI,而且结果也许无法马上显现出来(当然更不可能是实时的了)。这样一来,可能很难说服管理层和决策人员利用TDD和BDD的好处。有没有可能EDD因为可以提供直接和可量化的数据,而被管理人员青睐?

悲哀的是,我不认为EDD能够让你的猪头老板(Pig Head Boss)变得更聪明、更讲道理。

IT部门,扩展到很多业务和企业软件公司,对于用户有一种偏执。当你不必听从用户的时候,有时就会树立起一种围绕着客户的文化,开支票的人或职位就是客户。客户总是对的,他们也不会容忍任何并非他们提出的变更,因此他们希望看到一个路线图,看到从0到100%的持续进度过程。这是典型的瀑布式方法。

在另一端,有这样的公司和项目,他们无法强迫人们使用自己的软件。他们必须讨好自己的用户,让用户高兴,让用户的生活在某方面变得更好。衡量成功的方式不是看在财年结束时完成了多少功能,而是赢得了多少用户。

当你以交付功能的方式度量成功时,绘制精美的甘特图就是你的指路明灯。还可能把甘特图放大,贴在办公室最大的那面墙上。如果以客户的满意度来度量成功会发生什么?让市场部门把自己的季度董事会报告在整个公司里面流传么?这在交付和反馈之间可是有三个月的延迟啊。

有些公司会在角色扮演练习中产生用户原型,并围绕着这个想象出来的用户原型设计软件。其他公司已经想办法实施充满寓意的“吃你自己的狗食”,有些公司只开发自己内部也会用到的软件。可如果你的市场不是软件开发人员怎么办?

如果你理解软件的运作方式,就能知道按代码行数衡量工作效率毫无意义。通过特性或故事点数衡量软件也好不到哪里去。二者都是在衡量和优化优先级次高的效果。工作效率没告诉你多少有用的东西。

反之,选取最重要的业务度量指标。Dave McClure给它们起了个绰号:“海盗的指标”,包括获取率、激活率、保持率、推荐率和收入。雇佣最聪明的人,包括开发团队,找出如何提升获取率,提高保持率,增加收入。

目的不是为了获得业务上的量化回报。如果量化回报必须从市场部门逐渐转向开发经理,再下放到团队主管,那就会出现带宽和延迟方面的问题。关键是要把开发人员直接放到第一线去,把度量指标植入流程之中,度量关键的业务目标。

我将其称为“后敏捷”,因为它构建于敏捷的成功基础之上,但是用“可验证的学问和关键指标”替换“可工作的软件作为进度的基础度量方式”。EDD之于“后敏捷”,就像TDD之于敏捷。

EDD会在未来几年成为标准吗?它能否提供坚实有力的成效?还是仅仅是另外一个以DD结尾的缩略词?您怎么看?

查看英文原文 Experiment Driven Development - The Post-Agile Way

译注

  1. 渠道(funnel)、转化率(conversion)和登陆页面(landing pages):这三个词都是在线网络营销的常用词汇。funnel表示网站方希望访问者为达到某个目标而使用的页面路径。详细解释可参考Google Analytics的解释。网站转化率,是指将网站访问者转化为常驻用户的比率。登陆页面landing page)是指网站访问者通过点击站外链接到达当前网站的页面,可能是主页,也可能是网站中其他页面;可参考Wikipedia页面。
  2. WTF:粗口“What the fxxk”的简称,WTFs/m的含义,可参考该页面。Bob大叔在自己的《Clean Code》一书中对此也有引用。


由外而内看敏捷软件开发
架敏捷开发中史诗故事与用户
看板任务管理
面向全球化的有效敏捷交付
小型团队快速开发方法
DevOps,不是一个传说!
更多...   


统一过程及应用
敏捷过程实践
基于XP/RUP的迭代开发
软件开发过程指南
SCRUM过程实践
敏捷测试-简单而可行


某博彩企业 产品经理与产品管理
北京 研发团队与工作管理
广东金赋信息 敏捷开发过程与项目管理
某支付平台 软件配置管理与发布管理
富士 软件外包项目管理与进度管理
塞孚耐 基于Scrum的敏捷开发
更多...   
 
 
 
 
 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号