在团队中如何带领新手

目标

通过引导、任务分配和沟通反馈等方式,让他逐步适应团队正常工作面临的压力、节奏和不确定性。对于一些心理预期过高的领导者,在此阶段应该明白,对于一个新手,还暂时谈不上能力判断和机会给予。

方式

创造良好的工作气氛:信任是第一位的。只有相互信任,才能把工作放手交给新手去做;另一方面,在他们失败的时候依然要给予信任,否则,所有的事情结束点就是“失败”。一个人所取得经验,最大的来源就是失败。良好的工作气氛,也包括各种非正式的交流与沟通,比如聚餐、聚会等等。

定期反馈:可以在每日、每周对新手的工作进行反馈,同时也让新手有一个渠道发出自己的声音。反馈应包括:做得好的地方,以及需要改进的地方。反馈中需要注意的是,虽然是新手,但已经是成年人,思维、行为模式大部分已定型;我们需要去识别对方的性格特点,合适的沟通方式,以及他们的动力来源,尽可能做到:了解他们的愿景,帮助他们做成他们想做的事,帮助他们成为他们想成为的人;切忌让他们被迫成为“我们”想要的人。

制定学习计划或任务:针对新手已有的知识体系制定短周期的学习计划,分配适当的任务给他们完成。在这个过程中,需要去检查并督促对方完成计划或任务。能够完成简单任务之后,逐步让对方感受到工作中的压力和需要随机应变的场景,给予指导,让他们逐步能独立适应工作。

障碍

带新人的过程中,往往会遇到不少的阻力,最终他们无法达到早期的期望。分几个方面来解读:

两只手表:在公司里非常影响工作的是权职受到牵制,带新人这种小事也不例外。如何新人失去了对你的信任或他更倾向于另一个人的反馈,那么你对他的指导是无法成功的,遇到这种情况,可以和另外的人,也许这个人就是你的上司,谈谈如何更好地带领这个人,或者放弃对他的培养。

沟通失败:部分虽然工作多年,但沟通经验不够丰富的人,可能无法在双方沟通中明白对方表达的真实意图,并无法识别对方性格上的偏好,导致沟通上的失败最后无法达成目标。有效的沟通,是需要双方都明白对方的意图,作为优秀的沟通者,更需要清楚地知晓在沟通之中,哪些“需求”是可以让步、放弃但又不影响全局的,这就是妥协:我们应当明确,当一方作出让步时,又需要对方相同地作出哪些方面的让步,以达到对目标的共识。在与成年人的沟通中,可能会出现多次的妥协,因为每个人有独特的背景和知识,这都导致了不同的认知和行动方式。

纠正行为模式:这种情况对双方都是痛苦的过程。并不是每个人都出生在良好的家庭,一开始就有优秀的父母指导如何做事。比如隋性、注意力分散、害怕挑战、防备心理等等。在这方面我也有不少失败的经验;所以我认为“改变”一个人几乎是不可能的,但我们可以采取一定的手段,将负面行为的影响力降低到最小。比如之前和其它人沟通如何让90后新人对自己的工作任务负责,不是在他们彻底忘记任务后批评责备,而是将他们的任务期限、状态醒目地展示在工作区域,多次提醒的结果明显大于事后究责。另外在需要一个人做出改变的,应当与他明确,他做出的改变是为了满足团队的共同目标,而非个别领导人的偏好;他做的改变是为了解决自身面临的障碍,而不是变成所谓的“完美之人”。

最后如果让我用较少的几句话来总结“带人”的经验,我会说:第一,带人时你有权力,但不可利用权力,你要明白权力“该”做的部分,而不是沉浸在“可”做的部分;第二,带人时对方会做一些你让他做的事,但不可把他当成你,甚至当成你可以去塑造的人物,他需要在这个过程中成为他的更好,你也需要在这个过程中成为你的更好,否则,你只是这事的附属品,你会费力不讨好,会委屈难受;第三,世上没有完美的人,你也不是爱因斯坦,调子放低点,会有更多人主动向你学习。

Share

从敏捷宣言理解敏捷交互设计

本文原文发表于InfoQ:http://www.infoq.com/cn/articles/xzc-agile-interaction-design

敏捷交互设计是敏捷方法论向交互设计领域的延伸,它提倡让所有相关人参与到设计过程中,迭代演进式地进行交互设计。从2010年开始,已经有越来越的团队在不同程度上使用敏捷交互设计的方法,而放弃了流程化的传统产品设计过程。

事实上,敏捷交互设计方法在很多方面都充分体现了敏捷价值观,因此,理解敏捷交互设计实践的最好方法是从记录在敏捷宣言中的价值观开始。

个体和交互胜过流程和工具

一个传统交互设计的流程一般分成以下几个步骤进行:

  1. 任务分析:任务分析基于功能列表(一般来自于客户的功能说明书)──在功能性需求的基础上拆分出人物流程和场景;
  2. 页面流程:根据任务分析的结果,为每一个大任务下的子任务中覆盖的功能制作页面流程;
  3. 信息建模:根据页面流程的设计出一套完整的信息框架,满足用户所有功能性需求;
  4. 原型设计:基于信息建模,设计出低保真原型,交给美工进行页面美化;
  5. 视觉设计:基于原型设计,对页面进行美化,最终产出高保真原型,同时编写设计说明;

在传统流程中,我们可以看到非常细致的分工──产品经理负责功能的拆解和分类,以及页面流转;交互设计师设计信息架构和具体交互行为;视觉设计师负责美化页面;前端开发人员负责高保真原型。

你是否体看见了传统瀑布式开发的影子?弊端显而易见:

  1. 分工造成的局限性──每个人都用自己的视角进行工作,无法形成统一的产品视角(Vision);
  2. 分工造成的“不可评价性”──你没权利对产品经理的功能拆解有异义,因为你不是这方面的专家;
  3. 需求在传递中产生了失真的风险──需要靠大量文档进行记录;
  4. 客户没法说不──当客户需要到整个流程的最后看到一个或者两个大而全的设计方案时,他无法提出任何有价值的反馈,这本身就是用一个贵重的半成品绑架客户;

跟软件交付中的敏捷实践一样,敏捷交互设计倡导全功能团队,避免过于明显的分工,和基于分工特有的流程。仅有的流程是基于产品逐步清晰化的过程,而非基于人员的技能,所有人都应该参与到这个过程中来。敏捷交互设计主要分以下几个步骤:

  1. 寻找产品方向(Inspire):抛开需求列表,从目标人群的期待体验出发,寻找可能存在的产品方向;
  2. 定位产品需求(Identify):定位本产品需要提供什么样的消费者体验;
  3. 设计产品体验(Ideate):对决定的目标体验进行设计;
  4. 验证产品设计(Implement):快速制作原型,并频繁进行用户测试,迭代式改进。

