| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx

一地鸡毛 — 软件项目中的人际困局

1
项目管理 C/C++ Go 11567 次浏览

  文/方坤

  作者结合切身经历,展示了他之前所在团队软件项目延期的种种原因,而其中印象最深刻的是各种人事纷扰乃至于勾心斗角。

  六年前,毕业未久的我在一家外企工作,我所在团队开发的软件项目在交付到集成测试组时因种种原因延期一周。这本身根本不是什么大事情,但其间各种人事纷扰乃至于勾心斗角却着实令我印象深刻。

  公司

  我的老东家是一家大型跨国电信设备开发商,曾具有辉煌的历史。我还记得在公司110周岁的生日庆典上,一位高管致辞说:“110年,这不是奇 迹,是成绩”,令人不胜欷歔。遗憾的是,公司在.com泡沫中遭遇重创,一蹶不振。时任CEO为求摆脱困境,打起了人力成本的主意。当时,公司在美国雇用 一名工程师的综合人力成本接近中国的2.5倍【注:工资只是其中一小部分】。至于法国,成本比美国还要略高一些,而且不要忘了,人家可是35小时工作周。 大家都是聪明人,很快就看到端详:公司正在法国裁员,将项目转移到中国。

  令人尴尬的是,我所在的中国团队恰好就在与法国团队合作。这一项目最早完全在法国,此后几年时间,中国团队大规模扩张人手(我就是这样进来 的),将项目模块逐一从法国团队手中接过来。刚开始,法国工程师将原先的模块移交中国之后,便转而从事其他项目或职位,谈不上什么个人损失,双方共事可谓 融洽。后来可就不是这么回事了。有一次,两位中国工程师去巴黎接手一个项目,一位法国工程师负责培训,为时2~3个月。在这位法国老师兢兢业业的帮助下, 两位中国工程师成功掌握整个模块,按期于圣诞节前夕归国。告别巴黎时,没有一个法国同事去跟他们寒暄话别 —— 那位法国老师被裁掉了,他的最后一个工作日恰好就在两位中国工程师离开的同一天,法国同事都去送他了。

  到发生本文将要详述的交付延期之时,所有模块的开发工作都已从法国团队移交到中国团队,而集成测试虽然仍由法国团队负责,但从法国到中国的移交也已开始。不妨猜猜看,法国集成测试团队的工程师们此刻在想些什么。

  团队

  我很幸运,毕业后初入职场就遇到一位好经理H,坦率地说,她也是我到目前为止跟随过的几位经理中最好的一位。中国很多女经理都有一个共同的特点:没有私心。她们对于自己的晋升、提薪并无多大热情,更愿意把心思、时间和精力花在辅导和培养自己的团队上面。

  H因分娩而“暂时”离开我们团队。经过短暂的过渡,接任我们经理的是T,一位新近招聘的职业经理人。他的风格与H大为不同。仅举一例说明。当年 向H请一天年假,她总是微笑着说:“没问题。不影响工作吧?”T则会端起架子:“不影响工作吧?没问题。”语序上的变化,加上语气的差别,虽然只是细微末 节,却反映了态度的不同、对员工是否尊重。除此之外,更严重的是工作态度问题。现在我们知道,T在北京待了不到一年时间,买下两套房、一辆车,还办妥了到 加拿大的移民和那边的工作 —— 而在当时,我们这些员工仅仅只是知道,我们的经理不太在办公室出现。

  在团队内部,我所在的FM小组与另一个CM小组工作是紧密衔接的。但在CM小组的核心员工之间却存有罅隙:小组长B与技术骨干S矛盾日增。怎么 说呢,这两位都是很好的同事,然而好人之间也会彼此鄙视的:S认为B不懂技术,瞎指挥;B认为S目空一切,难以共事。缺少一位好领导来调和,好员工也不能 组成一个好团队。

  流程

  我们开发的是一个庞大的电信软件项目 —— 3G接入网网管系统,采用的开发流程仍然是传统的瀑布式。简单来说,依时间顺序,一个软件工程师(首先是各小组的小组长)需要依次参与以下几个阶段。

  • 需求阶段:跟踪和审阅由系统架构师撰写的需求文档,必要时要求澄清,然后预估工作量,经理据此调整人员安排。
  • 设计阶段:分析需求文档,完成模块设计,据此撰写高层设计文档和底层设计文档,前者以定义模块接口为主,后者则涉及更多细节。
  • 编码阶段:根据两份设计文档完成实际编码工作。
  • 单元测试阶段:是的,你没有看错。根据本部门正式的、成文的流程,单元测试阶段在编码阶段之后安排时间进行。 在实践中倒是没有这么僵化,大家尽可以测试先行,只要时间大致齐即可。各开发团队在完成各自负责的一或多个模块的单元测试之后,将代码提交到统一的代码 库,打上标签,然后将这些标签连同其他注意事项写成文档保存到指定目录。其后,就是集成测试阶段了—— 集成测试团队收集所有团队的所有标签,从代码库提出相应的代码进行编译,编译成功后即按照事先准备的测试用例进行测试,给开发团队提Bug。

  我参与了前面几个版本3.X、4.0的开发,仅从技术角度而言,瀑布式开发流程工作得尚称流畅。但工程师是要领工资的,软件写出来是要卖钱的, 一套经典的瀑布式流程走下来往往耗时几个月甚至年余,等到软件产品正式发布,用户需求已然发生变化,这怎么赶得上趟呢。公司不是没有意识到这一问题,但舍 不得做伤筋动骨的巨变,只愿意在现有流程上做一些微调,效果甚微。

  有一个例子很能说明问题。当时,中国的销售部门向总部反映,我们在中国市场遭遇到本土厂商的强力阻击,要想争夺中国市场,就必须在定制化方面下 更大工夫。在大中华区乃至总部高层的大力支持下,我们部门成立了一个“快速特性”开发小组,专门根据中国客户的需求为我们的产品添加相应的特性。有一个快 速特性是这样的:本来,我们的网管系统会在电脑屏幕上显示一台虚拟的机器,如果某个部件坏了,代表该部件的绿灯就会变成红灯并开始闪烁,提醒操作员注意。 中国客户看过演示后说不错,但光红灯闪烁还不够,还应该放点儿警报声出来,不然操作员离开座位了怎么办。我们的销售一口答应下来。猜猜这个特性我们做了多 久才交付给客户?三个月!这就是瀑布式流程下的“快速特性”!(当然,中国的销售部门和开发部门分别向国外的上司汇报,由老外负责协调中国的事情,这也是 造成拖延的一个同等重要的原因。)

  这样拖拖沓沓做出来的产品,其销路如何不问可知。公司应对的办法,就是一方面推新版本、新特性来吸引客户,另一方面强调开发速度的重要。很显 然,这两者之间存在矛盾:新特性越多,开发时间就越长,客户不会买账;可是如果新特性太少,跟上一版本差异不大,客户同样不会买账。

  版本

  有一天,经理通知大家:咱们要开始做新版本4.1了。其后,像往常一样,我们就陆续接到一批批需求文档,开始预估工作量。然而这一次,事情一开 始就有些不同:这些需求文档写得异常混乱,常常不知所云。我们如何能够根据一份看不懂的需求文档来预估工作量呢?我们随后联系法国的系统架构师(他们处境 安全,跟我们合作融洽)要求澄清,他们也很不好意思,有时还确实能够做出澄清,但大多数时候要么含含糊糊地来一句“我们也在研究”,要么说“根据我的经 验,这条需求应该与你们模块关系不大”云云。大家就这么半猜半蒙,在磕磕绊绊中前行,心中满是不详的预感。

  4. 1版本很仓促地做出来了。又有一天,经理通知大家:4.1版本过于保守,连公司自己都觉得销路不会好,决定立刻开始4.2版本计划。于是一切都重新来过, 而这一次,情况更糟:大多数需求文档都是匆匆写就,语焉不详。一些需求文档只有一个标题,正文人家根本就没来得及写,而经理就要求我们根据这样的需求文档 来预估工作量。如果你认为这样很夸张的话,那我只能批评你想象力有限 —— 个别文档只有一个编号,收纳到某一领域的写作计划之中,连标题都没有,而我们仍然要据此预估工作量!就这样,日复一日,我上报一些连我自己也不相信的数字 给经理,而他则努力装出相信的样子。

  软件工程应该怎样做?我本来以为CMM、TL 9000等是王道,经历这一风波我才深切地体会到,再好的流程与制度也经不住扯淡啊。“人和”最重要。

  4. 2版本更仓促地做出来了。又又有一天,经理通知大家:4.2版本过于激进,工期又短,从设计到实现毛病多多,公司也不看好,决定立刻开始5.0版本计划。 这一次倒是没有太荒唐的事情发生。5.0版本实际上没有什么全新的特性,而是将4.1、4.2这两个版本的特性做一折中,从这个意义上讲,叫它4.1.5 版本更合适,当然这个话不能对客户说。就这样,几个月以来第一次,大家终于能够做点儿靠谱的事情。然后,出事了。

  风起

  第一波的事故,我是直接责任人之一:因为我的失误,我负责的FM模块没有通过编译。

  我还记得前几个版本交付时和H一起工作的情景。她会敦促我们尽量提前完成开发和测试工作,提交代码,打上标签,撰写交付文档。她会亲自检查我们 的交付文档,连一个细节也不放过。比如有一次,她就发现我无意中开启了Microsoft Word的中文自动纠错功能,把“…”(在版本配置中具有特殊含义)自动替换成了半个中文省略号“…”,让我脸上无光。大大小小的问题被她连续抓住几次之 后,我开始小心谨慎,此后几个版本都顺利过关。印象最深的还是编译时的一次次待命。由于时差的关系,法国同事依据标签提出代码开始编译的时间是在北京的晚 上,每一次,H都会带领我们几个少数技术骨干在办公室待到夜里,直到我们团队负责的所有模块都成功编译之后才离开。这可真是一件苦差事,而且在我当时看来 毫无必要 —— 我们的模块从来都是一次编译成功,错误(如果有的话)从来都属于其他团队。有一次,法国同事连续犯错,导致编译迟迟不能开始。当时我还保留着自校园带出来 的早睡的习惯,时间一长,上下眼皮开始打架。H就跑到我的座位,谈人生,谈理想,谈八卦,反正就是不让我睡着。一直坚持到凌晨两点,编译开始之后照例一次 成功,H才领着饥肠辘辘的我们离开办公室,请我们到楼下的小店吃宵夜。喝着温暖的豆浆,我在心中嘀咕:“真是事儿妈啊。”

  这一次,“事儿妈”不在了,新任经理给予我们“完全的信任”,从头至尾都放开手 —— 这同一件事情我们都连续做了好几遍了,还能出什么错呢?

  还真就出事了。前几次,我们至少能够提前一周左右的时间完成全部工作,这抢下的一周时间足够我们反复测试、排查问题,并为应对突发事件留下时间 —— 尽管突发事件从未发生。而这一次,大家经过连续几次折腾之后疲惫不堪,工作效率低下,更何况这次的工期本来就偏紧,还被前面几个环节挤占不少。我们FM小 组勉强提前几天完成工作,CM小组却陷入苦战,加班加点,紧赶慢赶才在最后一天完成。FM模块依赖于CM模块,这样一来,我们也受到连累,不得不换上CM 小组最新的标签,重新测试FM模块、打标签、修改交付文档。等到我饿着肚子敲完最后一个字符,又仔仔细细检查了几遍,已是周五晚上7~8点钟的光景。我长 吁一口气,站起身来,摇摇晃晃地离开了办公室。

  等到我周一早晨回到办公室,这才发现自己犯下低级错误:我忘记将修改后的交付文档保存在指定目录了!这样一来,法国同事据以编译的乃是先前保存 的老版本的交付文档,FM模块编译失败!我赶紧寄出道歉信,连同最新的交付文档。然而,晚上的编译仍然没有成功。根据法国同事提供的编译错误日志,我很快 就发现问题:FM模块与其他依赖模块之间使用了不一致的标签。说起来还是怪我们两边当时掉以轻心,只是口头约定了一下,也不知怎么就听岔了,关键时刻害 人。又是一番折腾,FM模块在第三次编译中顺利通过,我心中一块石头才算是落了地。

  乱战

  我这边没事了,CM小组却开始焦头烂额。

  CM模块几次编译均告失败,而法国同事提供的编译错误日志乱七八糟,毫无帮助。原来,我们项目当时尚未采用分布式编译技术,为了缩短编译时间 (仅仅某一个子模块单机重新编译就需要18小时),法国的集成测试团队自行编写了一个脚本,开启几路进程并行编译各个子目录。这个脚本写得过于简单,几路 进程的输出信息全都杂七杂八搅到了一块儿,以至于CM小组研究了几天,连到底哪个子目录编译不过都没闹明白!

  CM小组尝试向风雨飘摇中的法国集成测试团队请求帮助:“你们能否用单路进程编译CM模块的各个子目录,将错误信息提供给我们?”

  法国人回答:“请中国团队尽快修复编译,你们堵住了整个项目!”

  CM小组解释说:“我们正在努力,你们能不能帮忙……”

  法国人回答:“请中国团队尽快修复编译,你们堵住了整个项目!”

  CM小组再次尝试:“这一错误本地不能复现,而编译日志……”

  法国人回答,并且抄送各路神仙:“请中国团队尽快修复编译,你们堵住了整个项目!”

  外事不靖,内部也不安宁:CM小组的小组长B和技术骨干S此刻正在斗气!从一开始,B就将编译错误的排查工作分配给自己和另一位同事,没有邀请 S介入,而S也不主动过问。没想到这么一个乍看上去再简单不过的错误一拖就是好几天,这样一来,双方陷入僵局。站在B的角度,如果连个编译问题自己都解决 不了,还得请S来当救兵,这不是坐实了自己不懂技术的指控吗,这张脸以后还怎么搁?再说S一直面无表情地坐在自己的电脑前做自己那一摊事情,一句问话没 有,这不摆明了是要袖手旁观吗?而S也有自己的苦衷:自己要是一开始就主动介入倒也罢了,如果拖到现在才出手,那怎么解释自己前几天不闻不问的态度?就算 自己辩解说确实没有端架子、看领导笑话的意思,完完全全是在服从领导安排,也得有人信啊!双方有一点想法倒是共同的:这个编译错误赶紧消失了吧……

  既然CM小组迟迟不能修复编译,顺理成章地,项目经理(一个不偏不倚的法籍华人)开始找他们的上级,也就是我们共同的经理T。然而,她找不到 T!事情就是这么凑巧,虽然T平时就神龙见首不见尾,可像这次这样整个礼拜办公室都不怎么见人影、写信也不太回的情况还真不多。连续几天,项目经理从法国 给T的座机打电话,按说这是法国的休息时间,中国的上班时间,可是法国那边有人打,中国这边没人接。电话留言、电子邮件都不好使。项目经理急了,电子邮件 写得越来越不客气,每封信的结尾都是同一句话 —— “T在哪里!”……

  事情终于惊动了上面,领导出来问话了:“发生了什么事?为什么会耽误到现在?”法国团队再次暗示中国团队无能,中国团队则强调本地无法复现,必 须法国团队配合,项目经理在居中调解的同时狠狠地告了T一状……领导不愧是领导,跳过T的事情不提,和蔼可亲地建议法国团队考虑中国团队的合理要求……事 情终于走上正轨。法国团队终于按照CM小组的建议尝试单路编译;与此同时,B主动去征求S的意见,问他是否愿意参与排查,而S也立刻答应下来;T又神秘地 出现在办公室里,如果这有关系的话……经过整整一周的纷扰,周五,编译终于成功。

  那么,这一编译错误到底是如何产生的呢?说起来,这居然还与前述混乱的版本计划有关。在4.0版本中,出于兼容旧有设备的需要,CM模块中有些 文件按照foo_V4.h的格式命名,后来升级到4.1、4.2版本后文件内容相应修改,文件名保持不变。可是5.0版本实际上是4.1、4.2版本的综 合,CM小组被迫把4.1、4.2这两个版本的foo_V4.h文件都引入5.0版本,文件名分别命名为foo_V41.h和foo_V42.h以示区 别。换言之,文件名变长了一个字符,而这就导致法国集成测试团队的编译脚本中的命令行超过了最大长度的限制……

  尾声

  软件工程应该怎样做?我本来以为CMM、TL 9000等是王道,经历这一风波我才深切地体会到,再好的流程与制度也经不住扯淡啊。“人和”最重要。

  无论版本号如何,我们的产品终究还是销路不畅。新任CEO上台后,大刀阔斧厉行改革,将整条产品线出售。毕竟,对于IT业来说,创新才是利润之源,单纯的削减成本没有出路。基于这一认识,我转投互联网公司,从此踏上新的征程…… 原文链接

2个答案

0
我顶
0
我只知道我还活着。哈哈。一切很好。接分走人。