最近面试了几家公司,感觉大家对采纳Scrum流程还是挺感兴趣的。5年前,我翻译了《代码之道》这本书;其中,第二章有一篇文章谈到了敏捷方法。文章的后半部分还对Scrum做了重点介绍。作者原是微软员工,他的一些观点和建议难免会结合微软公司的实践,但总体上来说,他的观点公允,值得大家借鉴,因此也可以算是不错的入门读物吧。(只是我有点汗颜,因为现在重读这篇文章,感觉我当年的翻译确实有点生硬……)
以下是正文:
我很难做出判断。也许你可以帮我。我不能断定谁更恶心:一个是使用“敏捷”方法,并且想知道为什么微软不在全公司范围内采用它,用它解决我们面临的所有麻烦的人;另一个是认为敏捷狂热归根到底是被一些无知的学者鼓吹出来的,它实际上是一种改头换面的愚昧,它让开发者免于任何责任的人。我只能掷一枚硬币来决定了。他们两者的言论,都会使我肚子里有一股作呕的感觉。
现在让我们来纠正这两种观点:
1. 如果你认为敏捷方法解决了我们产品开发过程中的所有错误之处,那你真是个白痴。雇用成千上万个人来开发高度复杂、深度集成的软件给上亿客户来使用,这不是件容易的事。这世界上没人比我们对这个任务知道得更多,包括敏捷联盟的那些聪明家伙。并不是我们现在做的所有事情都是错的,也不是所有事情都能用敏捷方法来满足我们的需要。
2. 如果你是极端的反敏捷人士,你认为Scrum是a System of Clueless Reckless Untested Methods(一个毫无头绪、不计后果、未经试验的方法系统)的缩写,那你也是个白痴,而且更加无知。不假思索就随便以什么理由妄加否定,本身就是带有偏见而不职业的做法。像敏捷这样的草根运动总是有一些事实基础的,它可以使我们的团队和客户受益。那些概念可能并不总是直接适合于我们的业务,但当你停下来去理解它们的时候,那些事实基础总是有一些用武之地的。
作者注:敏捷在微软整个公司范围内,真的就是由一小撮人和一些小团队牵头的一次草根运动。
是时候来破除关于敏捷方法的传说了。我还将解释如何去使用这些方法背后的创新思维,以构建我们自己的优势。
真理的敌人
首先,让我们来破除下面的这些敏捷传说……
传说之一:敏捷就等于极限编程(结对编程、Scrum、测试驱动开发、用户素材、或者其他敏捷方法)。敏捷方法实际上是软件开发实践的一个集合,这些实践共享公共的一套原则定义,但除了原则之外其他方面都不相关,有时甚至还是对立的。你可以从敏捷联盟(www.AgileAlliance.com)了解到关于敏捷的更多真实信息。
传说之二:敏捷方法不适合大型组织。这种说法很荒谬。敏捷是包含很多各不相同的方法的一个集合。这些方法中有一些不适合大型组织,但有一些适合,还有一些如果你创新一下的话也可能适合。在做出一个空洞的结论之前,你必须带着问题去研究具体的方法。
传说之三:敏捷方法可以用于大型组织。敏捷哲学崇尚“客户合作胜过合同谈判”和“响应变化胜过遵循计划”。跟1亿多个客户合作是艰难的。合同谈判在跨团队依赖性管理方面是至关重要的。(参见第8章的“要么听我的,要么走人”栏目。)遵循计划对于商业承诺来说是必要的,因为合作伙伴在上百万美元面前会变得难以相处。在大规模项目上应用敏捷方法,要求你灵活而创新地去处理好这些问题。
传说之四:敏捷意味着不写文档。敏捷哲学崇尚“可以工作的软件胜过面面俱到的文档”。很多敏捷的狂热者看到这个就认为,“啊,不需要文档了!”如果你认为走廊的尽头也就是世界的尽头的话,那你也不该得到在你的围墙之外产生的大量收益。敏捷哲学申明了,“虽然右项也具有价值,但我们认为左项具有更大的价值。”换句话说,可以工作的软件比文档更重要,但必要的文档对客户、合作伙伴和跨部门的依赖方仍然是有价值的。
传说之五:敏捷意味着没有前期设计。敏捷哲学崇尚“响应变化胜过遵循计划”。 很多敏捷的狂热者把这误解为,“没必要思考或做计划,设计到时候将突然出现!”突然从哪里出现?一个放射性污水堆积处吗?这里的要点是说,响应变化胜过过分死板地遵循原来的计划,而不要纵身跳下悬崖之后再去看会有什么后果产生。
传说之六:敏捷意味着没有个人责任。敏捷哲学崇尚“个体和交互胜过过程和工具”和“响应变化胜过遵循计划”。很多管理者看到这个感到很恐惧,认为这个意味着完全没有责任可言。实际上,敏捷在这个领域收到的效果恰恰与管理者担心的相反。敏捷使个体对团队负责,而团队对管理层负责。责任性大大地加强了,并且额外的间接层次让敏捷团队更加有效、有韧性、并且名副其实地“敏捷”。
传说之七:Scrum是个缩写词。这是个很无聊的传说,但它几乎让我发疯。Scrum是最有名的、并且实践得最广泛的敏捷方法之一,但它绝不是一个缩写词。Scrum是根据橄榄球术语来命名的,代表比赛双方的团队聚在一起,两手呈圆形闭止,准备争球。它也是Scrum团队每日例会的名字。在微软,我们已经使用了一种类似Scrum的方法达数十年,比这个术语出现要早得多。Scrum是最简单的敏捷方法之一,也最接近于微软的很多团队在现实中采用的方法。后来,更多的团队转向了Scrum。
拨乱反正
抽象地谈论敏捷只会招来漫无边际的争论,但到应用它的时候,却是实实在在的行动问题了。我们已经知道,敏捷实际上是软件开发实践的一个集合,问题是,“哪种方法适合在大规模项目中应用呢?”很多人对这个问题已经思考过或者撰稿论述过,但没有很多人写这样的栏目。在我给出我的观点之前,请看下面的几条基本规则:
1. 能不变就不变。如果一个团队已经在业务看重的各种度量上表现得很好,那就没有必要再改变了。改变总是有代价的,哪怕它的结果可能会很美好。你改变的目的只能是为了在最后获得改进。因此如果不需要改进,也就不需要改变。
2. 不要走得太远。如果改变是必要的,也不要一下子改变所有的东西。让功能团队每次只挑一两样改进,并且留意它们的进展状况。不是所有的团队都要一起改变,也不是所有的团队都要做相同的改变。当然,如果你改变的是一个像建造系统这样的中央服务,那么所有的团队最终都必须接受它。但即使是这种改变,我们也可以选择让它对个体团队是公开还是察觉不到。推荐的方法是:一点一点尝试,一点一点学习,循序渐进。
3. 区分项目级别和功能级别。人们感到困惑最大的地方——尤其对于敏捷方法——是在项目级别和功能级别上的差异。在项目级别,团队之间需要严格的日期和协议约束。在功能级别,其实没那么多讲究。很多管理者都不能理解这个奇异的概念——你的团队能够达到你想要达到的任何日期,问题只是你最终决定在这个日期之前做多少功能而已。只要项目级别的计划能够被跟踪和控制,你的功能团队应该选择任何能够让他们工作得最有效率的方法。
作者注:这一段像是一个电池组。值得注意的是:当组织中的几个小团队使用相似的方法时,通常这个组织会工作得更好。这些方法不需要完全相同,但如果团队步调一致的话,他们会在一起工作得非常好。否则,因为团队之间的预期时间各不相同,他们之间的协调和沟通就会变得一团糟。
准备改变了吗?
现在你想尝试敏捷方法了。但也许你只是想安抚一下部门里的那几个敏捷疯子,在他们喝着催眠的Kool-Aid饮料时,给他们送上一些Scrum“小吃”。那么,你应该尝试什么呢?你又怎样才能把它最好地集成到正常的工作中去呢?眼下有大量的敏捷方法可供选择,因此我在这里只能谈一谈最流行的那几个:Scrum、极限编程、测试驱动开发、结对编程、用户素材、重构和持续集成。
译者注:Kool-Aid是美国本土的饮料,里面含维生素C,是美国人在成长时最喜爱的饮品,不含咖啡因,口味多变。
首先,有两个方法在微软我们已经用了10几年了,它们是“重构”和“持续集成”。重构只是简单地重新组织你的代码,并不改变它原有的功能。重构用来将复杂的函数(面条代码)打散,或者在现有代码的基础上增加新的功能,比如把一个只能读取CSV文件的类改造成一个抽象类,以便能够同时读取CSV文件和XML文件。持续集成的想法是,让新代码总是集成到定期的(理想情况下是每天)完整建造中去,以便所有人都能对它进行测试。
译者注:面条代码(Spaghetti Code)是一种经典的反模式,用来形容看上去很乱、几乎没有软件结构的一段程序或者一个系统。
让他说话
其次是“用户素材”,它们就像是应用范例和功能的单页规范书的组合。用户素材的想法是,为特定功能的实现和测试提供刚刚够用来评估的信息。
用户素材比较麻烦的是,它们应该是由用户来创建的。很多敏捷方法假设用户经常就坐在功能团队的旁边。不幸的是,当你有1亿个目标用户时这就成了问题。
不管你喜不喜欢,我们需要用户代表。像市场、产品计划、用户体验、销售和支持部门都可以充当这样的角色。他们的发现可能被写入价值主张和远景文档,而远景文档恰恰就是基于大范围的用户调研基础上的。然而,当那些宽广的远景和端到端的应用范例被分解开来的时候,我们在功能级别上仍然能够使用用户素材的概念,提供刚刚足够的文档信息,用来对一个功能集合的实现和验证进行评估。
你完善我
“结对编程”是指两个人共享一张桌子和一个键盘,在一起编码。它的想法是,当一个人在打字的时候,另外一个人的视野更为宽阔,可以发现不理想的设计或实现。这一对人常常交换角色。虽然两个脑袋比一个脑袋工作得好,但他们同时也花出了两倍的开销。我更愿意看到把这种双份开销用在设计和代码审查上面,这样价值会更高。然而,结对编程在新代码库的培训上面效果显著,这时通常把一个熟悉代码的人和一个不熟悉代码的人结成一对。
除了重构和持续集成,“测试驱动开发”(TDD,Test-Driven Development)和Scrum已经被证明是在微软应用的最简易、最有效的敏捷方法。我在我的栏目中描述精益工程的时候(本章的第二个栏目),关于测试驱动开发我是这么论述的:你首先为一个类定义它的功能和函数,然后给公共函数编写单元测试,再然后才是写实现代码。这是个反复的过程,并且每次都只写几个单元测试和一点点代码。这种方法让开发者在做最少量的、但又是高质量的实现设计的同时,得到了他们想要的覆盖代码的单元测试。因此,测试驱动开发这种方法相当地流行。
先写测试也更有趣。当你先写实现代码的时候,单元测试就成了一种花样翻新的痛苦,而且它只会带来坏消息;测试不能真正起到增强代码的作用。当你先写单元测试的时候,编写代码去适应测试会比较容易,而且当测试通过的时候你的心情会非常愉悦。
测试驱动开发可以和结对编程组合起来使用:一个开发者负责写一些测试,另一个负责写足够的代码来通过这些测试。他们两个的角色还可以常常交换。最后,测试驱动开发让开发者对“什么时候才算是真正完成了实现”有了清晰的认识。也就是,当所有的需求都有测试,并且所有这些测试都通过的时候。
有点极端
“极限编程”是一个完整的开发方法论。它把用户素材、结对编程、测试驱动开发、重构、持续集成和另外一些实践组合在一起,非常适合应用在跟客户紧密合作的小团队中。
极限编程大量依赖团队知识,以及与客户之间的直接交互,而且几乎没有文档。如果你的团队是独立的,并且你的客户就在你的走廊边上,这种方法会很有效,但在微软这种现象并不普遍。如果我们不能每年赚到数10亿美元,我们的形势就会很悲惨。然而,就像我已经说过的那样,极限编程中的很多单个方法在我们的产品开发中应用得非常好。
准备玩橄榄球!
最后我将讨论的(可能也是被人误解最深的)敏捷方法是Scrum。人们可能把Scrum和极限编程(它实际上不用Scrum)混淆在一起,也可能认为敏捷就等于Scrum(哈?!)。除此之外,Scrum最令人困惑的部分就是下面这些相关的术语了:Scrum大师(Scrum Master)、急待完成任务清单(Backlog)、burn-down图、冲刺(Sprint),甚至包括猪(Pig)和小鸡(Chicken)——这些足以吓跑任何一位管理者。真是极大的误会啊!
无论好坏,Scrum是由一个喜欢有趣名字和故事的人发明的。实践本身既不复杂,也无争议。因此,除了重构和持续集成之外,Scrum是多年来我们内部一直在做的、最接近于敏捷方法的一种实践,并且我们还有一些重大的改进。
接下去,让我们先来澄清那些令人困惑的术语。“Scrums”是指每天的例会,“Scrum大师”是指功能团队的组织者,“急待完成任务清单”是一些功能或者工作条款的列表,“burn-down图”用于展示剩余的工作,“冲刺”是指小型的里程碑,“猪”和“小鸡”则是指企业家的农场动物(故事很长,但很好笑)。
这些概念没有一个是新创出来的,但Scrum的确带来了一些大的改进:
*** Scrum的每日例会组织得非常好,用于收集有用的数据。团队的组织者(Scrum大师)简单地问所有的团队成员3个问题:从昨天到现在完成了哪些工作(并且花费多久时间),现在到明天到来之前准备做什么(并且告知剩余的工作量),什么正阻碍着工作的进展。
作者注:跟踪每个任务完成所花费的时间,是我的团队对微软的Scrum作的一点小小的贡献。通过把这些信息加入到burn-down数据中(还剩下多少工作量),你就可以画出美妙的累积流线图,度量花在进展中的任务和工作上的时间,并且更好地估计团队的生产力。典型情况下,产品团队花在任务上的时间大概为42%,花在沟通上的时间为30%,拿我来说,我花在一起协作的功能团队上的时间有60%之多。
*** 在Scrums会议上收集到的数据被输入到一个电子表格或者数据库中。基于这个电子表格,你可以分析花在任务上的时间、完成日期、进展中的工作、计划变更和许多项目问题。这种情况下最流行使用burn-down图——一种展示时间和总剩余工作量之间的动态关系的图表。
*** Scrum大师是一个独立于团队之外的力量。他甚至最好不是组织中的一员,但这通常不太现实。Scrum大师有权利排除阻碍每日例会进程的因素,保持会议的简短。
*** 功能列表或者时间表称作为“产品任务清单”(ProductBacklog),而工作条款列表或时间表称作为“冲刺任务清单”(SprintBacklog)。通过分离这两个列表,管理层可以关注在他们想要完成的工作上(产品任务清单),而团队则关注在手头的工作上(冲刺任务清单)。为了保证所有事情都在正常的轨道上,Scrum大师一般每周跟管理层开一次会(比如每周的主管会议),进行状态更新。
*** 冲刺作为小型的里程碑,它的时间长度是固定的。当时间用完了,一个冲刺也就结束了。典型情况下,一个冲刺大概30天。(译者注:其实,Scrum推荐的Sprint周期为2~4周。)
*** 每次冲刺结束后,功能团队会跟管理层一起复审工作(不错的改变,哈?),总结本轮冲刺做得好的地方,以及下轮冲刺需要改进的地方(这总比等上1年或者10年、产品最终出货后再做总结来得强),然后为下轮冲刺制定计划并重新估计工作条款(改变原先的计划和估计?决不!)。
通过使用每天、每周、每月的反馈机制,Scrum允许团队在一个多变的环境中保持高效的工作,并且富有弹性。通过收集一些关键数据,Scrum允许团队和管理层知道团队的运作状况,在问题还没有成为问题之前就把它解决。通过分离管理层掌管的功能列表和功能团队掌管的工作条款列表,Scrum允许团队自我指导、工作更加投入,使团队内的每个成员和团队外的管理层都很有责任感。
最后你要知道的
不是所有的敏捷方法都适合于每一个人。很多根本就不适合微软的大型项目。但Scrum、测试驱动开发、重构和持续集成可以被很多微软的团队使用,并且会有显著的效果。结对编程和用户素材的适用程度要低一点,但如果条件适宜的话,应用这些方法也能很有效。只要你不是心急、一下子走得太远,或者强迫你的团队采用敏捷,应用这些方法定会有大量收获的。
作者注:几乎在我任职过的所有地方,我都见到过有管理者强迫工程师改变他们的方法论的情况。这绝对行不通,哪怕像Scrum这样很受大众欢迎的东西。管理者可以建议、支持、资助行为方面的改变,但绝对不要强制。
如果你想作更多的了解,请在我们的内部网络或者互联网上搜索敏捷方法。同时也请留意2006年春天即将开设的关于敏捷方法的新课程。如果你的团队方方面面都表现得很出色,那建议你不要做任何改变。但如果你希望看到一点更高的质量,或者更好的基于功能团队的项目管理,你自己思量一下是否要采取一些行动,尝试一下敏捷方法。