图1. 从体验中寻找交付范围,把功能列表放在一边

除了流程简化和分工融合,在工具的选择上,敏捷交互设计也与传统方式有所不同──对于交互的推崇高于对特定工具的选择。

所有在敏捷交互设计中使用的工具,都应该遵循一条原则:它必须推动设计团队成员间的交互,而不是简单提升单个成员的工作效率。

基于此,敏捷交互设计中推崇各种轻量级工具,而不是大型的第三方软件,例如纸质原型Paper Protityping而非Visio或Axure此类原型工具。过于精细的结果往往会增加协作和反馈的门槛,虽然可能提升单个成员工作效率,却达不到鼓励交互的目的。

图2. 使用轻量级的工具进行交互设计

可工作的软件胜过完备的文档

敏捷软件交付过程中,每个迭代的核心产出是不足够完美,但却满足一个完整业务场景的软件──端到端流程的可完成,而不需要面面俱到的完美。

而传统开发方式中在长时间内只是各个功能模块中功能的堆砌,无法在短时间内实现端到端场景,那么文档便成为串联各个功能保证有序开发的必需品。

传统交互设计也存在这个问题。往往一个标准交互设计阶段的文档分三个方面,它们是:

  1. 内容方面(Content):内容的层次和整体信息架构设计;
  2. 视觉方面(Visual):整站风格的视觉设计文档;
  3. 交互方面(Interaction):整站高保真交互设计原型;

仔细分析这些文档的生产过程,我们不难发现以下特点:

  1. 它们都是以整站为目标,试图覆盖所有使用场景;
  2. 它们的生产过程是线性的,直到三者全部完成才能够指导开发;
  3. 正因为每个环节的过程是孤立的,无法形成统一的认识,文档传递经常发生失真;
  4. 一个完美的东西很难得到产品方向性的关键反馈;

敏捷交互设计试图在解决以上问题。

敏捷交付的核心在于尽早地交付出可进行端到端测试的代码,而非完备文档,而敏捷交互设计的核心则在于尽早地交付出可以进行端到端可测试的原型,同样亦非完备文档。

而这里说的“端到端可测试的原型”包含以下含义:

  1. 端到端:必须设计出符合合理使用场景的端到端流程,这个流程会覆盖一个典型用户最核心的使用场景,所有的交互设计应该第一时间收敛在这个端到端场景周围,而非“整站”功能的分割展示;
  2. 可测试原型:不需要完美的原型,只需要所设计端到端场景中涉及到的原型,同时,原型的完备性上必须达到内容、视觉、交互三者细致力度一致,在测试中,三者力度的不一致往往会隐藏问题,例如,如果测试的原型视觉上过于完美,就会减弱用户在交互上的关注;

假设我们把交互设计的四周拆分成每周一个迭代,每周交付一个覆盖端到端场景,且在内容、视觉和交互方面都相对完备的原型收集反馈或进行测试,和传统项目相比,我们是否可以更早地得到客户反馈,是否可以让设计过程更透明,是否毋须完备的过程文档?答案自然是肯定的。

图3 逐步细化的原型,不停进行用户测试

当然,这样的过程必然需要多模块(这里的模块指技能的差别)之间的融合,实现全团队的运作。

你会问我,这是否意味着我们的交互设计师需要学会使用IIlustrtor进行视觉设计?或者视觉设计师需要学会HTML+CSS+jQuery制作高保真原型?

是的,在很多情况下,敏捷交互设计团队中的设计师确实需要具备多种功能的T型人才──他们有专业的技能,也可以在其他方面有足够的贡献。

分工的结果只能导致能力的停滞不前、产品视角的缺失、职能不可替代的风险、协作软的低效、沟通的浪费等等,而唯一的好处在于,可以更快和“更不被抱怨(如德鲁克说过程文档的价值在于管理抱怨)”产生一堆堆相互分裂且无法让客户挑错的文档。

客户协作胜过合同谈判

让我们举例说明在传统交互设计阶段出现的场景:一份标书、一份功能列表、一份到处使用的所谓用户体验调查问卷,在交互设计的开始阶段,我们和客户在一起进行“需求调研”,其实这些不重要,我们只需要对比我们之前的产品都有哪些功能可能有重复,类似产品有哪些可以借鉴,调研往往只是形式,关键还是未来的二至四周;

然后最后一次见客户也许就是最终文档提交的那天,给客户看一套精美的PSD文档,一般我们会做出A和B方案,其中不乏我们臆想出来的需求,有时只为让那个区域看起来不那么空,客户高兴地选择了其中的一套方案后,交付正式开始。

这就是基于合同进行设计的典型场景,谁也不知道合同中的功能列表意味着什么,而对于客户来说,它确实是购物单,真正交付时已忘记为什么需要。

但这不妨碍交互设计师进行设计,大部分时候他们并没有仔细思考这个功能真正的使用场景,而是把它“画”出来,让它看起来很美,却不管它如何实现和如何被用户使用。

这是基于合同进行设计自然而然的结果,在每个功能上,设计师都希望当成对自己的挑战,他们绞尽脑汁收集类似产品类似功能,尽可能取悦客户,说服他们采用更炫更丰富的交互方式,而作为不对交付负责的人他们毋须承担责任。

而敏捷交互设计希望打破这种基于合同或者换言之,基于功能列表的设计模式。它希望在设计的全过程将客户参与进来,让客户了解某个标书上的功能也许没有意义,或者不是当下应该解决的问题──一个交付项目范围的最好确定时机就是在交互设计过程中客户的全程参与。客户参与的优势有以下几点:

  1. 过程的透明化提升客户的安全感,随时保持对设计进度的了解;
  2. 最好的反馈模式就是让客户亲身参与设计过程;
  3. 了解最终用户和业务模式的是客户,客户是不可多得的资源;
  4. 当设计结果是功能列表的重新确认,对于合同中的内容便达成了新的共识;
  5. 客户参与的过程是建立信任的最佳机会,良好的信任关系应该在最开始就建立;
  6. 在产品设计方向上和客户达成一致,而不是仅靠标书或者访谈结果的支言片语;
  7. 提升参与感有助于培养更负责的客户,在交付阶段,之前的努力将会获得巨大的回报;
  8. 有效控制设计的变化,当客户亲身参与设计决定过程时,很多盲目的设计变化会减少很多;

拥抱变化胜过遵循计划

当你的设计不能和客户一起进行,你只是个标书需求列表的简单执行者,需求的变化便是理所当然的事情。

在有些传统交互设计流程里甚至出现“需求冻结”这样的流程──如果你已经对某个环节的文档进行进行签收,就不能在“需求冻结”后改变主意。这样的结果无非两个:一尽量不要签收那个环节的文档;二在需求没有冻结的时候抓紧机会改变主意。

