在2005年11月份左右,我还是微软一个普通的合同工,当时我和VoltComputer Services的合同差不多过期了,我刚刚把我的夫人接到美国,不找份正式工作心里不踏实。我一开始先尝试着在微软找份工作,我去了一个MSOffice测试组的面试,结果面试发现这个组使用手动测试居多,自动化测试很少。我的能力和方向和他们相差还很大,自然没有通过。我当时所在的小组又没有任何全职机会,所以我就开始寻找雷德蒙地区(华盛顿州的微软的老窝)其他机会。有一天我收到了一封来自PeterStroeve的信,可能是我在HotJob上张贴的Resume引来的注意。我和他来回了几封电子信,我最后决定去这个名叫Net Objectives的公司进行一个面试。当时我们就聊了聊天,我和Peter见了面,他是个很沉默的人,和他一起的还有DavidMoynohiem(不知道有没拼错),后来还来了一位Kevin Yu(广东人)。我和他们海吹山侃地聊了25分钟,然后又做了些他们出的题目。他们对我非常满意,就派我到MSN旗下一个搞上网安全软件的小组面试。我轻松搞定了这个简单面试。
随后我开始了我事业生命中最光彩,最难忘的经历。当时David告诉我说,这是一个微软MSN的外包项目,我们准备用了Lean&Agile的管理模式来进行这个项目的设计和制作。我不知道这个Lean&Agile究竟是什么,我当时心想不管怎么样,先当优秀的士兵,在连长安排下冲锋陷阵,做好本职工作,发挥110%的自我能力,肯定没有问题。我打心里就不相信所谓的Lean&Agile能够做好一个软件。当时我看到的微软在Vista上的人员互动,我对软件设计管理丢失了信心,我只知道自己能力不错,能处理任何问题,当时的信念是“一夫当关,万夫莫开”。我对自己的能力的信任是没有任何疑问的。
第一个星期整个小组在招人,和我同时选上的还有一名叫NadimRubeiz的黎巴嫩人,Kevin是项目负责人。后来我们又招了一个叫Brian Young的测试员。他是个硬件驱动高手,对视窗内核和驱动设计了如指掌,是个不折不扣的高手。我们又招了一个叫SaidFathababel的埃及人,此人对视窗内部的构造十分了解,也是高手。Brian和Said都有一定的问题,我后面再慢慢叙述。这第一周我们先是选定办公地点,是公司中一个稍大的会议厅,Kevin定购了一张很大的会议桌,我们四人团团围着桌子坐,当时我觉得这样办公好寒惨。几分钟后才知道这才是Lean&Agile的最佳工作方式。我们随后安装了新买的Dell电脑,开始将所有的任务写在纸上,贴在窗上。我们的开发就此开始。
第一个星期的工作基本上是投石问路,我们大概知道我们的用户期待的是什么,我们大体把前三个星期该做的事列举下来了,第一周过后,我们和客户见面进行了45分钟的会谈,首先Kevin介绍了Lean&Agile的管理原理,我们外包人员是一辆汽车,我们的客户是驾驶员,客户的意愿加上我们的做事程序,将完成客户所期待的价值。随后我们把该做的事和客户进行沟通,选出了两周左右该做的事。这些都叫“故事”(Stories),最准确的名称应该是“任务”。我们把故事的重要性进行分类;最重要最急迫的被划分并放入“FrontBurner”;不急不缓的“故事”被放入“Back Burner”;最不急的“故事”被放进“Cold Frig”。所有最重要的“故事”必须在第一个开发周期(两周)内完成。这并不是硬性指标,因为完不成的任务往往是重要“故事”中最不重要的任务。这些完不成的任务和“BackBurner”中的任务重新被衡量,最重要的这些未完成的“故事”被选择到“FrontBurner”中,作为下一周期中该进行的任务。就这样周而复始地,所有的任务要么在最后基本完成,要么时间全部用完但是一部分任务根本没有完成,而这些“故事”正是客户不需要的。这就是Lean&Agile。
我们开完会,回到公司开始开工。我们先总结了一天的工作,这是一个15分钟的短会,叫“Scrum”。每个人必须站立着,向工程负责人汇报昨天作的事,这是每个开发人员每天做的一件事。然后在每个周期开始,我们要进行设计会议,我们把故事细化,然后把所有的故事列在白板上,大家每人选择一个自己有兴趣的“故事”去做,做完验收后,再选择一个新的“故事”去做。我们第一个开发周期的进度完成地非常顺利,我们设计了一个简单的用户界面,然后是一个简单的中间件,最后是一个后台数据存储件。设计的时候我们遵循了“测试为先,开发随后”(TestDriven Development)的设计准则,利用CxxText作为我们的单元测试框架,事实上我们好多测试都是用CxxUnit来完成的,我们除了硬件,操作系统,和VisualStudio .Net 2005外所有的资源都是自己搞出来的,微软贡献的,或是开源资源。我们五个人组成的开发团队最大的价值是我们过硬的技术能力,这些基本上就能在外包行业赚取利润。当然,这并不代表我们的团队没有任何问题。下面我就要谈谈我们所面对的问题。
从第二周开始,我们的进度就开始影响。首先是Brian在第一个开发周期时没有完成他所要完成的测试任务。事实他在整个开发过程中没有做什么事,他有一个不满周岁的小孩,每天不到10:30或11:00我们不一定能见到他走进办公室。下午早在3:30,就见他准备回家接孩子。好在他的合约签的是合同制,否则这样每天五小时的工作算成八小时的工作,我们的公司不是被他骗去不少钱。随即出现的问题是,Lean&Agile要求组配对设计,两人一起解决一个设计问题,这需要两人相互给对方提意见,然后相互吸取对方的意见,这种做法就是强迫设计小组中的任意两人进行取长补短。既然这是一种硬性规定,我们就必须虚心相互沟通。Brian并不是这样的人,他的智商可能有156,所以他认为所有的人都比他愚蠢。我根本和他合不来,我的意见他根本听不进去。一个简单的测试程序我们争吵了三四小时,我觉得这个程序五十行码就能写完,他偏偏要用各种钻进牛角尖的方法进行设计,我的简单设计他听不进去,我也无法说服他采纳我的意见,然后我只好和他抬杠。这种情况本身就是与Lean&Agile背道而驰的。面对这样的问题我毫无办法。等到我们的程序突破三百行代码时,我们才设计了整个程序的一半。我实在无法控制这样的局面,在他离开后就只好向Kevin坦白我实在无法和他沟通。Said和Brian几天前出现过同样的问题,他们甚至为双方的专业背景而产生争执。事情是这样,Said背雇佣后,Brian问他是否是搞驱动背景的。当时Brian的态度很不好,给Said的感觉是Brian 藐视了他对小组能做出的贡献。当时大家的心态都很不好,我们三人(我,Brian,Said)都在微软工作过,我们刚刚被Layoff,大家都希望自己在这个新公司里的位置稳一点。Brian大概是害怕Said作为一个懂视窗结构的老手来夺取他在公司里的位置,而Said则觉得自己好不容易在丢了工作后找到这么一个来之不易的机会又受到一个年轻Punk的排挤。Said气忿之下两人就争吵起来,后来我们只好开会互相谅解。后来Nadim花费了一个上午才说服Brian尝试简单的设计思路。后面我们发现Brian和整个小组的配合并不很好,所以我们后面的做法是,尽可能少给他事情做,将他变成一个可以随便取代的成员。因为他拥有更好的测试手段,和硬件测试技术,有利用价值,所以我们一直容忍他的不作为到项目结束,最后我们也发现他的存在确实在关键是可能帮上忙,正应验了古时候“鸡鸣狗盗”故事中的寓意。
在第二个开发周期的前期,Nadim重新设计了后台数据存储系统。然后我们重复了几次有关UNICODE和ANSI的争执。Nadim希望使用ANSI编码作为后台数据存储系统文件的编码,这样文件的大小比较小。我觉得视窗都是用UNICODE编码,如果使用ANSI,我们要用一堆的转换函数,这是非常繁琐的操作。具体的原因我也不记得了,我们改了两次,最终将设计定为用UNICODE编码作为后台数据存储系统文件的编码。我也在设计中犯过错误,我和Said花费了三小时设计了用户界面和中间件衔接。Nadim来了以后审核了我们的工作,结果推翻了我的设计,我们花了一小时半,将所有的设计重新搞了一遍。我当时非常恼火,但是仔细看了看他的设计思路,他的思路更好,完全分开了中间件和用户界面。这时我才意识到这样成对进行设计的好处就是取长补短,这种好处是有条件的,两人都必须是水平相等的;两人都必须是有一定深度的开发能力;两人都必须尊重对方,并能接受成对设计这种思想。
在第二个开发周期中,最大的一次问题是第二个星期的星期五。我们把所有的设计源码上交后准备回家,结果单元测试输出了六十多个错误。结果我们仔细察了一下,有人没有完全做好自己的单元测试,就随随便便提交了自己的代码。这个人是Said。既然出了问题,那我只好留下来陪他把问题解决。那天是2005圣诞前夕,Brian已经早退;Kevin好像有事所以也先走了;Nadim腿有上伤,比Kevin还早就走了。既然是程序出错,我又是QA,所以我就和Kevin说我可以留下帮一下Said。我们花了两小时,没有任何进展,又是圣诞,所以我们就回家了。事实上这个问题解决方法不难,我们使用了Win32API的用户权限函数,结果效果很不理想。后来我在一本叫“Write SecureCode”(我们第一个设计也是从这本书里抄出来的)找到一段用ATL设计的代码,我在家里试了下,效果不错,就推荐给了Said。后来Said又和Nadim成对进行了设计,最终在第三个星期一完成了修改。这里学到的教训是,加班是么没有用的。一周的工作已经让人十分疲倦,将员工的休息时间转换成更多的工作时间完完全全是错误做法。疲倦的员工心里只有一件事,休息,放松,不想工作。强迫员工加班或是员工自愿加班的行为只能损伤员工的健康,同时很少的进展能在这样的状态下完成,最后公司还要为这样次等的工作付出加班费,这就是一种浪费。
和Brian比起来,和Said的合作还算正常。和他的互动我发现他对单元测试并不感冒,他写的很多的单元测试都是部分的集成测试(PartialIntegration Test)。Said是个C程序员,所以很多他写的代码都要看两遍才能知道他在做什么,但是,这些代码效率确实很好。可是有时我们发现什么错误,都要花不少时间来查找问题在什么地方。在这个项目之前,我用VisualStudio的Debugger用得很少,这次我可是实实在在地学了如何使用这个工具。Said最厉害的地方,可能我现在还没有学会这个,就是如何在代码里挖虫。我们在第二个周期里设计了一个压力测试程序,当时Kevin叫我们设计这么一个程序,我就花了半小时用C#写了这么一个程序。我们运行了一下发现微软给我们的TDI驱动里有严重的内存泄漏。我找了几小时找不出问题,Kevin 就叫我把这个问题转让给Said。Said在两小时内就发现了几个文件柄没有关闭的问题。后面两个设计周期中,他不断地在微软给我们的代码中发现这样的问题。我从他那里学到了不少查找虫子的方法,特别是使用像Sysinternal的一些第三方的工具来监测内存泄漏。当然我也学了一些C编程有关的技巧。但是和他合作,速度是一个很大问题,有些问题只要45 秒钟可以解决的,但是他要看4分钟才能想到这个45秒钟的问题,这样反而减慢了整个开发的速度,这样的开发反而有个好处,因为他在思考的时候方方面面都考虑到了,所以速度和周全相互抵消,最后的设计效果有时反而很好。有时这样的过多思考反而效果不好。我记得在最后一个开发周期中,我们有个改进要做,假设两个用户一个改变了程序设定,然后快速转变用户,换到另一个用户,这时Systray中的ICON也要同时改变。我和Said尝试了一个非常复杂的设计,当然我的技术没有那么厉害,所以Said提供了这个方案,在用户一那里改变设定,然后用户一更新Systray中的ICON。接着,程序在用户一的桌面上向用户二所在的桌面的同一程序送一个信息,让这个程序更新Systray中的ICON。然后我们一起编写了这个设计。当然这么一个想当然的方法没有成功。我回头一想,每个用户在快速变换(FastUser Switch)时,程序能够检测用户快速变换,所以在第二个用户桌面转成屏幕上的桌面时,只要重新将程序设置更新一下,第二个用户的Systray中的ICON就更新了。这个第二种方案几十行代码就解决了,一点都不麻烦。我们犯的错误就是想过头了,真正的Lean&Agile就是要从最简单的解决方法想起。
我和Nadim的合作产生的毛病最少,我和他的合作一般是早上我大约在9点多进公司,第一件事我先是做些有关一天要做的任务的调查,然后等所有的人进了公司后我才和他或Said进行成对设计。这样的效率也非常高,我早上查找的信息一般在90分钟到内变成可用的代码。我和Nadim合作设计了好几个用户界面有关的部分,他是一个很优秀的设计者,我的技术和他比起来就要差一些。所以我完全可以承认我的技术功底不是很优秀,后来微软没有招我做正式员工也是能理解的,我毕竟不是异常优秀的程序设计人。但是如果微软招我做了正式员工,那么我就不可能有机会和这些微软以外的高手合作,不可能有机会在实践中体验Lean&Agile这么先进的软件工程管理理论,更无法想象一个工程小组能如此高效,如此精简敏捷地进行客户能够满意的开发。Nadim让我佩服的是他的理解能力,我记得那一段时间中最丢人的经历是花了一天时间没搞出如何用WiX技术进行安装包的制作。Nadim的耐心让他在一天中搞出一个很漂亮的安装包,对这个壮举我是十分佩服的。我还记得我们两人搞了一下午的单元测试来摸索微软给我们的一个特殊字符串处理类,叫MSN::CString,这个库是专门用来处理URL字符串的。当时我们的配合非常好,我和他轮流想出测试这个库里的函数的测试单元用来试探这个库的使用方法,以此,我们在毫无文档解说的情况下摸索出了这个库的使用方法。当时MSN的开发人员问我们说,没有文档你们怎么知道如何使用这个库的?我们的部门经理很自豪地回答说全靠遵循我们开发管理系统中的一套制度摸索出来的。我和他还一起解决过一个有关CListView(MFC)处理大量物件(List View Item)速度太慢的问题。当时CListView自己的加入物件并显示的速度在处理10000个物件时要花几秒钟,我们用Google查找了90分钟,找到了一套自己加载这些物件加入ListView的办法把整个速度加快到处理100000个物件只需两秒。一下把效率提高过来。这个改进当时又一次让MSN对我们感到非常满意,加上后来我们在他们的代码中找到许多文件柄没有关闭的问题之后,我们的高效和专业敬业完完全全取得了他们的信任。我觉得Nadim最让我值得尊敬的素质是他的领导能力。Kevin是个非常优秀的领导,Nadim则是Kevin不在时的替补领导。因为他的技术基础过硬,和许多的开发经验,所以赢得我们所有人的尊重,我们会尊重他的意见,我们在他的带领下进行开发。没有他在后面用技术做领导,这个项目完成后的质量不一定是那么好。我同时感觉他在整个过程中对Lean&Agile的领悟非常深,他和我一样喜欢这套做事方式。
最后说说Kevin。他是一个很优秀的领导,没有他对Lean&Agile管理的深刻认识,我们肯定不可能在两个半月内将这项目完成,但是他要是没有我们这些人,也不可能把这个项目完成。他是一个非常勤奋的人,他的主要职责不是和我们一样开发,他的职责是和用户沟通,他把用户所希望得到的最后期望转化成一个个细节的“故事”然后吩咐给我们设计。我们把他作为我们的客户,我们做完了一个局部设计先让他看,他认为满意,我们就知道客户对这样的设计一定也会满意。他要是不满意,马上会告诉我们应该达到什么样的效果。客户要达到的效果,他能仔细地分析细化,然后和用户沟通哪些是重要的,哪些是不重要的,排序以后,我们再简单讨论如何分配这些“故事”给每个人做。他耐心地和Brian还有Said解释Lean&Agile的理念。特别是Brian,Brian的贡献最少,但是他还是耐心地和Brian一起成对进行设计。后面我实在没有兴趣和Brian成对进行测试,因为Brian每次碰到机会就反对我的意见,每次他自己出现问题就是花费数小时自己去阅读,试图理解这个问题的方方面面,完全不顾整个开发进度,完全不顾其他人是否有这方面的专长能否帮他把眼下工程搞完。Kevin不懂C++,只懂C#,可他还是坚持和Brian成对编程。他不是想学技术,他是尽自己最大努力监督Brian把Brian 自己该做的任务做完。可以看出Said是没有时间Brian纠缠,Nadim似乎也没有兴趣和Brian纠缠,我就完全承认,我是没有好脾气和Brian扯皮。但是作为一个设计组的领袖,Kevin不得不做坏人,用威信逼迫Brian做到他想要的结果,当然这样最终还是逼着Brian做完了该做的事。而且在同时,我们在没有Brian捣乱的状态下做完了我们该做的事。Kevin的表现100%完美地展示了Lean&Agile的管理和开发过程,他是个非常优秀的ScrumMaster。由他的带领下,我们做正事的,遵守了所有Lean&Agile要求,他灵活地运用了Lean&Agile的管理模式,而不是死板地遵照书本上写的教条,所以我们在最短时间内做了三倍同样时间能做的事。我们每个人都接触了一些我们平时没有搞过的事,我搞了不少Build有关的工作。就是微软内部用来建造的系统,就是WinDDK加上Platform SDK。我花了60%的时间在开发上,但也有40%的时间搞我该搞的QA工作。总得来说我在这个项目了做了异常多的工作,这是我觉得我应该在这么短时间内做完这么多的工作量。Nadim完成的工作量比我多,他也和我一样穿梭在各种各样的任务中。Said和Brian各自也最大化地尽了他们的努力。Brian在最后一个周期,特别是临近交货的一天中花了9小时测试了整个用户界面的功能,查找出不少值得改进的地方,我这时才发现他并没有我想象地那么没用。Said就不用说了,他在关键的时刻就能为我和Nadim提供一些非常有价值的反馈。Said的代码修改实在让人敬佩,他写的东西就是很灵巧(这个词大概我五年没用了)。Kevin在调度员工让每个人在必要时发挥自己的能力做得实在让我佩服,这也说明他运用Lean&Agile十分娴熟。当然和他合作,我也有感到不耐烦的时候,我向他解释一些比较技术的问题,我要解释三遍才能解释清楚。他经常在我正做得兴起的时候把我打断,然后进行15分钟的Scrum会议,这时我在一开始就会觉得有点烦躁。同样的问题,有时他会在我做事的时候把我打断,叫我更新用来记录工程进度的Wiki主页。但是这些小小的愉快根本算不上什么。在这样的设计组里工作,合作的愉快远远大过一些小小的不舒服。
最后总结一下我对这个工程的感想。这个工程是我觉得自己所参加过最好的一个项目。我们100% 地执行了 Lean& Agile 工程管理模式,我们在规定的时间内为客户完成了客户所期待的产品。我们没有完成所有客户所希望的产品功能,我们完成了所有客户认为最重要的产品功能,客户对我们的评价是“Youguys are the superstars! ”但是等我们做完后,他们没有其他项目给我们做,允许为我们在其他项目的投标中为我们提供好的评价。我们交出工程后,15 天内,客户从来没有和我们联系让我们进行维护,说明我们的工程质量完全合格。我们在整个项目中,除了最后一个开发周期,基本上都没有加班过。最后一个开发周期中,我们七天不停地工作,我那一段时间加班赚了不少钱,但是马上又病了一段时间。说说我对这套工程管理模式感到不满意的地方,就像我说的,任何工程管理模式都有一些不足的地方。首先是大家工作的时间表,除我以外,大家都在早上10 点半甚至是11 点才到办公地点,然后自愿做到晚上8 ,9 点才回家,我挺不喜欢这种工作方式。我在这个工程过程中发现,能够保证工程顺利进行的主要还是人的因素,一个开发组要有能够接受这样的开发风格的人相互协作,心无二念,能够服从领导的指挥。一个开发组必须拥有一个很有能力的ScrumMaster ,必须能够准确地和客户沟通产品的功能,能够记录客户提出的每一个要求,再和开发组进行沟通,ScrumMaster 还要有很好的管理能力。每个组员的能力也是一个很重要的因素,没有能力强,能够合作的组员,一个工程也很难继续。在这个工程开发中,一个技术能力很强但是合作能力很差的人,给整个小组的贡献其实很少,为了保持进度,我们其他组员都要承担这个人的任务,这样让我们所有人都觉得累。其他问题还包括,我们并没有完全遵守 Lean& Agile 的规则,我们对设计的细化做得不够,我们的单元测试,集成测试做得也不够,最后我们交给客户的产品我是满意的,我觉得它可以被设计得更好,可惜我们没有更多的时间来完善。 我对这个工程的最后结果是很满意的,我的经历告诉我,这样的工程管理是非常有效的,前提是,这么一个开发小组需要的高效,技术好,能合作,能把事情做完的人,需要一个能力高超的管理人员,需要所有的人员都能按照Lean&Agile的规则做事。一个开发小组缺少这些因素中任意一个,开发就不一定