敏捷开发“松结对编程”实践

  传说中的结对编程,大致结构是两个人共用一台电脑,一个开发,一个测试,以随时评审来抵消返工时间损失。

  传说归传说,谁也没有见过。问题出在哪里?有两种主要原因。

  一是来自高层的,高层感觉两个人只有一个人干活,实在是有点浪费。“评审抵消返工时间”虚无缥缈,但每天只有一个人干活却是现实情况。

  二是来自基层的,两人若有高低,高手肯定觉得还不如我一个人干的快;两人若旗鼓相当,难免产生争执。

  其实在我们身边一直有一种方法很像结对编程:“师徒制度”,就是每个新人来到公司,都指派一个师傅带着,在技术与业务方面提供指导。他们既不用一台电脑,也不是老死不相往来,这其实就是一种“松散”的结对编程。只不过多数企业虽然有这种制度或实践,但却很少有很清晰的定义,难免限制了这种实践的效果。本系列的目标,就是从人员结构、计划实践、日常工作实践、绩效考核等各个角度,来完整地思考和建立这种制度。

  挑选小组长(师傅)基本原则

  乐于助人,有责任心,善于沟通,擅长管理,技术精湛,业务精通……很可惜,好词汇越多,越难找到符合的人。不过,一些基本原则还是要考虑的:

  1. 尽量找对业务有兴趣的人

  整体上偏业务的人未来有更好的发展(这是我2001年的上司的原话,事实证明很对),由于有行业壁垒也较少跳槽。由于小组长角色未来将被提拔为更高的项目经理、产品经理,对业务的了解也会为此做好铺垫。

  2. 尽量找善于沟通的人

  善于沟通的程序员成长更快(还是那位上司的原话),也更能帮助别人成长。

  挑选组员(徒弟)基本原则

  1. 徒弟能力一定要低于师傅(应该说:师傅一定要高于徒弟)

  很常见的一种做法是把几个水平相当的人放在一起工作,认为这样他们可以互相学习,其实不然。

  之前我们在的项目组经常发生技术“争论”,发生的次数多了,我们发现一个规律:每次争执不下的,都是两个技术相当的人,而每次争执的解决,都是一个水平更高的人给出一个截断众流的方案,然后大家散去。

  2. 徒弟年龄不要太大

  如果有两个水平相当、月薪要求都是6000的程序员,当然找年轻的了,有发展潜力,后劲足。

  挑选组长(大项目经理)基本原则

  1. 项目经理必须喜欢业务胜过技术

  项目经理是掌舵的而不是干活的,因此必须对业务有深刻理解。

  2. 项目经理最好精通技术

  这里不讨论是否存在“不懂技术却精通管理”的项目经理,但是如果目标是项目成功而非证明奇迹的确存在,项目经理应该首选那些从小组长成长起来的既懂业务技术又精湛的人选。

  这里的“精通技术”不是从技术实现层面考虑的,而是从“技术想象力”层面考虑的,就是说他必须能想象到有某种技术存在。比如以前我们遇到一个程序员写了一大堆重复代码,原因就在于他的想象力受到了局限,明明有虚函数、模板等各种方法来简化代码,却没有想到。“没有学到”是无法避免的现实情况,但“没有想到”是可以避免的。

  团队结构和运行理念

  既然待在某个“位置”上,每个人必有不同的职责。这里就不一一列出了,因为猜都猜得出来(比如师傅要带徒弟之类)。下面只列出松结对编程与一般小组的核心差异。

  1. 对每个小组(师傅+1~3个徒弟)整体考核

  也就是师傅要负责到底,不能出现“他刚来所以把事情办砸了”的情况。这里的负责到底,包括计划、估算、跟进、进度、质量、徒弟成长……等一干事情,本系列的其他文章中都将展开描述。

  2. 在工作中学习

  尽管“松”,但还是“结对编程”,学习和指导过程实在生产过程中集成的,因此师徒关系的成败不只是人员成长,还包括任务和项目的成败。这首先是一个生产团队,其次才是学习团队。

  新人其实很少偷懒,因为一方面正处于入门学习的高峰期,另一方面工作时间不长,需要得到企业和团队的认可。可为何他们工作总是不得力呢?

  新人的真正问题在于无心办错事和好心办错事。

  无心办错事包括没学过某种好的方法、不知道企业已经有某些可用代码或库、不懂业务等种种问题。

  好心办错事包括想做一个比领导想想的更好的功能、过度思考了可复用性可维护性等。

  这两个问题笔者都经历过(作为新人和老人),“避免”是最好的方法,而不是事后改正,这就需要在设计阶段和计划阶段从技术、管理两个方面来提前预防。

  技术:轻量级设计

  如果要把一个任务分配给一个“不放心的人”,有两种办法保证成功:师傅把设计做出来交给徒弟做,但是“设计文档”的详细程度很难把握,写少了做不出来,写多了等做出来了很多内容又多余了;师傅徒弟结对编程,但是很占用师傅的时间,尤其是倘若徒弟“实际上”(可惜只有上帝知道)完全可以胜任这个任务。

  有两种解决方法。

  1. 事前轻量级设计:预想陈述(有点隐喻的意思)

  预想陈述是微软很久以前就使用的一种方法,任何人(不只是徒弟)有什么设计,不用写下来因为太费时间了而且还可能被抛弃,而是给大家讲一下。大家会给出评价和意见,以保证其正确性。然后此人就按这种方法去实现了,倘若成功了也被认可了,就简单写下来以供日后参考使用。由于系统已经存在,这个简单写下来的设计可以真的很简单。

  在“松结对编程”里边,有两种类似的做法。

  一种是师傅把自己的想法告诉徒弟(一般用一个白板,或一张白纸),徒弟提问师傅回答,到差不多为止。

  二种相反,徒弟讲给师傅听,师傅师傅质疑和指导,到差不多为止。

  两者都不要事先形成永久文档,但都在被证明可行(就是编码完成后)写一个简单文档记录。任何代码之外的能帮助理解当时做法的文字/图片都可以称为文档,没有字数限制。如果能和用户故事放在一起则更好,一个描述做了什么,一个描述怎么做的。

  2. 前检查点

  就是在某事开始的时候进行临时结对编程。一般发生在某个功能刚开始做的时候,详情会在之后的“日常活动篇”做详细描述。

  管理:共同计划(共同估算,扑克牌估算)

  预想陈述、前检查点虽然已经很轻量级了,但是如果师傅和徒弟都刚刚对需求(用户故事)有所了解,还给不出很清晰的思路的时候,比如在Scrum计划会上,怎样快速知道徒弟有没有理解需求,有没有大致的实现思路呢?那就是共同估算(扑克牌估算是共同估算的一种最好的实现形式)。

  1. 共同估算

  共同估算的原理和做法还是很复杂的,这里只简单说说,以后会有文章详细讲述。

  共同估算就是师傅和徒弟基于相同的信息(一般是在计划会上听PO讲完故事的时候),一起说出自己认为做完这件事情需要多久。基本原理是:若两个人对某件事情的工期认识是相同的,那么他们的实现方法不分高下,用哪种方法都差不多。

  为了防止人云亦云,一般需要采用匿名方法,而扑克牌估算就实现了高效有效的共同匿名估算(另有文章详述)。

  2. 验收标准

  为了基于相同的目标建立共同估算,也为了防止需求镀金或最终软件不能满足需求,师傅和徒弟要建立对需求的共同理解。

  简单方法就是两者(其实是师傅和多个徒弟)一起参加估算会,一起听PO讲解故事。但最好是在此之后,建立一个“文档化”的验收标准。比如在一张故事卡/Excel表里……上写上“需集成;无性能要求……”等最简单的描述(请参考本博客的敏捷开发分类下一片关于验收标准的文章)。

  共同估算+验收标准,使得师傅和徒弟(推广为高手和新手)使用大致相同的方法,做大致相同的东西。共同估算既是一个工作的过程,也是一个学习的过程,因为在理解做什么和怎么做的同时,徒弟也向师傅学到了东西。

  估算是经久不衰的管理话题,大致分为两种流派。

  第一种是领导指派,领导说这是10天的活,就必须当是10天的活来干,如果干不完,可以用加班、损失质量、功能缩水等各种方法曲线救场。另一个变种是大家自己估算,但是交给领导审批;领导审批其实就是砍一半的过程,还好大家之前就已经加了一倍,所以不怕。

  第二种是自我管理派(偏敏捷),就是由具体开发的人员自己说开发工作量,领导和他人不干预。尽管“自组织”了,但是领导深以为这种方法留下了偷懒的种子,而队员也觉得某人的估算很不靠谱(太长或太短),到底怎么办呢?共同估算吧。

  基本概念

  假设现在是一个计划会上,PO(产品经理,策划组长,项目经理,某销售……)刚刚讲完需求,下一步不是交给某人做估算,而是交给某个潜在的组(师傅+1~3徒弟)。

  由师傅带头打牌,对,在计划会上玩扑克:

  1. 大家各自思考可能要花多久时间完成任务,扣一张牌出来;

  2. 师傅喊开牌,大家亮牌,比较大小;

  3. 一般最小和最大的两个人PK,说出自己的观点,大家一起讨论;

  4. 差异无非来自于两个方面:做什么,怎么做;PO参与讨论回答做什么的问题,师傅和徒弟们讨论解决怎么做的问题;

  5. 讨论过后再来几轮,直到大家觉得结果差不多了。

  扑克牌估算的匿名性和开放性保证了大家不会人云亦云,也不会因为缺少沟通而难以达成一致。

  笔者的经验是一局扑克牌估算大约持续1~5分钟,还是很快的。偶然有黄庄的,一般都是因为PO那里回答不了做成什么样子,某某附加功能是否也要做……等等问题时。

  几个问题

  1. 为什么分给组而不是个人?

  不分个人就打牌使得每个人都不得不思考,因为怕出错了牌又说不出所以然。这样即使日后他不做这个功能,也对这个功能很了解。

  2. 为什么不让最后领任务的人自己估算?

  因为他很可能因为不知道某代码可用、不知道某软件不行、不懂template(我们因此扔过1个人月代码)……而选择了错误的实现方法。

  3. 为什么不让师傅估算大家采纳,他不是最厉害吗?

  师傅的想法常常是徒弟们理解不了的——比如为什么不留在女儿国而偏偏去西天取经之类的,呵呵——共同估算就是让大家在思考中对照自己的实现方法和师傅差异的过程。

  4. PO怎么还参加?不是不让别人干预吗?

  很多问题比如在游戏中“显示武林排行榜”,具体工作量可能不在于怎么做而在于做什么:凭什么排名?排多少名?实时排名还是每周排名?怎么显示排名?……因此PO不能写出一堆文档,然后以不便干预估算为名不参加敏捷计划会议。

  PO可以挑战估算,比如:“这真的要这么久吗?我记得上次……”但要有理有据。其实实践中更容易看到的是,团队往往过于激进乐观,PO反而要让他们意识到完整的需求和要求,做出更现实的估算。估算不准确,PO也有责。

  5. 一直无法达成一致怎么办?

  其实估算不是为了最后那个数字,而是弄清楚做什么和怎么做的问题,如果这两件事情清楚了,但结果却是偏偏有人说4天有人说6天,随便取个数就可以了(事实是应该按墨菲定理取6天)。有师傅在,一般很少会就实现方法争执不下;有PO在,一般很少会就要实现什么争执不下。

  不排除有特殊情况比如PO发现自己也没想过排行榜凭什么排行,那么就应该搁置此用户故事;又比如大家觉得如果数据库给力可能实时排名也行但又拿不准,可以暂时搁置到开发的时候再说,但把故事上标注一下“若需要每周自动排名+1天”。如果经常黄庄,Scrum Master要分析总结避免。

  6. 四个人出牌不同,师傅先说还是徒弟先说?

  想起个脑筋急转弯:科学家 医生 士兵 护士 ……等等一群人在飞机上,飞机结冰快坠落了需要有人(可能不止一个)跳下去,问谁跳?答案是从体重最重的人开始跳,因为可以少跳几个。

  因此我们是出牌数字最小的先说,和师徒无关。因为他极有可能掌握最佳实现方法。如果后来发现不是如此,请参考下一条。

  7. 都有什么理由可陈述?

  按下面的顺序,越靠前的越接近真理,感觉自己接近真理的就一定要举手先说,马后炮招人嫌:

  经验事实:我以前做过……咱们有个类库……那个方法我试过不可行……

  蛛丝马迹:谁还记得上次……听说隔壁……与上回相比……你以前不是……

  逻辑推理:理论上说……我觉得……

  几个注意事项

  1. 小组内不要有强分工,否则大家会缺省认为肯定是某人的工作。

  2. 师傅不要太抢眼,要通过估算鼓励徒弟思考,同时也掌握徒弟的真实水平。

  3. 师傅不要太较真,编程规范、易用性、易维护性这些纪律不能放松,但如果徒弟想尝试一种不同但工作量也差不多的方法,可以适当鼓励。

  4. Scrum Master监控整个过程,防止太细/争执……等问题。

  5. PO必须参加。

  团队中常见的一种情况计划、估算、设计的时候大家还在一起,但编程的时候就会分开。分开看似是安全的,但是却充满隐患。

  2001年,一位招聘考试前三名(一共120员工)的程序员的两个月的成果被彻底放弃重写,原因是里边包含3000多个常数,而且很难修改(码流参数),重写的人座位距离他只有4米,重写也只花费了2周;2002年,一位月薪7000(那时候北京房价才3000多)的程序员编写了一个月的4000多行代码,在一个下午被重写为50多行,座位距离他只有5米的项目经理疑惑加惊讶地问:“你真的没学过c++ template?”。

  这就是团队的距离,即使是高薪聘请来的程序员也难免犯错。难道我们只能避免下一次问题发生,而不能避免这次问题发生?

  前检查点

  前检查点就是在做某功能的最初一段时间,师傅与徒弟结对编程,完成最初最重要的设计。

  “开始做X功能的时候叫我一声,咱们敲定一下具体怎么做。”这个是师傅的前检查点标准语法。尽管在共同估算的时候大家还是略有共识,但是限于计划会的有限时间,徒弟未必真的知道怎么做。在刚开始的一两个小时里边,师傅带领徒弟一起把基本的结构理清楚,最好写上一些基本代码,让徒弟有一个直观的概念。

  在上面提到的2周的重写工作中,重写者和被重写者一起工作了1.5天,重新设计了打包类、递归函数等最难缠的部分;被重写者在剩下的两周里边完成了工作,而且很出色。倘若这一切发生在两个月前该多好。那次事故之后,我们订立了更严格的代码审查制度,所有代码均由部门技术最好的人审查后才进代码库;之后再来的新人,均指派师傅,并由师傅保证其代码质量;将人员划分为需指导的/免于指导的/可指导的/可培训的四级(10年后我在NEC参观交流时发现了几乎完全相同的分级制度)。

  前检查点的工作作用是打下设计的基础,保证工作顺利进行。如果一切按照前检查点的设计进行,徒弟可以继续独立工作,如果有偏离,要询问师傅。

  前检查点的学习作用是显而易见的,师傅平时工作的精华都展示在徒弟面前。而且这种展示是动态的,在结对编程的状态下,徒弟可以完整地看到师傅是怎样入手工作,怎样

  后检查点

  后检查点就是某事做完后,师傅检查一下徒弟的结果,保证达到验收标准。

  曾经分配给我一个刚毕业半年的组员,刚来没多久就经常看到他上网玩,过去一问,原来工作做完了(真的非常快),惊奇之余赶紧看看结果:功能是有了而且实现得也很好,就是总有点瑕疵:要么按钮不正,要么界面上有错字。后来就改成每次任务完成都赶紧喊我去看看,修正后继续下一个。他后来能力超群,在此公司作为“台柱子”10年,现在还在。

  其实多数新人在大学中都形成了“能运行就行”的概念,并不懂商业软件开发的标准。本人也一样,毕业5年还不知道delete内存(C++),每次都是多预留点C盘空间,这样程序就能多运行一段时间,下班之后关机重启就可以了……这样的软件肯定无法在服务器上长期运行的。

  后检查点的工作作用是可用来进行代码审查,以确保软件产品的质量,之后会提到。

  后检查点的学习作用是帮助新人学习商业软件的开发标准,逐步养成好的习惯。

  日常工作

  除了在任务前后的时间点外,日常8小时也应该保持良好的沟通。在一次极端的环境中,我们曾经将其发挥到极致。

  当时我们以很高的日薪临时聘用了两个不错的程序员。他们技术虽然很好,但是却对业务一无所知,也没有提前看过文档。因为总共也没有多少天,当然不能把任何一分钟花费在熟悉业务上,所以……

  1. 每天早上(包括第一天)

  整个软件被大致分为三类功能区,互相关联。组长(我)也自己编程,负责其中一类功能。

  有20分钟的晨会,组长会把一个简单的设计文档的一部分拿出来讲解给两个人,同时指出今天要做的工作要给予其中的哪些内容,他们提问我回答。散会前我们会就没人的工作做一个简单的估算(当年还不会扑克牌估算,太可惜了),确保当日是可以完成的。

  晨会会提到技术问题,而不是每日立会中说的只说进度。但技术问题一般只涉及到要求,比如“做分段计价模型的时候,不要在C++里边做For循环,看能不能在SQL里边解决,如果解决不了来找我”“好,我试试。(或)这可能吗?”凡是有问题的就会稍微深入一点;凡是“我试试”的,都放过,但如果试验的结果不通就必须找组长讨论而不能自行解决。

  小组加组长只有3个人,所以所有人都参加这个20分钟会,包括肯定不做某任务的人,也听组长和别人的讨论。

  2. 每天下午1:30点左右

  就是吃饱饭犯困的时候,组长会分别和大家在计算机前碰头一下,主要是看当日的工作是否可能在下班前完成(坚持不加班);另外就是看是否和晨会上预想的一样。

  其实就算是短短的半天时间,事情就可能有变。有一次其中一个程序员在一上午写了大约4屏幕的代码(一般每天才写这么多),而功能却遥遥无期。原来他不知道有个函数可以快速实现这些功能,正在自己造轮子,他本应该告诉组长所遇到的困难。

  程序员很少在这个时候求助,他们总是相信自己能最终解决问题……因此在转型为自组织团队的时候,担心程序员会偷懒的想法整体上是多余的,更需要预防的是蛮干/过于乐观/激进/需求镀金/消息闭塞/无法互相学习等问题。

  3. 每天下午下班前

  当时6点钟有《七龙珠》(工作场所有台电视),两位对此都很着迷,所以我们基本到点就看片,看完后散伙回家。

  因为也不能让电视台调整播出时间,基本上下午5点就要开始打扫战场:组长分别找两位,看最终结果是否完成,并做一下修改。同时还要做代码审查(请看下一篇详述)。

  由于估算不会太准确,我们专门把所有三不管的小功能梳理出来,谁提前做完了,谁就找其中一个把剩下的闲工夫占上,结果其中一位几乎包揽了全部。

  4. 晚上

  对,组长晚上还要工作。在他们走后组长会在晚上做个集成,把几个人做的功能合成在一起运行。当时也没有持续集成工具,所以只能手工。

  在正常项目的正常团队中,这个工作应该在第二天的工作时间完成,也就是说或者找专人(或轮流),或者让组长做,或者让自动工具做最好。推荐小组内轮流负责此事,因此可以让大家理解别人的工作、整体的工作,乃至与组外人员的集成工作等内容,为组员成长为组长打下基础。

  5. 随时

  可以已经注意到我们没有“每日立会”,一则当年还不知道Scrum,二则感觉一个3~5人的团队还要靠开会交流实在迂腐。比如在篇首提到的两次事故中,团队都没有少开会,但都因为缺少随时的沟通而导致大错。

  其实任何伸伸懒腰的时间都可以进行沟通。不过一般不要“太随时”,应该以师傅的时间为主,也就是如果徒弟遇到了问题,但可以绕过去先走着,就先来一句“我这有问题,有空帮忙看看”+“好,再过15分钟”。这样既不会让徒弟被卡住,也不会让师傅因为经常被打断而导致无法工作。但师傅可以随时发起交流,因为他们是去帮助徒弟的,聊的也是徒弟的事情,不存在打扰的说法。

  注:上述部分内容仅限于特定环境中,但思路很多时候都是可取的。

  松结对和紧结对不一样,两个人不是总坐在一起随时发现问题解决问题,而是很短时间地坐在一起。其中在后检查点发生的主要事情有两个:一是看结果是否符合需求(做什么),而是看代码是否存在问题(怎么做),后者就是代码检查。

  代码检查(也称代码审查Code Inspection)是一种由来已久但是很神秘的东西,最初引入是在一些生命攸关、重大财产相关的软件开发中,典型的就是SSOS(美国航天飞机的软件),其每段代码都交由6个人审阅,方可入库。成果就是在1989年之前(之后笔者没有数据),SSOS在太空中失效次数只有一次。笔者亲身参与的代码审查活动包括某数字电视CA系统的代码审查(25个程序员只有1个测试,已用于CCTV)、某电信计费系统的代码审查(一周发现2400个缺陷)、某电信运维系统的审查(2天发现200个重要缺陷,其中1个已困扰团队5年)、某航空无损检测系统的代码审查(交付后一年内客户只发生一次失效)。

  代码检查的基本原理就是相信人脑(而非人眼)是判断代码好坏的最好工具,比如如果代码中有一行:if (i == 1001) return die()的错误或非法代码,几乎无法经由测试包括自动测试发现,但肉眼却一目了然。

  笔者曾编写过一个“复杂而彻底”的代码检查培训教材,但后来发现过于复杂而且还不彻底,所以作罢。下面将要介绍的是一种业余但却有效的代码审查方法。

  -----------------------------------------------------------------------

  程序员的质量观

  有人曾把程序员分为四级:编写可用软件(大致是大学在校生的状态),编写可靠软件(大致是好一些的职业程序员的状态),编写精美软件(在简单性/可维护性/可复用性上有所突破),编写思想深邃软件(设计模式、MVC、JQuery及早期OLE、RPC等创始者所做的事情)。

  但在现实中,却往往发现很多程序员停留在第一层次:“你测吧,测出缺陷来我改”“这个不用改也能运行”“这么编就是难读点而已”,师徒间的代码检查,就是把程序员从第一级别向上提高的过程。

  第一段提到的25个程序员+1个测试人员的团队是01年我们所在的团队,当时保持了良好的质量风气。尤其由于大家知道没有测试人员擦屁股,留下缺陷相当于给自己找麻烦,所以大家不得不习惯自己动手防患于未然。这个产品后来发展势头很好,07年曾占据市场60%(之后不详)。

  怎样检查

  “高手本来自己就要开发很多代码,还要替新手检查代码,多花费时间啊……”这是一个常见问题,答案是:“每天,在后检查点,花费不超过15分钟时间,能看出什么来就说什么,时间到了就停。”

  一般而言,大致每天高手能编写100多行有效代码(按分号计数),新手会多一些但也不超过200(他们编写代码比较费时),也就是10个屏幕以内。有经验的人一定知道:高手看新手的软件,5秒钟就能发现问题。

  常存在的一种情况是高手“看不懂”新手的代码,当然不是因为技术太精妙了,而是写得太乱了。但在松结对编程里边不存在,由于师傅徒弟天天在一起,这200行代码可谓一目十行,如果以往一直每天检查代码,那么里边存在的问题应该不会很多。

  检查什么

  这个是重点,整体包括:

  1. 结构问题

  代码最大的问题,不是一两个地方有技术缺陷,也不是业务逻辑错误,而是整个软件编写的不好。前两者都可以通过测试或使用来发现和更正,但后者就不同了。如果回想一下自己见过的各种烂摊子,是不是有同感?具体哪里有问题怎么改说不上来,就是整个软件看上去混乱无章,无从下手。

  具体结构问题包括:重复拷贝代码(不封装函数,不用Template/泛型……),函数过长(超过一屏幕就叫过长),错误封装(不恰当的public/不用Interface/不内聚/强耦合/在类中封装了无关方法……),内容错误(多个无关类置于一个文件/不恰当的命名……)等等。

  改正结构问题,是从编写可靠软件向编写精美软件迈进的重要方法。

  2. 业务逻辑问题

  就是软件是否与需求的要求符合的问题。师傅和徒弟经常对业务需求的理解有差异,借此机会同步一下,必要时引入PO(产品经理/策划人员……)。

  有人会说业务逻辑问题不是一测试就知道了吗?可是测试一般发生在很久以后,有些逻辑测试还需要一定的触发条件,而且测试只会发现失效(failure, 与预期不符)而不能发现缺陷(defect, 具体哪里出了错),等积累长了,谁也找不到原因了。

  3. 编程素养问题

  很多问题属于那种“这样也行那样也行”的状态,比如命名/初始值/缩进/断行……但是高手的做法总是比新手好一些。

  比如bool result = true; 这句话就有问题,刚初始化就先宣布成功,必有隐患。这是一个真实案例,而下面也的确有一个分支错误地返回了这个true(实际案例是个HRESULT)。而发现这个问题,不是测试而是代码检查。实际上测试几乎发现不了这些问题,比如上面那段代码会在某文件打不开的时候错误地返回这个true,而在测试中几乎不会故事破坏那个文件来测试其结果。

  实际使用时,不用拉太长的清单,师傅能想到的看到的告诉徒弟就行。

  徒弟不需要学到天上去,只要能学到师傅那么好就可以了。之前在做CMMI咨询的时候我弄过一些检查表,推广均以失败而告终。那些表都是为了顶级安全性的软件考虑的,在普通项目里边使用是个灾难。

  几个问题

  1. 师傅天天检查,会不会很累?

  检查不全是为了发现缺陷,而是为了提高成长。如果总是发现重复问题,此徒不可教。好学的徒弟有半年时间就能接近师傅了,考虑到师傅一般比徒弟多工作2年,我们因此让一个人加速1.5年。

  2. 不会饿死师傅吗?

  会,也不会。如果师傅止步不前,即使他不教别人,也迟早被人超越;师傅也是需要学习的。事实是会教徒弟的师傅才会学习,而会学习的师傅才会教徒弟。

  3. 师傅跟谁学?

  师徒制度是最底层团队制度(1个师傅+1~3个徒弟左右),其上还有更大的结构和更高的高手。我们之前曾把人员层次设为需指导的(徒弟)/可免于指导的(也是徒弟)/可提供指导的(师傅)/可培训的(团队最高级别的高手),最后一级需要定期与大家分享内容。

  师傅作为高级技术人员,还享有机会外出培训/采购图书等待遇。

  师傅自学也很重要,经验更是不可取代的。前事不忘后事之师,要把自己的经历和别人的经历都当作经验来看待。

  4. 师傅努力编好自己的软件不久已经有很大贡献了,为何要帮助徒弟?

  软件整体是一个串联系统,一个环节出了问题整个软件崩溃(Web软件好一些)。因此软件质量取决于最差的部分,而不是最好的部分。

  代码审查的确会占用时间导致最好的部分变差,但却使最差的地方变得好得多,整体质量因此而得以提高。

  ------------------------------------------------------------

  从工作层面讲,代码检查使得代码的质量尤其是结构质量,整体上保持在师傅可能达到的水平,从而保证了项目的成功。

  从学习层面讲,代码检查使得徒弟可以不断/渐进地学习,从而花费远远低于师傅的时间成本达到更高层次。

  心态是其中的关键。徒弟不能因此而觉得有一个后盾了可以放任存在问题等师傅发现,要珍惜师傅的时间,也要利用师傅的时间每次都学不同的内容;师傅也不能觉得徒弟学会了对自己是个威胁,威胁时刻都在,不来自于自己的徒弟,也会来自于别人的徒弟,唯有自我提高。

  至此所有实践层面的内容基本上都写完了,下一篇将提到一些“139团队”的问题,所谓“139团队”就是一个使用松结对编程工作方式的大型团队。

  松结对编程是小型团队的实践,大约运行在1个师傅+1~3个徒弟的尺度上,当面临更大尺度的时候,就需要大型团队模型。这里推荐139团队模型,因为它不但可以让松结对编程运转顺利,还解决了大团队沟通、绩效考核、师傅的出路等问题。

  139团队的整体情况相当复杂,将另有系列博文描述,这里只描述与“松结对编程”相关的内容,以保证本系列博文的完整性。

  基本概念

  139团队就是1个项目经理,3个师傅,9个徒弟的简称,当然实际上未必正好凑够13个人,也未必正好每个师傅都有3个徒弟。

  在第一篇里边已经提到过三个层级的工作关系,下面是一些深入的剖析。

  绩效考核

  绩效考核历来是软件业最头痛的问题,按代码行考核吧新程序员写的垃圾代码比高手多,按任务数考核吧任务大小不一,按功能点考核吧多数人不会数,按工作按时完成率考核吧师傅还帮不帮徒弟了?……139团队大致有个答案:按1-3-9的层次安排大致薪金和奖金比例(在139团队系列中有详细分析)。

  139团队认为绩效考核首先是团队的整体绩效;在分解到个体时,不是看具体每个人干活多少,而是看在团队中所起的作用。

  所以,想加薪?带徒弟吧。不过有一点,带一队没用的徒弟是没用的,首先要有团队绩效,才会有个人绩效。

  人员招聘

  人员招聘一般在较高层进行,最低也是项目经理,但是最终带新人的却是师傅。所以招聘的时候应该请未来的师傅也在场,部门经理/项目经理可以问师傅“这个人给你当助手,你觉得够吗?”这个问题我最近正好问过,师傅的话语权很重,因为如果他不喜欢,下面的配合会很难。如果是招聘师傅,项目经理心里要对此人和现有师傅水平的高下比较有个概念,尤其是沟通和教学能力。

  师徒的差异既不能太大,也不能太小。太大学不明白,白耽误师傅的功夫;太小没什么可学,还可能引发冲突(经常半斤大战八两,如果其中一个是二两就打不起来了)。如果理解了松结对编程的上述实践,在遇到实际人员的时候实际情况实际分析一下就可以了。

  职业生涯规划

  徒弟学好了可以做什么?可以独立工作,比如新出现一个模块或业务,可以单独交给此人开发(要配代码审查人);做得更好了可以做师傅,带徒弟。

  师傅学好了可以做什么?可以做项目经理。比如如果有个师傅带了多达3~5个徒弟,而且还想增加人,那么他的那个模块多半要分拆为一个子项目了,而分拆后,师傅是新项目经理的最佳人员。

  之前呆过的一家高成长性公司,去的时候只有18人,一年半以后就达到120人了,而业务骨干多半都是当年的徒弟,而不是新招来的高手。究其原因,一则业务壁垒不是刚招来的高手能突破的,二则师徒制度使人成长很快。最初大家并没有正式的师徒制度,但是项目经理无私地指导大家,为团队成长和后来建立师徒制度建立了条件。本人刚去的时候工作五年了,还不知道申请的内存要删除(C++),现在的编程功底基本上都是在这家公司学成的。

  主程序员团队

  如果遇上一个顶十个的师傅,也有团队模型就是主程序员团队。师傅干活,徒弟打杂+学习。本人用过两次半,都很成功。主程序员团队的工作方式更“松”,但也有其工作模式和师徒制度。

  主程序员团队不如松结对编程团队健康和有潜力,个人感觉只适合某些情况。

  本文未涉及的139团队内容

  自组织团队的激励机制,大型团队的计划会,大型团队的每日立会,大型需求团队与开发团队的配合,强分工团队的工作方式,139团队详细的绩效考核/非物质激励等内容,将在139团队系列中展开讨论。

  -----------------------------------------------

  139团队是应用松结对编程的大型敏捷团队,在其3-9级别上适合松结对编程过程,而在整个层面上适合Scrum过程。

  139团队解决了绩效考核、人员招聘、职业生涯规划等一些大团队问题,从而为小团队(师徒团队)应用松结对编程和日后健康成长铺平道路。

  本文是“敏捷开发松结对编程实践”的最后一篇,本系列所属实践仅适用于几个开发人员的微观环境,其外围大型团队的实践请参考“大型敏捷开发团队:139团队模型”系列。

  ------------------------------------------------

  后记

  任何开发方法都有局限性,也都有可取之处,松结对编程也不例外。

  笔者在多年开发及咨询过程中,逐渐发现所有研发方法都会遇到困难,而所有研发方法经过变形都可以某种方式应用下来。关键问题在于,在遇到困难的时候不要因为困难而否定方法,而要积极为解决困难寻找答案。格言说得好:不是缺少发现问题的眼睛,而是缺少解决问题的手。

  松结对编程本身就是在实际环境中应用敏捷开发和结对编程的时候遇到困难后的变形,所以在应用松结对编程的时候如果遇到困难时,办法只有一个:继续变形。

  敏捷开发传入中国已经10年了,但是如果问哪家企业非常成功地应用敏捷开发,谁能出来好好地讲讲案例,几乎无一能者。究其原因无外乎两个:

  1. 过于迷信方法,因此尝试原封不动地使用方法,结果水土不服遭到失败。

  2. 过于不迷信方法,尝试失败后就轻易放弃。

  整个过程中最容易被忽略的,是实践者自身的创造力。其实早在创建Scrum的时候,Ken就指出Scrum只是一个起点,他建议人们从原装的Scrum入手以保持稳定的过程框架,并进而自行发挥。但多数人在应用时,都过于喜欢查书,百度,google,找培训课程,看博客——包括这里,只要还找不到的,也不再尝试不再创新,这就背离了创始人的初衷。

  刚刚参加完MPD 2011深圳站,在演讲中间及后来媒体采访,被问到了一些问题,也给出了答案,这里做一总结。

  我自问自答到一半,才发现这里边的很多问题的答案,都用到了火星人谚语系列之一:有问题的地方无答案火星人谚语系列之三:正确的答案一定简单。如果您觉得答案和自己的情况不完全相符,请用火星人谚语系列之二:问问题的人负责找答案

  另外多数答案在本系列1~6中有,只是比较分散,不太容易意识到是答案。

  人员与结构

  在团队中使用层级结构,是否阻碍了个体与外界的沟通?

  极少有底层程序员或新手能和产品经理做深入的沟通的,所以中间放上师傅这一层,让其代为问问题,徒弟旁听,不但不会阻碍,反而会促进。

  这样徒弟可以更快地学会问答技巧或熟悉业务,真正学成了,师傅才懒得在中间“阻碍”呢,呵呵。

  师傅又要懂业务,又要懂技术,又要带徒弟,是否要求太高了?

  的确不低,但是如果不要求这三个师傅如此,就要要求全组如此,更难;当然可以要求让程序员们可以不懂业务,但这样的程序员怎么放心让他干活呢。

  但实际上,这点要求算不上什么,和“多才多艺”二字沾不上边。所以这种人其实很多,只是他们没被赋予这种职能而已。

  师与徒

  高手不愿意带徒弟怎么办?

  所谓求什么得什么,如果企业给个人能力高的人发高薪,而不给能带团队的人发高薪,屋子里边坐着的一定是一堆不愿意带徒弟的高手;反之则反。

  另外一个角度,139团队不只是一个学习团队,而首先是一个生产团队。师傅带徒弟,一定程度上有上级带下级的感觉。还没有一个上级不希望自己有更多手下的,也没有上级希望自己手下都是饭桶的。

  所以制度合适,人自然改变。

  招聘了徒弟,没有师傅愿意带怎么办?

  以往人是招聘来塞给某人“你负责他的成长的”,现在应该是有师傅说“忙不过来了,给我招聘个徒弟吧”。师傅要参与徒弟的招聘和试用。

  徒弟不听师傅的怎么办?

  试用期就走人。

  时间与效率

  师傅一个顶仨,照顾别人是否降低效率?

  要做好时间管理,就是师傅找徒弟随时,徒弟找师傅预约(“我有问题……”“好,等15分钟……(继续干活至一段落为止)”)。

  一个人看那么多人的代码,会不会很花时间?

  高手看新手的代码,10分钟就能看到一大堆错误。

  师傅看徒弟的代码,5分钟就行;每天早上做了设计,中间还有前后关键点,没什么可看的。

  今天看到的问题,明天不可再见,早晚一天无问题可见。师傅是培养徒弟干活的,不是给徒弟擦屁股的(在试用期就要考核这个,不怕起点低,但一个人连培养价值都没有,还能干啥)。

  专家与杂家

  大家需要了解的东西太多,生产率是否降低?

  我见过的最高的几个高手,都是以更广泛地了解业务和技术为特点的。

  我见过一个13个人的团队,9年来人换了好几批了,从来都是每人只负责的功能,都是“专家”。产品最后有25万行,被一个高手花一年半改为1.3万行。问为什么原来的代码那么多,答:“原来的专家走了,没人能看懂其代码,所以只能大面积拷贝粘贴。”这样的专家,要他何用。

  有些人希望只专注于自己的工作,怎么办?

  目光这么窄的人,能做好自己的工作才怪;所知这么窄的人,能委之重任才怪;一直自己干活的人,能管理部门才怪。很多人苦苦钻研技术,希望能力提高然后被提拔,实在是缘木求鱼。道理一讲就通。

  如果还讲不通,迟早会发现不想当将军的士兵,连厨子都做不好的,呵呵。

  绩效与成长

  师傅学不到东西怎么办?

  师傅之上还有师傅;师傅人数少,可以送去培训……师徒制度里边没有关于师傅怎么学习的内容,但如果理解“有问题处无答案”,这类问题很好解决。

  教会徒弟,会不会饿死师傅?

  如果我是老板,我会喜欢下金蛋的鹅,胜过金蛋,因此给鹅更多钱。

  如果我是师傅,我会喜欢卖金鹅蛋,胜过卖烤鹅腿,因此能值更多钱。

  如果我是徒弟,我会羡慕下金蛋,胜过我就是个蛋(好惨啊)。

  徒弟的能力超过师傅怎么办?

  我的编程能力超过我师傅的时候,他做部门经理去了,因为我们部门的所有师傅,都是他的徒弟,不选他选谁。

  能力的不总是等于编程能力,而是一种在不同年龄不同层次有不同定义的东西,只有这种东西才能叫做能力。

  上面这句话套用金刚经语法,就是“如来所说能力,则非能力,是名能力”,刚开始很难理解,但理解了就发现是一种很通用很有效的思维方式。

  比如把“创新”带进去,就会得到乔布斯的创新观:我们苹果所说的创新(价值观创新),是不能被模仿的创新,所以才叫做创新(换言之能被那么容易模仿的,还谈不上什么创新);你们模仿iPod,我就做iPhone,你们模仿iPhone,我就做iPad;你们模仿iPad,我就得胰腺癌……

  因为何为“能力”,怎样根据“能力”确定师傅和徒弟,根据什么“能力”来考核师徒,是139团队和松结对编程的核心,所以多说两句。

  个人感觉凡是不违背敏捷之神的研发管理方法,均为敏捷。所有敏捷的实践者,都应该在敏捷的大框架下,跟着自己直觉和本能的引导,去创造适合自己的敏捷实践方法。

it知识库敏捷开发“松结对编程”实践,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。