从敏捷宣言的角度来看,之前的三句话是最后一句话的基础,如果不能做到对个体和交互的尊重,把可用软件当作产生核心价值的东西,并且努力和客户进行协作,谈拥抱变化只是空话。在敏捷交互设计中,遵循同样的道理:

对个体和交互的尊重──当需求发生变化时,因为在新的流程中对产品视角的重视,可首先对需求变化的价值进行判断,即它是不是匹配达成一致的产品视角;真正需求变化时,因为分工的模糊以及流程的简化,可更灵活地调配资源进行处理;再者因为大量使用轻量级的工具,修改成本大大降低;

关注可工作的软件──因为我们把可进行的端到端场景测试作为敏捷交互设计过程中最重要的目标,当出现需求变化时,可通过审视变化本身“是否包含在端到端场景中?如果不产生这样的变化,用户因此有何种损失”来判断需求变化本身的价值;同时,因为能够尽早的得到端到端场景原型设计,需求本身往往来自于用户测试的结果,这样的需求变化往往是有价值的,有理可依的;

客户协作的重要性──需求变化往往来自于客户的不确定性,很多情况下这种不确定又来自于一个新产品背后业务模式的不确定,客户协作帮助在设计过程中及早发现和解决这种来自业务方面的不确定,同时,客户协作对客户责任感的培养也大大减少了来自于客户不负责任的需求摆动。

这就是敏捷交互设计可以很好的管理用户需求的根本原因。

从敏捷推行到现在,在交付领域已经走向成熟,越来越多的团队开始采用敏捷方法进入开发,但从软件交付的全流程来看,早于交付的交互设计环节目前依然以传统设计方式为主。

随着消费型软件大行其道,用户对软件使用体验的要求越来越高,同时新产品的推陈出新对快速产品设计提出新的要求,这样的背景使得传统交互设计流程不得不做出一些新的调整以拥抱更加频繁的变化,这也是为什么很多交互设计团队开始努力尝试具有敏捷价值观的敏捷交互设计进行产品设计的主要原因。

最后,让我们来比较一下传统交互设计方法和敏捷交互设计方法的区别:

传统交互设计 敏捷交互设计
没有交付团队的参与;客户参与度低;设计团队中各职能分工明确; 交互设计师、用户研究者、视觉设计师、前端开发者、客户代表、以及开发团队代表都完整参与整个交互设计的过程,并只有能力区分而弱化职责分工;
客户需求文档中的功能列表是贯穿设计过程的主线; 基于终端使用者期待体验的设计过程,往往客户功能列表只作为参考;
各自有各自对产品的理解,无法达成共识; 对产品设计方向的形成共识是贯穿整个交互设计阶段;
使用大型的交互设计软件; 鼓励使用白板、海报、贴纸、手绘等轻量级的工具;
客户只在开始和结束参与项目; 客户全程参与设计活动;
主要以文档制作为主; 主要以Workshop工作坊活动为主,高互动过程;
设计师单独和封闭工作; 设计师合作式的工作,随时把工作的产出物展示,接受反馈;
设计师能力专一; 鼓励T型人才;
缺少用户测试; 在不同精细度的原型上快速进行用户测试,迭代式演进设计;
大而全的设计; 只设计足够的交互;
远离客户以避免变化; 和客户在一起鼓励变化;
不对交付负责,肆意发挥; 对交付负责,在成本接受的范围内创新;

感谢张凯峰对本文的审校。

本文原文发表于InfoQ:http://www.infoq.com/cn/articles/xzc-agile-interaction-design

Share

持续集成理论和实践的新进展

最近雷镇同学将Martin Fowler先生的著名论文《持续集成》第二版翻译成中文并发布出来,掀起了国内对于持续集成理论和实践讨论的新的高潮。笔者在本文中将全面对比持续集成论文前后两版的异同,分析并展示ThoughtWorks在持续集成领域的理论和实践方面的研究成果,以图对国内企业实施持续集成起到参考和借鉴作用。需要说明的是,本文所介绍的内容毕竟限于笔者的水平,并且主要是ThoughtWorks内部开发和对外咨询实践的总结,所以未必对读者所遇到的情况是适用的,请自行甄别。

《持续集成》第二版虽然是最近才翻译出来,但是实际上Martin Fowler先生完成此文是在5年前的事情。这五年恰好是ThoughtWorks中国公司快速成长的五年。在这五年内ThoughtWorks中国在持续集成领域也有很多的发展,这包括:著名的持续集成工具Cruise主要是由中国公司负责开发1; 中国公司帮助国内很多大中型企业完成持续集成实施和相关的流程改进;2009年中国公司的很多同事对于持续集成的度量进行了深入的讨论并且最终由胡凯将其实现为一款软件iAnalysis;2010年至2011年成功的交付了从需求提供方到多个技术服务提供商的持续集成方案,以及企业级自动化中心方案。所以,本文主要包括两部分内容,一部分是通过对比第一版与第二版的异同介绍2000年到2006年之间持续集成领域的主要发展,另一部分则是介绍第二版发表之后持续集成领域的新进展。读者如果之前没有阅读过《持续集成》论文的第二版,建议将本文第一部分一同阅读,因为本文并非对论文的重述,所以很多地方还需要参考原文中的内容。

第一部分 《持续集成》第一版与第二版

《持续集成》第一版由ThoughtWorks首席科学家Martin Fowler先生和Matthew Foemmel共同完成2,第二版由Martin Fowler先生更新。

《持续集成》的第一版中并没有给出比较正式的定义,虽然作者在文中说是借鉴了XP实践中的术语,但是目前能看到的XP实践中对持续集成的定义实际上大多数都是指向了Martin的文章。那么我们还是来看看第二版中给出的定义。

持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的验证,以尽快发现集成错误。许多团队发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。3

第二版相对于第一版增加了不少内容,其中最重要的几点包括:

  1. 详细介绍了使用持续集成进行软件开发的工作流程。
  2. 突出了配置管理在持续集成实践中的作用。
  3. 提出分阶段构建的概念。
  4. 增加了持续集成报告的内容。
  5. 增加了持续部署的内容。
  6. 给出了引入持续集成的建议。

持续集成的流程

在持续集成领域,我们经常会用到的一个术语就是“构建(Build)”。很多人认为“构建=编译+链接(Build=Compile+Link)”,Martin在第一版中指出一次成功构建包括:

  • 所有最新代码从配置管理工具中取出(check out或者update)。
  • 所有的代码从干净的状态开始编译。
  • 将编译结果链接并部署,以备执行。
  • 执行部署的应用并运行测试套。
  • 如果上述所有操作没有任何错误,没有人工干预,并通过了所有测试,我们认为这才是一次成功的构建。

实际上,目前很多团队对成功持续集成构建的定义基本上是符合上述定义的。这个定义的特点在于它是相对独立的,它是一个从干净状态的源代码最终获得可运行的通过验证的软件的过程。

