E项目是一个在线的物资跟踪监控系统。由ThoughtWorks团队提供的一套完善的软件交付服务,整个开发过程由ThoughtWorks团队负责管理。
ThoughtWorks提供完整的交付团队(PM* 1, BA *1 , TL * 1, QA * 1, DEV * 4, UX * 1),团队为颇具代表性的敏捷团队,规模10人左右。客户团队主要接口人3位。
项目上的主要技术栈是Python, Django, AngularJs, PostgresSQL, Docker。DEV在进入这个项目之前,擅长的技术栈是Java, Springboot, C#, Android, jQuery。
项目之所以成功交付,核心在于人,而良好的敏捷流程与实践也是不容忽视的。
早在2001年,17位追求卓越的志愿者聚集在美国犹他州雪鸟独家圣地,讨论一个新的软件开发趋势,它被称作轻量型软件开发过程,后来他们将它定义为敏捷,并且发布了敏捷开发宣言:一种把以人为本、团队合作、快速响应变化和可工作的软件作为宗旨的开发方法。敏捷宣言可以总结为四句话:
个体与交互 优于 流程与工具
客户协作 优于 合同谈判
响应变化 优于 遵循计划
可工作的软件 优于 面面俱到的文档
也就是说,尽管右项有其价值,我们更重视左项的价值。
敏捷开发的核心就是在一个高度协作的环境下,不断的通过反馈来进行自我调整和完善。重点强调的是协作和反馈,协作体现在团队与客户之间的协作,团队成员之间的协作。反馈则是在开发中的任何环节,包括代码质量、自动化测试、部署、项目进度、需求变更、客户验收等,而且反馈越快越好。有句土耳其谚语这么讲的:"不管你走了多远,错了就要重新返回",所以我们越快得到反馈,就能越早确认自己有没有走错路。如果没有错,我们会更加充满信心。反之,及时做出调整,让浪费?最小化。
项目中所涉及的敏捷实践主要围绕迭代进行,用一张图概括:
(点击放大图像)
可以总结出以下几点:
敏捷的宗旨是减少浪费,所有的敏捷实践也都是围绕着高效协作与快速反馈这两个核心理念展开。
IPM(Iteration Plan Meeting),迭代计划会议主要是跟客户保持沟通与信息更新的一个会议。
敏捷宣言里面有一条:客户协作优于合同谈判。在Scrum团队中有一个角色叫做产品负责人,Ta的核心职责是确保业务需求的清晰和透明,保证开发团队对业务有足够的了解,并将这些待完成的业务需求(Story)按照优先级排列出来,按照任务卡的方式来驱动团队的开发。并在客户需求有变更后能够第一时间告知团队以做出调整。
在我们团队中,这个角色就是一开始提到的BA。她是IPM主要参与人,另外还有Tech Lead会一起参与讨论(团队中每一个人成员都是可以参与进来的)。IPM按照团队指定的迭代的周期,通常是两周,每隔两周跟客户接口人一起约一个时间,主要讨论以下几个方面的内容:
通过这种会议,能够让客户对我们团队状况有一个清晰的了解,而且客户对我们下一个迭代要做的功能有了整体的把控,一起设定好期望,这样也会大大降低风险。
IPM的主要产出是下一个迭代中完成的Story,这些Story即为下一个Story要完成的目标,我们通过敏捷看板工具来管理它们,例如下图上位于Backlog栏中的Story:
(点击放大图像)
跟客户建立信任关系是合作的基础,而让客户保持愉悦,也是项目成功交付的助推剂。
Regular catch up with client,即 定期跟客户进行沟通,双方共同商议一个时间(工作时间最佳),一起开个短暂的小会,时间上的成本较低。
Catch up的主要参与人员是BA(PM)和TL,通过于客户方Face2Face会议或者online会议进行一个短暂的沟通,沟通内容主要涉及:
因项目而异,Catch up实践可以大体分为两种:
通过与客户进行定期的沟通,产生的价值主要体现在客户信任和客户关系方面:
并不是每一个项目都会有这个实践,有些独立交付的项目,他们每日站会的时候客户也会参与进来,就不需要额外单独的时间去做这件事情了,而有些项目,因为特殊性,客户可能不希望这么频繁的Catch up,这时候需要团队灵活变通,与客户一起商讨出一个合适的时间周期,做出一些权衡,让客户自身觉得舒服。总之,Keep住的一点是:保持跟客户的信息沟通,尽可能早的得到客户的反馈,保持良好的客户关系。
Standup是一项成本小收益大的活动,做好它是敏捷的第一步。
Standup,就是每日站会。我听过一个有趣的事情:在敏捷开发方法兴起的时候,很多传统开发模式的团队跃跃欲试,他们选择从Standup切入。然后每天早上上班后,大家聚在一起开个会(站着、坐着都有),然后该怎么做还是怎么做。他们会对别人说,我们在搞敏捷开发…
没错,Standup就是团队在一起快速地开一个会,大家挨个的更新一下自己的状态,更新包含以下几个方面:
既然是快速的会议,Standup的时间就不宜过长,建议5~15分钟。最好是站着开会,因为研究表明,当人们坐着开会的时候,会议的时间会被无形中拉长。Standup的时间安排在工作时间开始后的半个小时最佳(比如9:00上班,9:30开始),这样大家就不用一到公司就急急忙忙的参加Standup,大家有个缓冲的时间,比如说设置电脑,泡咖啡,沏茶,整理今天的todo list等。
没有什么特殊原因的情况下,确保团队成员都要参加,如果一些人因为特殊原因经常不按时到,适当调整Standup的时间,但也不宜太晚。
而对于规模很小的团队(3~5人),也强烈建议执行Standup,因为它的成本真的很低。
或许有人会觉得:大家天天都在一起工作,沟通如此方便,何必要这项活动? 这有点深处酒巷中不觉酒香的味道了。站会能够给团队带来的价值不容忽视:
在一个Story开始前,确保BA, QA, DEV对Story的理解达成一致,并严格按照AC来验收。当然,前提是Story本身是不容置疑的。
Story kick off,指的是对某一个Story进行开卡,也就是启动该Stroy,从而使其进入开发阶段。Story kick off的时候,通常需要三个角色一起参与:BA、QA以及要开发该Story的DEV。
Story由BA预先写好,并通过专业的敏捷管理工具进行管理。DEV在kick off的时候,BA会给DEV讲解这个Story要完成的功能,以及它的AC。DEV如果对其中的描述有任何疑惑,需要及时提出来,当场弄明白才可以正确的去完成这些功能。在后续的开发过程中,如果碰到任何疑惑,随时找BA或者QA了解清楚,不应该自己猜测着开发,更不可跟着心走。
Story kick off 的核心目的是确保DEV开发出的功能都是符合客户期望的。而Story本身存在错误并不在讨论范围之内。实际上在开发过程中,也未发生过这种情况,因为一旦客户的需求变更后,Story卡也会及时变更过来。Story kick off 可以follow以下实践:
最后一个实践严格上讲不是kick off环节里面的,它发生在kick off后,DEV自行决定怎么去完成功能。我比较推荐DEV在kick off后将Story划分成子任务列表,按照依赖关系和优先级排序,逐个干掉他们。一些敏捷管理工具(, , , )都支持这种任务拆分,你还可以很容易的记录与跟踪。
Story kick off也是一项短时间高收益的活动,因为在我们DEV界中,有一句邪门的定律:
猜出来的需求往往是不靠谱的,最终需要打回重做!
所以kick off能够有效的避免Dev自行臆测业务需求而产生的浪费。除此之外,能够弥补BA在编写Story的时候技术视角的一些遗漏。
一些项目会引入好的开发实践,比如说BDD。它能按照人类自然语言去描述一个功能的实现。我们的Story描述通常会参照这种方式: as...when...then...when...then。这个时候,DEV、QA、BA可以在Story kick off的时候利用一些测试工具()一起来编写Story验收测试用例(主要由QA来编写),DEV负责编写代码来通过这些测试。理想情况下,验收测试用例如果正确完整,当所有测试都通过后,意味着Story功能已经完成。而且这种TDD的方式,代码出现bug的几率也会大幅度降低。
结对编程的开发速度通常小于简单地将一个人的开发速度乘以2,但它依然能创造价值:知识的共享,代码质量的提高,缺陷率的降低。
XP里面提到了结对编程,经过事实证明,它是一项利大于弊的实践。
通俗地讲,Pair就是两个人同时工作在同一个Story上,一起讨论Story的解决方案,并编写代码实现功能,一个人敲键盘,一个人看屏幕,穿插着进行。Pair的小伙伴在快速敲击键盘的时候会伴随一些交流,并时不时停下来讨论说笑片刻,亦或是在欣赏一下自己漂亮的代码。
两个人一起写代码即为Pair,那么如何进行高效的Pair呢,也有一些良好的实践:
在一些很简单的defect上,可以不采用Pair。
Pair将本来可以并行工作的两个人聚焦在一件事情上,表面上是在降低生产力,实际上它确实是有一定的成本的。而这种付出并不会打水漂,最明显的好处是能够最大化知识的共享(尤其是更换pair的场景下),包括业务知识的共享、技术方案共享、解决问题思路的共享,这一点尤其体现在团队有新人融入的时候,通过Pair能够快速带领新人成长起来,提高整个团队的战斗力。另一方面可以提高代码质量,Pair实际上是两个人一直在不停的做,两个人的思维碰撞能够避免很多代码小聪明和不好的编码习惯。
有些时候,因为项目进度的紧张,Pair并不会这么理想的被落实,团队可以进行灵活的调整。如果Pair的时间减少了,可以通过加长的时间来做一些弥补。
TDD,测试驱动开发,这项人人都称赞、却很少有人真的去做的活动,不应该只是一个被供奉起来的神。接地气,再接地气一点。
TDD,即测试驱动开发,强调的是测试先行。TDD是一个存在争议的主题,因为在一个连测试的没有的代码库中(多数客户也不关心测试代码,他们通常只想要看得到的功能),它的立身之本就不复存在了。我经历过只有纯手工黑盒测试的项目,没有单元测试、没有集成测试、没有E2E测试(),所以TDD无从谈起。我也经历过客户要求测试覆盖率的项目,有专门的测试覆盖率工具()来检测代码库,有的甚至集成在上作为一个硬性指标。
所以,TDD必须在一个有测试的项目中去讲。它跟我们先实现功能代码后添加测试的过程恰恰相反。我们根据对业务理解,先写一些测试(E2E,Integration, Unit),此时得到运行结果为红色(测试运行失败),然后编写业务代码让其变绿(测试运行成功)。
当然,TDD实践存在一定的门槛,TDD更多地考察一个人的设计能力,所以需要有一定经验的开发人员,而新人往往是很难做到这一点,但这不应该是新人不去尝试TDD的借口。
在实际项目中,可以根据团队自身的条件,灵活采取TDD去编码。就我个人的经验而言,TDD编码的时候刚一开始的时候并不是那么顺手(因为TDD更偏重设计),心里会觉得比较耗费时间,最终Story的完成时间相差无几,而TDD除了有效地降低缺陷率,还有以下三个方面的好处。
不可否认的一个事实:人人都爱整洁的代码。而一个人单独编码难免会耍一些小聪明,或引入一些自身习惯难以察觉的不良代码。Code Review能让你提高警惕,并改善代码的质量。
Code review,检查代码,也叫代码审查,就是开发人员凑在一起来检阅彼此所产出的代码。看看有没有新的代码坏味道,看看有什么不合理的设计甚至是错误的设计,等等。
既然是开发人员凑在一起审查代码,那么Code Review会产生一定的时间成本(根据团队的规模1~2小时 = 5~10个开发人员),所以需要一些良好的实践来确保Code review的高效产出:
另外,从团队规模和时间安排上,可以遵循以下两个原则
长期的实践证明,Code Review能带来的好处有:
不管客户有多忙,也要定期让客户确认自己的期望是否得到满足。在签订合同前,要跟客户达成一致:Showcase的地位不可动摇。
Showcase就是给客户演示我们上一个迭代已经完成的功能,它的宗旨是及时得到客户的反馈,确认团队的产出是否满足客户的期望,降低需求变更返工的风险。
Showcase从项目开始时周期性地进行,并直到项目交付。这个时间间隔是基于团队设定的迭代周期,我们团队是两周一次。团队跟客户安排一个远程会议(如果是在客户现场,一些参与讨论效果更好),主要涵盖了以下内容:
Showcase的目标是客户,需要针对不同的客户有不同的策略。如若客户觉得每两周一次过于频繁,团队可以变通调整迭代周期,通常建议的是1~4周,不宜太长,太短也没什么效果,至于如何权衡这个时间,有两点可以参考:
试想一下传统瀑布开发模式下,一个功能的演示通常安排在在某个里程碑节点,此时项目或许开展了半年或一年甚至更久,客户这个时候见到自己的系统,简直会惊叫起来,原来这压根不是他们想要的东西(因为客户一开始都不知道自己要什么),即便开发团队严格按照预先的设计文档。这是一种时常发生的灾难,它导致大量的浪费,且很难挽救。
敏捷开发可以规避这种灾难性事件的发生。而Showcase在敏捷开发中是一个不容忽视的环节,它契合了敏捷宣言中的拥抱变化优于遵循计划。Showcase能够让团队在每个迭代完成后及时从客户那得到反馈,对变化做出快速的响应,避免了劳动成果的浪费以及方向的偏离,也能最大化让客户的期望得到满足。
为了达到更好的Presentation效果,Showcase通常提前准备一个总结性的Slide来引导整个过程的推进,结束后该Slide即为产出的一部分,另外也会有一封总结性的邮件来跟踪记录Showcase的结果。
没有CI的项目开发是在耍流氓。CI在Agile中是一项最基础的设施,它通过自动化来提供有效的反馈机制以及高效的部署,大大降低代了码集成和项目交付的风险。
CI,持续集成。在敏捷开发中,它是一个项目开始前必须搭建起来的基础设施。当代的软件开发项目中,几乎没有项目是只有一个人在开发的。超过一个人就形成了团队,每个人同时并行开发不同模块的功能,这就涉及到代码的集成,所以代码集成是几乎所有开发团队都要面临的问题(一个人的开发项目不在本文范畴中)。
持续集成跟团队开发人员独立开发没有冲突,相反,借助一些工具(, ,),它能快速的对我们开发人员提交到代码库的代码作出反馈。开发人员每天都在代码库提交代码,版本控制工具(比如)在提交前必须更新代码库最新的代码(解决冲突,代码合并,应用更改),然后将代码提交到代码库中。这个过程是代码集成的第一步,最重要的是如何确保这些集成是可靠的,以下是一些关于CI的良好实践:
通过这些实践,CI能带来的价值也是相当可观的,主要体现在五个方面:
可以借助一些工具,比如Chrome插件可以将CI的多个Pipeline集中展示出来。
团队专注于交付目标,埋头干活的同时,也要懂得停下来总结过去,并更好地抬头看路。
Retro是Retrospective的简写,即回顾。团队通常以回顾会议的形式进行,大家坐在一起,对过去的这段时间里,我们Team的工作状态(团队合作,技术实践,团队氛围等)做一个总结,它有一点基本思想:对事不对人,大家思想自由Open。如何做到这一点,下面是我们Team的实践:
说得天花乱坠,没有行动,犹如竹篮打水。Retro这个环节最核心的产出物是Action,团队共同一致商量出来的措施,有没有效果就在于行动了,所以Action分配了Owner之后,一定要跟踪这些Action有没有落实执行。一方面,需要Owner拥有高度的责任心和执行力,尽职将这些Action落实执行。
Retro的细节因团队而有些差异,而它的理念是一致的:总结过去,做的好的方面继续保持及加强,做的欠佳的方面一起讨论改进措施,并尽全力落实。Retro让团队在实践中摸索出适合团队的最佳实践,引导团队和个人不断自我完善,追求卓越。
敏捷开发实践不只是拘泥于这些流程形式,在形式背后,我们应该深入思考这些实践是否减少了浪费?是否促进了高质量的交付?每个团队都是不同的,不必拘泥于这些流程形式,而是要追求这些流程产生的真正价值与意义。