Martin在第二版中则在成功构建的基础上给出了成功集成的定义。成功集成关注的不是一次“编译+链接+部署+验证”的过程,而是从开发流程的角度介绍一次完整的在持续集成约束下的代码提交过程4

  • 将已集成的源代码复制一份到本地计算机。
  • 修改产品代码和添加修改自动化测试。
  • 在自己的计算机上启动一个自动化构建。
  • 构建成功后,把别人的修改更新到我的工作拷贝中。
  • 再重新做构建。
  • 把修改提交到源码仓库。
  • 在集成计算机上并基于主线的代码再做一次构建。
  • 只有这次构建成功了,才说明改动被成功的集成了。

下图展示了Martin对成功集成的定义:

当然在第一版的“代码提交”这一节,Martin也提到了本地构建的概念,只是不如第二版这么明确。

配置管理

Martin在第一版中有两处提及配置管理,分别是:单一代码源(Single Source Point)和代码提交(Checking In)。第二版中则包括:通过持续集成构建特性(Building a Feature with Continuous Integration)、只维护一个代码仓库(Maintain a Single Source Repository)、每人每天都要向主线提交代码(Everyone Commits To The Mainline Every day)、每次提交都应在集成计算机上重新构建主线(Every Commit Should Build the Mainline on an Integration Machine)。不仅条目数量上增加明显,作者提出的很多实践都是基于配置管理来讲的。

工具

配置管理是持续集成的输入。在第一版中作者所推荐的配置管理工具是CVS,到第二版中作者推荐的配置管理工具已经换成了SVN5(参见第二部分中的配置管理工具部分)。

分支策略

实现进度与质量的平衡是配置管理的重要目的。Martin在第二版中对滥用分支给出了警告:

尽量减少分支数量。典型的情况是保持一条主线,……,每个人都从这条主线开始自己的工作。(对之前发布版本进行Bug修正或者临时性的实验都是创建分支的正当理由。)

但是这里给出的建议对于大型团队来说并不十分合适。我们将在第二部分对于配置管理的分支策略进行详细描述。

内容

Martin在第一版中给出的原则是:

任何人都可以找到一台干净的机器,连上网,通过一个命令就可以取得要构建所开发的系统需要的所有源文件。

第二版中的原则增加了对构建的支持6

任何人都可以找到一台干净的机器,做一次取出(checkout)动作,然后对系统执行一次完整的构建。

分阶段构建(Staged Build)

分阶段构建是Cruise(已经更名为Go)引入的重要概念。其主要的意义在于:

  • 分离关注度不同的验证阶段,比如Commit Build和Regression Tests,团队会对不同的验证阶段采取不同的策略
  • 构建流程可视化
  • 通过分阶段并发构建来缩短反馈周期

当构建的时间过长时,我们通常会要求开发人员只运行速度较快的价值较高的构建阶段就可以继续自己的开发任务,而不必等待漫长的次级构建完成。这里作者提到ThoughtWorks不同的团队有很多有趣的实践,我们将在第二部分向读者介绍其中的一部分。

报告

作者在第二版中专门拿出一节“每个人都能看到进度(Everyone Can See What’s Happening)”来介绍有关持续集成报告的内容。因为:

持续集成的目的是为了沟通。

这是第二版相对于第一版来说一个非常明显的变化。在第一版中通知的手段还主要是电子邮件,实际上在作者撰写第二版的时候,ThoughtWorks已经不赞成将电子邮件作为主要的持续集成通知工具了。更好的沟通工具包括音乐、熔岩灯、显示器等。

对于沟通的重视从工具的角度也可以体现出来。Cruise Control最主要做的事情是任务调度,在报告部分做的相对来说非常粗糙,比较有价值的报告大部分是从Cruise移植过去的。Cruise在从一开始就非常重视这一点,通过Cruise你可以非常清晰地知道,代码发生了什么变化、正在进行的构建的状态和历史构建的状态。网页的形式对于分布式团队来说具有不可替代的优势。

正如我们前面所说的,音乐、熔岩灯等物理手段,具有更强的信息辐射能力。站起来往周围看一看就知道哪个团队的构建成功了,哪个失败了。

持续部署

持续集成实践有一个基本的思想就是:越是痛苦的事情,越要经常做。集成之后更令人心惊胆颤的事情就是——部署。部署到生产环境的流程通常要严格得多,然而所有的工作必须经历了生产环境的验证才算是成功的,所以——持续部署才是王道。Martin在第二版中建议:

你应该有一个脚本帮助你很容易地将系统部署到生产环境中去。……同时要特别考虑的是要能够自动回滚。

引入持续集成的建议

作者在第二版中特别给出了逐步引入持续集成的建议。包括:

  1. 引入版本控制。
  2. 实现自动化构建。
  3. 添加自动化测试。
  4. 加快提交构建。
  5. 寻找帮助。(比如ThoughtWorks)

第二部分 持续集成领域的新进展

正如前文所说,ThoughtWorks中国公司在过去的几年里面对于持续集成实践和帮助客户实施持续集成都积累了很多的经验,同时在理论体系方面也更加丰富完整。这也使ThoughtWorks在这个领域继续保持了行业领先的位置。

正如我们在第一部分讲到的,持续集成不应该只作为一个孤立的实践来应用。我们的经验表明如果只把持续集成作为一个孤立的实践应用很难从持续集成长期受益。持续集成往往进入“长红”或者“长绿”的不正常的状态。长红意味着系统长期无法集成;长绿则往往意味着缺少足够的验证。为了术语上的澄清,我们明确地将持续集成的定义区分为狭义的持续集成和广义的持续集成。

狭义的持续集成:基于某种或者某些变化对系统进行的经常性的构建活动。

广义的持续集成:软件开发团队在上述活动的约束下所采用的开发流程。

狭义的持续集成

一般来说,狭义的持续集成包括如下几个方面:持续检查、持续编译(链接)、持续验证、持续部署、持续基础设施、持续报告等6个方面。

持续检查

持续检查的目的是保证代码风格一致,主要关注于代码的静态质量和内部质量,比如变量命名方式、大括号位置等等。大部分的现代集成开发环境(IDE)都具备实时检查代码质量的功能。为了保证主线上的代码质量能够达到一致的标准,应当在持续集成脚本中加入静态检查阶段。比如,Java的PMD、 FindBugs等等。

持续编译

持续编译是一个很朴素的想法,就是保证主线上的代码始终处于可编译的状态。但是这对于很多大中型团队来说却并非想当然的简单。这是因为很多团队并未采用集体代码所有权策略,导致存在依赖的团队的代码无法编译。针对这样的问题,一方面我们建议采用集体代码所有权;另一方面,对于确实因为安全原因需要隔离的代码应该边界、明确接口,很少存在大部分代码需要对大部分人保密的情况。

持续检查和持续编译是持续集成中最基本的验证手段。

持续验证

持续验证的目的是检查主线上的代码是否能够实现所要求的功能,或者已有的功能是否被破坏。在大部分的构建中,验证部分是耗时最长、成本最高的部分,但同时也是收益最大的部分。在这个阶段,我们看到的主要问题是验证不充分和验证时间过长。针对这样的问题,我们通常采用分层分级的持续集成策略。后面有详细的描述。

持续部署

对于大型软件应用来说,部署往往是一个费时费力又容易出错的步骤,因为这里面涉及到数据迁移、版本兼容等各种棘手的问题。持续部署的思想是将这些工作标准化自动化,使其能够可靠地、自动地、快速地运行。持续部署是当前DevOps运动中的热门话题之一。

持续基础设施集成

现代大型软件开发,尤其是互联网应用开发中经常依赖于一些常见的基础设施——比如Spring、Tomcat、Database等等。这些基础设施发生变化的时候,我们应当及时地触发持续集成,以确保我们的系统是能够与新的基础设施一起工作的。

持续报告

报告是将持续集成的状态以适当的形式展现给干系人的基本手段。报告是持续集成的晴雨表,所以它必须直观、易懂,而且对关注点不同的角色展现不同的内容和粒度。比如,开发人员可能更关心错误的日志;项目经理可能更关心测试覆盖率;产品经理可能更关心持续集成通过率的趋势等等。

广义的持续集成及持续集成策略

当要把持续集成实践应用到团队的时候,有很多额外的技术或者非技术因素需要考虑。

组织结构

持续集成是一个重要的沟通工具,而开发过程中两个最需要紧密沟通的角色就是开发和测试。在我们常见的组织结构中开发和测试往往隶属于不同的部门,甚至这些部门隶属于不同的高级经理。这往往会给持续集成的推广带来很大的阻力。这是因为持续集成从环境搭建到运行维护都需要两种角色的通力合作。我们的经验是这类涉及到人力资源的事情除非某一级“共同的大老板”出面,否则是很难协调的。“借调”这样的方式往往不能保证效果。

流程

放到团队的角度看待流程应当更加关注于各个成员之间的配合。每个开发人员提交代码之前应当确保是经过本地构建的;开发人员在提交之前应该确认主线上的代码是通过了持续集成的;测试人员测试的版本应该是通过了某次持续集成的,并且有相应的具体版本信息。

为了保障流程的顺利执行,我们还经常采用持续集成看板、提交令牌等辅助手段。

环境

环境是指持续集成运行时所依赖的软件和硬件的集合。我们经常遇到的一个问题是,软件在一台机器上能够通过持续集成的验证,而在另一台机器上则不能通过。这通常是因为我们对持续集成环境的定义不明确造成的。所以在搭建持续集成和在组织内推广持续集成的时候,我们需要特别注意持续集成环境的标准化,明确指出持续集成运行时依赖哪些第三方库,机器配置如何,端口和网络状况如何等等。

我们经常采用将持续集成环境加入配置管理的方式来解决环境标准化的问题。

分层

在大型团队(超过100人)中,扁平的开发组织结构是运行起来是比较困难的。常见的做法是按照特性,将团队划分为10人左右的小团队。一般来说,如果团队数量超过10个,还会再增加一层架构。这时候,配置管理的策略也应当做出调整。常见的做法是为每个团队拉出一个分支,设置一个集成分支用于将各个特性分支的内容整合在一起。需要注意的是,这里每个分支都应该具备所有代码的访问权限,也就是所有分支是同根的、等价的。

图片来自:http://damonpoole.blogspot.com/2008/01/multi-stage-continuous-integration-part_05.html

测试分级

在实施持续集成的时对于测试的类型应该有比较明确的定义。一般来说,我们经常把测试分为三级——单元测试、集成测试和系统测试。这是一个很大的话题,这里只是说明此处的单元测试并不是指针对函数的测试。虽然单元测试主要是函数基本的测试,但是每个单元测试应该针对的是特性或者对应代码在实现该特性上所发挥的作用。

单元测试的运行速度通常非常快,应该在数秒到数分钟。单元测试应该覆盖绝大部分的特性需求。集成测试单个测试的运行速度通常会比单元测试慢一个数量级,比如存在文件读写或者其他的IO和网络操作。集成测试主要用于保证系统的各个组件之间的调用是工作的。系统测试的运行速度一般会比集成测试慢,通常需要将整个系统运行起来,比如Web开发中的selenium测试。系统测试主要用于测试系统的正确路径(Happy Path)可以工作。有的团队会开发很多基于整个系统的回归测试,也属于系统测试。就场景的覆盖而言,单元测试>集成测试>系统测试,从运行时间来看则相反。

持续集成的成熟度评估

在帮助客户实施和推广持续集成的过程中我们逐渐总结出一些原则,帮助客户评估现状,分析和设计未来的目标。该评估方法借鉴了ThoughtWorks敏捷成熟度模型中有关配置管理、测试、构建等内容,并做了适当的简化。

构建:

级别 描述
3+:对外防御的 团队能够根据自己的需要,协调其他团队的持续集成,当依赖的其他团队的代码和组件或者第三方库和基础设施发生改变时自动进行构建。团队对于外部依赖的可靠性有信心。
3:对内防御的 构建是自动的。由测试和检查来保证团队内部的开发质量。持续集成的修复具有最高的优先级。团队对持续集成的结果有信心。
2:频繁的 构建是自动的,而且构建的速度较快。构建的触发条件是明确的,通常每次代码提交都会触发构建。团队中的每个人都会触发构建,并且了解构建的状态。
1:重复执行 构建是自动的,但是执行的不够频繁。构建的触发是随机的或者频率是非常低的(低于每天一次)。构建的速度通常非常慢,比如一次构建超过半个小时。
0:可重复的 主要依赖于手动的方式构建软件,但是每次构建的方式都是相同的或者相似的。通常有相关的文档的指导。经常团队指定某个人负责构建软件,虽然大部分人都能够做这件事情。
-1:手动的 主要依赖于手动的方式集成软件。每次集成的方式可能不一样。经常团队中只有个别人能够将软件集成起来。

测试:

级别 描述
3+:全面集成的 全团队对测试负责。测试驱动整个开发过程。测试与构建完全集成。
3:测试驱动的 业务分析人员和开发人员均参与测试。测试在构建过程中自动执行。开发人员实践测试驱动开发。
2:集成的 开发人员参与测试。部分测试集成在构建过程中执行。大部分测试在软件开发过程中执行。
1:共享的 开发人员参与测试。测试并未集成在构建过程中。部分测试在软件开发过程中执行,大部分测试在软件开发结束后执行。
0:审查的 测试由专门的测试人员负责。有部分测试是在软件开发过程中执行。但大部分测试在软件开发结束后执行。
-1:独立的 测试由专门的测试人员负责。仅在软件开发结束后执行。

配置管理:

级别 描述
3+:企业级的 企业有统一的配置管理策略。
3:跨项目的 配置管理在多个项目之间协调。
2:自动的 配置管理策略与持续集成策略紧密结合,团队成员有频繁提交的意识。一般采用乐观锁策略,原子提交。
1:集成的 版本管理下的内容是受控的。通常在版本管理中的代码是可以编译的。开发人员能够访问到自己工作所需要的代码。开发人员按照一定的规则访问配置管理工具和提交代码。一般采用悲观锁策略。版本管理工具和构建过程集成在一起的。
0:基本的 有基本的版本管理。但版本管理下的内容不全面,或者不足以支撑团队的开发。
-1:无配置管理 没有配置管理。或者使用方式完全错误。

常用实践和工具

持续集成看板7

问题:

我们需要让整个团队能够方便快捷的了解持续集成的状态。

上下文:

在完成了基本的构建基础设施的搭建之后,我们需要让团队成员及时获得持续集成的状态信息。传统的邮件方式可能会使人厌烦,或者错过重要的构建信息。

解决方案和实现:

安装一个显示器,将构建的状态信息以简明的方式展示在显示器上。将显示器放置在团队所有成员都能够很容易看到的地方。

个人构建中心

问题:

在某些情况下,构建环境的成本很高,而我们需要每一个开发人员提交之前完成一次个人构建。

上下文:

有些测试是依赖于设备的,而这些设备非常昂贵,并且配置复杂,所以无法给每个开发/测试人员一套构建环境。我们发现根据本地构建的理论模型,每个人的提交应该是串行的,这样我们实际上可以做到让这些人共享一套环境,但是从逻辑上就像是每个人有一套自己的环境一样。

解决方案:

在运行个人构建的时候将本地的代码同步到一台共享的机器上执行构建,构建完成后结果反馈给提交这次个人构建的人。

实现:

个人构建中心的实现有很多种方案。这些方案的区别主要在于如何将代码同步到个人构建中心服务器上。两种常见的方式:一个是使用rsync或者类似方式同步;另一个是使用分布式配置管理工具如git/hg同步。其拓扑结构如下:

第一种方式相对独立灵活;第二种方式稳定、高效,但是对于配置管理工具有依赖。

后果:

个人构建中心节省了大量的计算资源,同时也容易使得中心服务器成为单点失败的源头。一旦中心服务器出现问题,可能会导致团队的流程受到较大影响。

提交令牌

问题:

在实施本地构建的时候,向目标分支的提交应该是串行的,以避免构建被破坏后难以定位问题来源。但是团队往往缺乏一种有效的机制来保证这种串行。

上下文:

有些团队试图通过技术的手段来解决这个问题,比如通过配置管理上的锁机制,这种方式和乐观锁模式有较大冲突。有些团队通过团队内部沟通的方式解决,比如谁提 交之前都会通知别人,或者通过持续集成监视器来了解当前的构建状态,以决定自己是否可以提交。这些方式各自有各自的适用情形,较容易理解。

解决方案和实现:

使用一个实物作为令牌,准备提交的代码的人首先取得令牌,当代码提交完成(包括相应的提交构建)之后,将令牌交还。令牌要醒目,并且移动方便。小型奖杯、毛绒玩具、较大的头饰(如下图)都是不错的令牌。

分阶段构建

问题:

在某些团队中完整构建所花费的时间可能很长,如果每次提交都运行完整的构建会浪费很多时间。

上下文:

随着持续集成的日益完善,我们往往会发现验证所花费的时间越来越长,而大部分验证趋于稳定,失败的情况很少见。通过技术手段缩短构建时间是解决问题的根本办法,但是缩短构建时间是一个耗时耗力的工作,很难短期内见效。

解决方案和实现:

将构建分为几个阶段执行,在本地构建中仅执行速度比较快、可信度比较高、出错概率比较大的验证。利用晚上或者其他合适的时间执行全面的验证——我们这次构建称为全量构建。需要注意的是,这种情况下仍然要保证提交构建和本地构建的一致性。

iAnalysis

iAnalysis是一款轻量级的持续集成报告工具。该工具的核心思想是将持续集成构建过程中产生的数据以趋势和对比的方式展示出来。正如前文所说,我们在2009年的ThoughtWorks Away-Day上讨论了敏捷度量的话题,大家最后一致认为,数据有两种最基本的用法——横向对比和纵向对比。横向对比就是不同的人、不同的团队之间对比;纵向对比就是现在和过去对比。iAnalysis正是这种思想的体现。

关于作者

肖鹏,ThoughtWorks资深咨询师,程序员,敏捷过程教练。拥有7年以上软件开发实践经验,多次担任大中型企业敏捷流程改进咨询和培训,服务对象涉及通信设备制造、通信运营、互联网行业等。他关注于设计模式、架构模式、敏捷软件开发等领域,并致力于软件开发最佳实践的推广和应用。他曾参与翻译《Visual Studio 2005技术大全》,主持翻译《面向模式的软件架构》第四卷和第五卷等图书。


1 目前Cruise的开发任务已经不在中国公司了。

2 实际上这篇文章介绍的是Matthew所在团队在2000年早些时候已经在使用的实践,ThoughtWorks中国公司的总经理郭晓先生当时也在这个团 队。

3 为了与ThoughtWorks常用的术语保持一致,部分术语与雷镇和熊节同学所译略有差别,下同。

4 笔者对其格式略作处理,与原文稍有出入。

5 Martin最近在自己的一篇博客上对几种流行的配置管理工具做了对比。

6 注意,本文并非为指出第一版的缺陷,只是通过对比来说明作者论文中重点的变化。

7 这里只是借用“看板”这个词的字面含义,与精益中的看板有区别。


感谢张凯峰对本文的审校。

本文原文发表于InfoQ:http://www.infoq.com/cn/articles/ci-theory-practice

Share

我和敏捷团队的五个约定

我——作为一名测试人员——有一个与众不同的习惯:每当要加入一个新项目的时候,我总会找到项目中的同伴,真诚而亲切地说:“为了更好地合作,我有5个约定,希望大家能尽量遵守”。

约定1. 业务分析师们,我们其实是同一个角色的两种面孔,请叫上我们参加客户需求会议

我们的团队需要让客户频繁的得到可用的软件,客户的不断反馈会给软件的未来做出最正确的方向指引。

如果我们交付的软件有很多质量的问题,存在大量的缺陷,客户会被这些缺陷的奇怪行为干扰,没有办法把注意力放在软件本身的价值是否符合他们的真正需求上, 不能给出最有价值的反馈。所以,我们只有频繁的做测试,在每次交付之前都把质量问题找出来告诉我们的团队,问题才能及时的得到改正。

而我坚信“prevention is better than cure”(预防胜于治疗),我会要把工作的重点放在预防缺陷上,这样可以节省Dev们很多修复缺陷的时间与精力。

为了达到这个目的,我需要跟你一起参加客户需求会议,尽早的了解客户需求与使用软件的惯常行为。那么在你完成需求的验收条件的定义的时候,我也基本完成了测试用例的准备。

我们可以赶在开发人员们写代码之前就告诉他们我要测什么,让他们减少因为过于乐观而漏掉的一些重要的有破坏性的情况,减少缺陷的发生。这是我测试的一项重要任务。

如果你们在大部分需求都整理好了再交给我们,我会浪费掉等待的时间。更重要的是,开发好的软件里面已经有很多本来可以不存在的缺陷在里面了,开发人员们可能需要加班加点来保证在项目最终交付时间之前把它们改好。这样很容易产生新的缺陷的。

所以,请让我尽早了解需求,请不要让我到项目后期才能开始测试。

约定2. 开发人员们,虽然你们是编写自动化测试的专家,但请听听我们意见

我知道,对于你们,自动化测试不过是利用junit, rspec, selenium,watir,uiautomation等等写出的“另一段程序”而已。而对于80%的QA来说,编写自动化测试并不是一件简单的事情。

不过我仍然相信,有测试人员介入的自动化测试更有价值。

你们用单元测试,集成测试来保证代码的质量。然而你们的这些日常测试离代码更近,离最终用户还点远。很多测试都不是在测软件功能。

你们可以把功能测试写的又快又多,而我们可以指出什么功能测试最有必要加到自动化测试中。

你们平时大部分精力都在编码上,没有太多时间去查都有什么缺陷。而我们可以指出什么地方缺陷可能会出现的比较频繁,建议在这些脆弱的地方加自动化测试。

所以请听听我们的意见,我们可以给你们提供这些信息。

约定3. 项目经理们,请不要要求我们测试软件的所有路径

软件测试是一个永无止尽的任务。基本上没有什么软件简单到我们能够尝试完它的每一个可能的路径的。就连一个看似简单的微软计算器都有无穷尽的路径,无止尽的输入,更何况比这个更复杂的商用软件。

如果你们担心没有尝试过全部的路径不可靠,疑惑我们怎么敢说这个软件质量是好的还是坏,都有什么风险。请你们先注意,我们是跟业务分析师一样,都了解软件的价值的。价值可以帮我们做出判断,什么时候可以停止测试并对客户说我们的软件已经满足您的要求了,请放心使用。

因为我们了解价值,我们可以肯定的说哪些软件的使用方式是至关重要的,哪些是不太可能出现的。我们会在全面测试了软件以后,把主要精力放在价值高的功能点上。合理的利用项目有限的时间。

因为我们了解价值,我们可以正确的把发现的问题分类。我们可以帮助dev们把精力放在重要的缺陷上,避免把时间放在对于客户微不足道却不得不花费大量精力才能修正的问题上。

所以,请不要要求我们无止尽的测试一个软件。我们了解价值,请相信我们的判断。

约定4. 迭代经理们,如果对于交付风险有任何疑问,请来询问我

BA和Dev们都是关注一个软件在什么情况是可以良好的工作。而我们除了验证这些情况以外,大量的时候都用在寻找什么样的情况软件不能正常的运行。所以除 了针对定义好的软件行为进行测试,我们还会做很多探索性测试。我们通常可以通过这样的测试发现一些没有定义的、不曾预期的行为。这些行为往往将会构成软件 交付的风险。

我们会告诉你们现在都发生了什么问题,分别分布在哪里。

我们会告诉你们,在什么情况下软件可能会有异常行为,是不是会牵连到其他的部分,是否可以绕过去。

我们会告诉你们,哪些部分功能比较不稳定,需要更多的留意。

约定5. 测试人员们,那些敏捷实践对于我们也是有用的。

结对不是dev们的专利。我不希望总见到你们独自坐在自己的位置上冥思苦想。走出去,跟其他队友多多交流!

多跟测试队友交流,pair看看设计的测试用例是不是够全面,独自一个人想到的未必足够好。他们会给你诚恳的意见的。对他们,也请一样认真对待。

如果你发现开发人员们做出的架构决定使测试工作变得更困难。那么请大声地告诉他们,design for testability(提高你们设计的可测性)。

如果你发现业务分析师写的需求无法验证,定义的客户行为不够具体,一个用户故事中包含太多了功能点,等等,那么也请大声地告诉他,INVEST(独立,可协商,价值,可估算,短小,可测)。

也请你们多跟开发人员结对写自动化测试,既可以帮助你们学习怎样更好的编写自动化测试,也能帮助开发人员们结对更多的了解用户行为。

这就是我的五个约定,它们是我在团队中顺利展开工作的基础。


作者:覃其慧,ThoughtWorks敏捷咨询师。她参与了大量的敏捷软件开发的实践和敏捷咨询。目前主要关注以价值为驱动的敏捷测试。


本文原文发表于InfoQ:http://www.infoq.com/cn/articles/thoughtworks-practice-parti

Share

敏捷测试之借力DSL

随着敏捷越来越广为人知,敏捷测试也更多受到了大家的关注。在这里,我想谈一下我在敏捷项目中遇到的一个自动化测试相关问题以及我们如何借助DSL领域专用语言来解决它。

对敏捷软件开发方法有一定了解的人都知道,敏捷软件开发过程是一个迭代式交付的过程。每个迭代相当于比较小型的交付周期。那么,为了配合频繁的软件交付,敏捷测试相对于传统测试必须要做相应的调整。这也导致了敏捷项目中的测试面临几个特有的挑战:

  1. 频繁的回归测试以确保每个迭代的成果都是可交付的
  2. 让整个开发团队参与到测试活动中以缩短质量信息的反馈周期
  3. 让客户参与到测试活动中来帮助提高测试的有效性

自动化测试在应对频繁的回归测试这个挑战上起着非常关键的作用。自动化测试做不好,团队最终会被每个迭代都会增加的回归测试工作量压垮。我经历过的一个团队,在这个团队中,大家很早就意识到了自动化测试的重要性,在自动化测试上的投入不遗余力。我们相信自动化功能测试增加到足够多的时候,它就能指导手动回归测试,保证整个交付过程顺利进行。

的确,自动化测试刚开始进行的时候,我们收益颇多。每增加一个自动化测试,我们就能减少一些手动测试。自动化测试让我们我们有比较充裕的时间来手动测试那些还没有来得及自动化的、难以被自动化的功能点上,而且还能有时间和精力做探索性测试。这个结果让团队感到生活很美好,也让我们对自动化测试坚信不疑。

然而好景不长,随着自动化测试的不断增加,我们会面临这样一些问题:

  1. 自动化测试是围绕着实现细节展开的。随着数量的增多,业务的轮廓很容易迷失在细节中。
  2. 在功能级别丧失了对测试的追踪。由于测试人员无法具体知晓那些测试案例被自动化测试覆盖。每次回归的时候,团队都需要回归整个测试组。

于是,我们的手动测试越来越难得到自动化测试的帮助。它开始成了项目的鸡肋。测试代码阅读困难、维护困难以及测试结果的看起来也很费劲。这直接导致了我们不仅要投入相当的时间来增加自动化测试,也要投入不少时间来阅读并利用测试结果。

于是我们开始重新审视自动化测试的做法,继续摸索更好的方式。

很快,我们发现“能够跑起来”并不是好的自动化测试仅需的特性。让我们通过一段测试代码来看一下具体怎么回事。

selenium.open(“/”)
selenium.type(“id=username”, “myname”)
selenium.type(“id=password”, “mypassword”)
selenium.click(“id=btnLogin”)
selenium.waitForPageToLoad(30000)
assertTrue(selenium.isTextPresent(“Welcome to our website!”))

这个测试中,我们首先打开了一个页面,在页面中寻找一个id为username的输入框,输入“myname”,然后再寻找一个id为password的输入框,输入“password”,然后点击一个id为btnLogin的按钮,等待30秒以后,断言页面应该出现的文字。

我们可以看到,这个测试的实现很完整的描述了测试的操作过程,是一个面向步骤而不是目的的描述。当然,稍加分析,我们也可以看出来这个测试的目的是测用户登录成功系统。

但是,想象当我们有很多这样面向步骤来描述的测试时,要从中抽离出被无数细碎的操作步骤所淹没的测试意图,并把测试的结果利用起来,其实并没有那么直观。而且,如果在测试中出现了错误,对于问题的具体功能点的定位也不是那么容易。

与此同时,并不是团队中所有的成员都有能力阅读和编写这样的测试。这无疑降低了团队成员对于自动化测试的参与度。对于客户,自动化测试更是一个黑盒子,做了什么,没做什么,基本上搞不清,更谈不上参与到自动化测试中,帮助提高测试的有效性。

种种状况,究其原因就是测试可读性太差,测试意图不够明显。可运行并且容易读的测试才是好的自动化测试。这样才能够保证任何时候,我们不会丧失对于测试案例的跟踪与管理。测试人员随时都可以通过快速阅读测试,了解那些功能已经被自动化测试覆盖,有效规划手工测试的工作量。

怎么提高测试的可读性呢?

我们的解决办法是DSL领域专用语言。

什么是领域专用语言?在马丁大叔的博客里有比较详细的描述。大致来说,领域专用语言就是针对某个领域的特定目的编程语言。不像Java、C#等通用语言,可以解决任何领域的问题。领域专用语言通过自己独特的语法结构来描述更接近于专业领域语言的业务。

让测试的描述能够接近被测系统的领域语言、使测试意图得到清晰表达就是我们想要得到的效果。DSL正好能够帮我们实现。

让我们再看看之前的那段代码:

selenium.open(“/”)
selenium.type(“id=username”, “myname”)
selenium.type(“id=password”, “mypassword”)
selenium.click(“id=btnLogin”)
selenium.waitForPageToLoad(30000)
assertTrue(selenium.isTextPresent(“Welcome to our website!”))

由于使用的是通用语言,在我们这个特定的使用场景中显得过于细节化、过程化,不能清晰表达测试意图。

换成DSL,我们的测试就可以直接用验收标准的语言来描述如下:

Given I am on login page
When I provide username and password
Then I can enter the system

这样测试的内容就直观多了,还包含了一些业务信息,让我们知道这个是在测试一个登录的场景,而不是任意的输入信息,兼顾传递了业务知识的职责。至于这些DSL背后能够运行的代码,也被隐藏起来。如果是不能够阅读原来那样的测试代码的人(不管是需求分析人员还是客户甚至一些对自动化代码关注比较少的测试人员)想要加入到自动化测试活动中进行反馈,就不会被DSL背后的代码带来的“噪音”所影响。

当然,在我们的现实应用场景中,这个需求没有那么简单,我们的验收标准还会考虑不同的数据比如输入不同组合的用户名密码:

Given I am on login page
When I provide ‘david’ and ‘davidpassword’
Then I can enter the system
Given I am on login page
When I provide ‘kate’ and ‘kate_p@ssword’
Then I can enter the system

以及更多的测试数据。

那么这种情况下,仅仅是比较通俗的语言还是不够的,毕竟测试数量在那摆着。如果测试数量不能减少,维护起来仍然很麻烦。打个比方,如果系统的实现变成了每次都要输入用户名、密码和一个随机验证码,我们就需要在我们的自动化测试中修改多处,比较繁琐。因此,我们需要在可读性比较好的自然语言描述的测试上,把它的抽象层次再提高一点。

幸运的是,我们当时选择的DSL工具是cucumber,它除了提供了几个测试的描述层次:Feature,Scenario,Steps,还提供了非常好的一种组织方式—数据表。

这样,我们的这个自动化测试就可以把之前的那个登录的功能根据特性、场景总结和具体的步骤分离开来,清晰的分层,同时利用数据表我们的测试精简成一系列被重复多次但输入数据有所变化的操作过程,如下:

Feature: authentication
In order to have personalized information
I want to access my account by providing authentication information
So that the system can know who I am
Scenario Outline: login successfully
Given I am on login page
When I provide ‘<username>’ and ‘<password>’
Then I can enter the system
Examples:
|username |password |
|david |davidpass |
|kate |kate_p@ssword|

测试这下看起来就更清爽了。首先,用Feature关键字,我们把测试分类到login这个大特性下的,并对这个特性本身的业务目的进行相关描述,带进业务目标,传递业务知识;然后用Scenario关键字来提高挈领的标明我们这个测试场景中做的是测试登录成功的情况,并且把步骤都写出来;最后,我们用Examples关键字引出具体的数据表格把用到的数据都展示出来,避免我们的相同步骤因为测试数据的变化而重复若干遍造成冗余。万一碰上了需求的变化,要求同时提供用户名、密码和验证码,那我们的测试也只需要改动较少的地方就足够了。

更棒的是,用了这种数据表的方式,整个团队的协作效率提高了。对于写代码没有那么顺畅的测试人员来说,增加自动化测试也就是增加更多测试数据,填充到数据表里就可以了。

就这样,我们用DSL实现了可执行的可读性高的文档。帮助了回归测试,降低了文档维护难度,也促进团队成员利用测试来传递知识的积极性,让更多人能够参与到测试中。如果您的团队也遇到了类似的问题,不妨也尝试一下。


本文原文发表于InfoQ:http://www.infoq.com/cn/articles/leveraging-dsl-in-agile-test

Share