分类目录归档:软件开发

阴错阳差的结对编程实践

 

我所在的团队服务于一个美国创业型公司,聚焦于企业级移动信息化。团队兢兢业业做了3年,让该公司被一个更大的支付公司给收购。期间有幸和美国的顶尖架构师,咨询,以及项目经理合作,收获颇多。
 
团队里面的项目组规模始终保持在极小规模,2个开发或者一个测试一个开发再或者一个测试两个开发,捣鼓一个月便将一个项目搞起,接下来转战另一个项目。同时,随着时间的推移,每个项目组身上除了新开发的项目外还负担着历史项目的维护。
 
该创业型公司对“流程重视程度不高”,我不确定是不是类似的创业公司都如此,但这一点我相信也是有充分存在理由的:
1. 创业型公司人少。流程一般针对于大规模团队有很好的实践价值,因为人多,应当用流程管人而不是人管人。基本的流程当然也应该有,不过大多数都是用“简单真实的对话”取代了复杂繁琐的流程。
2. 创业型公司人精。人人都是多面手,养不起闲人。大团队里面每个人接近螺丝钉,所以鸟瞰下是流程让每个零件正常地运转;小团队里面每个人处理几方面的事情,所以鸟瞰下是人将事情连起来,人去推动事情发展。
3. 创业型公司成本意识。创业型公司资源不如大公司多,所以更快。同样一个项目,可能大公司有底气一做半年保证“高品质”(结果怎么样再议);创业型公司则赶紧开始,然后在过程中不断地去调整自己的目标。
4. 创业型公司变化大。不管是人还是环境还是项目,当变化产生时,相应地就需要变化对策。而流程,从字面意思来说就是个固定的产物。如果制定一个流程,反复修改,所带来的时间成本不如没有一个写在纸上的流程,只有目标 — 用任何可行合理合法的手段达到目标。
 
一. 从流程改进谈起
我所在的公司很重视流程,很重视质量,甚至每个团队都会配备一名全职或者兼职的质量管理监督专员(SQA:见软件开发中的角色扮演)。SQA主要是为团队制定流程,发现问题。
 
正如前文所说,现在我们的团队和美国的顶尖架构师工程师一起合作开发解决方案级别的产品。既然是合作开发,我们的代码都是彼此共享,这样美国那边的工程师架构师就会偶尔“自发地“代码评审一下。坦白说,中国工程师的代码质量总体来说不如美国那边的,再加上不同地区的代码风格不会完全一样,所以美国那边发来一份代码评审的结果。
 
这份结果发来,引起了双方领导的“高度重视”,立马开会整理流程。总体来说,为了确保我们团队的质量,要把FTR重新做起来。
 
二. 所谓的FTR
FTR, Formal Technical Review, 正式代码评审。大体上来说分为以下几个步骤:
1. 需要被代码评审的项目组首先发出一封正式的Email,里面会写有要被评审的内容,正式代码评审大会的时间,附件里面有需要被评审的代码。
2. 收到邮件的工程师需要在正式代码评审大会之前完成代码评审的任务,同时有个模板可以记录你发现的错误。
3. 在正式代码评审大会上,大家围坐在一个会议室里,用投影打开代码,顺便对着合并好的代码评审记录一条条过错误。在大会上,只确定每条错误到底是不是错误,如果是,则跳下一条,然后工程师回去改进;如果不是则标记一下。
4. 正式代码评审大会后,被代码评审的项目组需要将提到的错误全部改进,然后再以邮件的形式发回给代码评审的人。
5. 代码评审的人需要对结果进行验证(Verify),看是不是改好了。这一步形式多样,有的时候开会,有的时候就“看看”。
 
三. 代码评审的好处
根据SQA的记载统计,大部分有价值,高隐蔽性的代码缺陷是从代码评审查出来的,而不是QA测试出来的。而且坊间有很多传说,比如Google公司所有的代码必须经过代码评审才能被Check in.
 
从一个团队的构成角度上来看,一般有少数高级工程师,加上普通工程师,可能再加上一些刚毕业的小弟小妹们。分工也各有不同,不如小弟小妹们可能会被分配做一些单独的简单的模块。所以,由高级工程师领导的针对小弟小妹以及普通工程师的代码评审就显得价值非常高,因为往往可以极大地优化原来的代码。
 
四. 代码评审的尴尬之处
尴尬一:时间紧张
作为创业团队, 每天的任务很紧张,有的时候甚至需要当天交付,就算不当天交付,也需要在当天的结束交付一个报告汇报进度。如果赶工,那么质量得不到保证,所以必须要代码评审。而FTR,正如那一节所说,虽然看起来很正规,实际上每一个步骤所耗费的时间不少,而这些时间成本对于一个每天任务很紧张的团队实在难以接受,同时美国那边的管理团队也不太愿意一天的时间有半天在代码评审,因为他们也背负着客户极高的产出压力。
 
尴尬二:业务不熟
文章前面提到,我们的项目团队是分为小组,每个项目组做不一样的项目,业务关系基本不一致。所以试想当一个工程师,突然收到一份FTR的邮件,里面放了20几个.java文件,说“你看吧”,从哪儿看起?每个.java类方法干什么用都不知道。于是这样的FTR经常的结果是:只能找出一些Coding style(代码规范)的问题。
 
尴尬三:为了流程而流程
有的时候一个高级工程师和一个普通工程师在一个项目组,这个高级工程师会去代码评审这个普通工程师。因为只有两个人,所以可能就在座位上两个人对着一个屏幕解决了。而这个时候SQA对FTR的流程判定是需要有一个代码评审的结果,否则谁知道你代码评审了没有?所以即使两个人可以很快解决,也需要再写一份文档把错误结果先填上去,然后另外一个人全标记为"Fixed".
 
五. 结对编程实践
当时在流程讨论会上,联想到代码评审的三个尴尬,于是我建议我们做一个新的尝试:
1. 搬两台机器到会议室,一台机器连投影仪,一台机器连一个普通的LCD。
2. 连投影仪的机器显示代码的开发环境,最好接上网线和办公室内网连接。连LCD的机器只显示代码评审结果的文档,由记录员控制。
3. 代码评审开始后,被评审的人会向各位评审员展示自己项目的代码,并且边展示边讲解,他的目标便是把整个需要评审的代码从头到尾都讲完。
4. 代码评审员会随时打断他的讲解,并提出疑问或者改进办法,如果一旦确定有一个错误,则……
5. (关键步骤)被评审的人会当场修改代码,因为连接的是开发环境;同时,记录员随手记录这个错误。
6. 一直循环第3步到第5步,直到代码都被评审完。
 
这样结对编程式的代码评审好处:
1. 一次会议,两份产出:改良后的代码和评审错误记录。改良后的代码可以直接提交给客户,评审错误记录可以直接交给SQA,并对他说&ldq
uo;我能”。
2. 评审过程中,被评审的人自己写的代码当然熟悉业务逻辑,于是在讲解过程中,来自其他项目组的评审员一来可以了解代码所实现的业务逻辑,二来可以丰富自己的视野 — 多参加几次不同项目组的评审基本上可以对很多项目有所了解,而评审员通常是高级工程师,所以可以在关键人力不足的时候成为重要备份。
3. 评审过程中,有一段时间是被评审的人当场修改代码,评审员看着他改并提出指导意见。这不是结对编程吗?取代了以前看冷冰冰的评审结果,而且身为高级工程师的评审员会对他的编程技巧/思路进行当场指导,参与过的普通工程师大呼过瘾,从高级工程师那里学到了很多以前自己一个人编程学不到的东西。在此过程中,经验无损耗的传输,不但是评审了代码,更是培养了新人。
4. 关于时间问题,这样的会议第一次会费时一些,大概2-3个小时评审一个项目。不过相比较原来的FTR还是要效率高一些,区别只是大家在不同的时间地点和在同一个时间地点。从第二个星期开始便快好多,因为只评审改动的代码,同时评审员也对这个项目的业务逻辑有所了解。需要注意的是,因为每次代码评审投入的人很多,所以一定要保持清醒头脑和敏捷的思维,保证第一次的2-3个小时是有效果的!这个和结对编程对两个人的要求一致。
 
六. 流程大会后
就当我写会议纪要时,我才猛然想到“结对编程”这样的概念,然后满心欣喜。因为现实工作中的一些窘迫和紧张的时间,逼迫我们“出此下策”,没想到就碰巧成就了传说中的一种我们想尝试却因为没有这样的人力和时间成本尝试的编程方法!
 
是为记。

技术重构

前同事离职,我接手他的项目,到现在为止,缝缝补补敲敲打打接近2个月(包括十一休假)。中间有大量的技术重构情节,于是总结和思维拓展一下关于重构的话题。当然,接下来不会讲技术细节。

项目背景是要将原来一个程序从本地版移植成在线版,说白了就是从本地读数据变为发web service从服务器拿数据。这么说其实这个项目本身就是一个大的“技术重构”,因为程序的关键点在于拿数据的方式不太一样,大部分的业务逻辑是可以复用的。当然由于在线版取消了SD卡,所以需要考虑性能和磁盘空间的问题,比如展现数据的列表就需要加上分页的功能,所以部分的表现层逻辑也需要相当的修改。编程语言是面向过程,特定平台的移动开发方式也是逻辑和界面混合编程,再考虑服务器端的编程,这确实不是一个简单的工作。

接手原来的同事的项目为什么也需要技术重构?坦白讲,前同事离职期间比较赶工,加上在原来的代码基础上修改,而且项目的需求又不太明确,所以很多情况下做出来的东西像半成品 — 表面上一个普通的bug,实际分析后可能需要重写相应模块才能从“根本”上修复掉这个bug。苦不堪言,为什么苦?不是因为重写模块多么复杂,而是表面上的这一个bug给客户的管理层,公司的管理层,以及自己带来了“一个bug应该马上可以修复掉”的期望,但重写相应模块甚至重新设计相应的技术架构又需要相对较长的一个时间并且没有产出!这对于软件服务公司来说“没有产出”是很让人hold不住的事情。奋战了将近两个月,这个项目基本稳定了。

下面关于技术重构总结一下:

哪些情况可能需要技术重构?
1. 需求变更时。
如果之前设计的架构可扩展性足够好的话当然是幸事,但大多数情况下你碰到的架构是为之前的需求量身定做的(有时候是技术局限)。需求一变,在我们的平台上甚至界面一变,逻辑层的代码也得变动。嘿嘿,工期估计的时候多谈点技术方面的原因争取多要点时间吧。

2. 代码评审后。
为什么说Code Review是王道呢?在Google所有的代码必须经过Review才能check in,可见一个人的思维有时候不是完美的。写代码前的设计Review(如果有的话)当然是好的了,不过相信我大部分人设计之后会在编码阶段更改,甚至和之前的设计完全不同。于是,迭代式代码评审就显得尤其重要了。

3. 二次开发时。
这个类似需求变更,不过可能不是原来的模块,而是你在原来的模块上新加模块。原则是尽量让新加模块配合原来的模块而不去修改原来的模块,不过做好心理准备去读别人的代码,去重构别人的代码。

4. 修复缺陷时。
正如片头举的例子,有时候一个bug,看起来很简单,但是如果想从根本上改掉这个bug而不带来其他regression bug,大胆重构吧。

5. 产品维护时。
此类应该是综合了第1种和第4种情况,大规模技术重构一旦发生,维护期便被拉长,偶尔维护期的加班也会发生。这也从另一个角度解释了为什么软件的维护费用很高了:)。

技术重构时可能会遇到的压力:
1. 时间线压力。
重构,就是大改。所需要时间会超过工期预算时的预期,于是时间线压力变转变为你需要花费更多的时间,在deadline不变的情况下,加班就发生了。

2. 技术不确定压力。
当碰见难题预计要发生重构时,脑中就已经有上面讲的时间线压力了。在如此时间线压力下,人容易患得患失自己的产出。“重构需要好多时间,赶紧抓紧时间写代码吧”– 慢着,您在设计重构时考虑周全了吗?本意是想重构别人的明显有问题的代码,结果自己的设计也有问题导致最后出现更为灾难的后果。敌军再多也需要坐怀不乱,静如处子,才能动如脱兔。

3. 管理层压力。
假设有这么个场景,你手头上有4到5个bug,你看出来其实这都跟前面糟糕的设计有关,于是改变策略从“针对bug来修复”到“一次性技术重构”。通常来说技术重构需要时间,你可能2到3天都专注于新架构的设计上和实现上 — 注意,这2到3天从管理层看来是,“一共才4到5个bug,都2、3天了一个bug都没改掉,你在干嘛?” –  不能怪管理层,这种压力是必然的。管理层的眼中只盯结果,2到3天结果没变,而项目又离deadline更近了,你一人在那里技术重构,鬼知道会不会碰上第二种压力让重构失败。所以,重构务必成功,否则真的要跟客户道歉了。

技术重构遇到压力阻力后会发生的事情:
1. 针对缺陷表面修复缺陷。
工程师迫于上面说的几种压力,干脆不技术重构了,就针对bug来fix bug。你不是说这个值显示不出来吗,那我加个全局变量搞定它;你不是这边跳屏逻辑有问题吗,我再加个全局变量搞定它。。。。。。搞来搞去,可能问题是修复了,但是软件内部实现就惨不忍睹了。一旦再次发生需求变更,嘿嘿,你有可能会在代码不显眼的地方发现一处注释“当时只有我和上帝知道这块的逻辑,但,现在只有上帝知道了”

2. 有些缺陷怎么也修复不了。
因为技术架构有问题,所以技术实现在某些看起来很小的bug上就是修复不了。比如UI上某处数据显示错误,在QA那边报一个字段显示错误,但实际上这个字段是一系列数据计算的结果,中间的某些数据因为糟糕的设计取不到。。你懂的,除非技术重构否则你修复不了这个简单的“UI显示错误”。

3. 时间线一拖再拖。
缺陷怎么改都改不完,改完了发现又多了些缺陷,尽管不断的加班,但是时间线一拖再拖。让我想到一个笑话,产品底层framework有问题你在上面去换公司CTO换产品班子有什么用?你懂的。

结论:
1. 出来混,迟早要还的。
该重构时还得重构,别留给以后的人了。就学某位美国总统说的,“麻烦到我这里为止”。

2.Jobs:让时间线见鬼去吧,我们需要一个好的产品。
是产品本身重要,还是时间线重要?当你的产品不足以好到苹果的水平时,客户不会为你的时间线延迟买单。

新手编程常犯的两种错误

最近做一个项目,带着团队里面的两个新人。两个新人在平时的评价都是非常聪明,学东西很快,可是因为项目原因不得已一直在做一些维护项目,只是修复下软件缺陷,从来没有做过新的项目。而这次恰好赶上我工作比较忙,便有了这次机会。

前两天,随着我开始做代码评审,发现项目上的质量问题越来越多,最后导致其中的一位新人昨晚通宵了,因为他做的一个模块被我看了之后需要全部重写。另外一个新人虽然没有通宵,只是因为他的模块在之前看过,结果也是全部重写。这两个新人的错误很有代表性,在这里马克一下,我认为这些是很多新人编程容易犯的错误。

1. 不读懂需求就开始写代码。

在他开始开发模块之前就强调了N遍,一定将需求仔细读熟之后再动手写代码,磨刀不误砍柴工。那究竟怎么读需求?

拿到需求文档后,首先第一遍要粗略(general)看一遍,知道有哪些模块,揣测项目的模块和现实的联系等等。随后第二遍便细读每一个章节,同时旁边备好问题列表(question list, 通常是由一个excel),争取通读一遍下来便可以在问题列表上有价值的问题。此时此刻,问题列表在这里是为了迫使阅读者提问题,能够提出问题的阅读才是高质量的阅读,因为除阅读外一定伴随着思考。通常第三遍,就会拿到客户的反馈再对照需求文档,甚至在需求文档上做更新,做批注。这时候熟悉的人估计已经将大体框架和具体逻辑线了然胸中,新手的话继续读N遍,一直读到放下需求文档可以独自在白板上演示业务逻辑的程度。最后,再开始动手写代码之前,再针对性地看需开发的功能模块细节描述,同时设计出具体的技术方案,比如什么时候数据从db里面取,什么时候从内存中取,用什集合(collection)更适合存数据,在屏幕加载的时候应该做什么东东等等,这些技术方案可以在脑中,在电脑上新建文本文档,不过我最喜欢的还是在白纸上划,个人觉得思考过程更接近本质。然后,就可以写代码了。你会发现这时候写代码就跟着之前的方案写了,好像在做翻译工作,因为非常重要的设计工作已经做完了。

不可否认,很多时候新手在写代码之前无法将设计工作做到很好,因为本身对代码技术就不太熟悉,这个时候不可避免地要边写代码边设计。但我还是建议设计在前,为代码铺路。

如何检测出这样的情况?一般的黑盒测试就够了,配上QA的问询,马上显原型。这个时候QA讨论需求答不上来,黑盒测试发现和需求不一样,很快就可以得出质量的总体印象。

2. 写代码没有任何思考。

这类同学会仔细读懂需求,但是在实现的时候不会考虑任何代码优化,架构设计,总之一句话:实现就好。这种类型在黑盒测试以及配合少数据量的时候一般测不出来,所以QA会觉得“没什么bug”。一旦上白盒测试,代码评审,那马上会让你七窍生烟。爱循环,也爱遍历,不爱重构,也不考虑性能,做完就好。最后代码评审自然就重写了。

对于这类人,最好的办法便是强调在开发前的设计方案。可以先让他把技术实现方案说给高级工程师听,做到前期评审,这样后期也不会有重写的代价了。不过,对于新人,吃一回亏,呛一口水是好事。在出事之前的任何建议都像教条一样,只有在出事后,知道自己的问题,加班熬夜甚至通宵过后,才会留下难以磨灭的印象,第二次就会重视很多。似乎软件工程师都会有加班熬夜的经历?我的办公室 夜日志

2010岁末iPhone项目总结

这是一篇迟到的总结,原因是此iPhone项目从2010年12月初做到12月底,31日晚上7点才将最后的包交付出去。一般来说项目团队都会精简成2人,但是由于这个项目极具战略意义,客户副总裁是Project Owner,我们将5个人全投入进去,美国那边也投入了全部的资源,所以这个项目还比较有意义。iPhone开发技术见长是一方面,从项目角度来说也学到了不少的东西。

先介绍下背景:
需求方面:11月底来需求,需求不是正规的文档而是一封简单的Email,大体是关于为某行业建立一个全方位的apple平台解决方案,架构是Server + 客户端。这个解决方案以前我们在客户公司平台实现,所以需求较熟悉。
团队方面:能够投入的项目组的有ABCDEF 6个人,其中5个DEV,1个QA。A之前做过一个iPhone项目的UI coding,可认为是高产出DEV,实际他是Tech-Lead,也需要承担沟通的成本。B技术素质好,领悟力高,也做过iPhone项目的自动化测试,有iPhone编程能力,可认为是技术攻关DEV。C也做过iPhone项目,编程技术一般,可认为是一个普通的DEV。D是实习生,聪明但是粗心思考问题不全面,iPhone开发基本不会也错过了之前的iPhone培训,DEV。E是一名成熟的DEV,但是从来没做过iPhone开发,不过他在前期会有其他的事情,所以属于兼职DEV。F实习生QA,没测试过iPhone项目。这里要描述一个事实,人力资源不能变。
设备方面:4台mac mini,2台iPod Touch。意思是最多只有4个DEV可以同时工作。
时间方面:12月底之前完成第一阶段,基本功能实现;之后第二阶段就是把第一阶段做成可配置。

下面是做这个项目的一些经验,感悟和思考:
1. 谁偷走了我的时间?
对于项目而言排一个合理的时间表很重要,一方面是方便追踪项目的进展情况,二方面是给客户信心,因为这是我们团队第一次做iPhone的项目,而且这个项目直接就是重要的战略级产品,客户和我们心里都没底。根据团队方面的背景,有这批没有经验的人开发这么一个产品,我很想把时间线订成2个月,但是事实不行,因为这个产品因为1月份的展览必须12月底交付。
时间线第一个版本就是假设工程师都是成熟的,在12月底可以把所有的功能都交付。我心里没底,但是我知道,如果时间线都不能把所有功能交付,那真实运作起来就一点希望都没有了。
时间线第二个版本是在12月初修改而来,最重要的更新是灵活地根据“复用”原则。比如Functional A 和 Functional B都是非常重要的功能,一般的思维就是重要的功能要先做而且必须做,所以会安排两个工程师一个做Functional A一个做Functional B。但是后来我发现Functional A 和 Functional B从UI上很多东西可以复用,一部分逻辑也可以复用,面对不会iPhone开发的工程师们,可以让有经验的DEV A先做,等做完后,其他的工程师再去“依葫芦画瓢”甚至直接拷贝代码,这样会大大加速Functional B的开发时间。根据这个原则,实际上12月份出这个产品就有很多buffer了,但是这个建立在一个前提下,工程师是成熟的iPhone DEV。
另外一点就是时间线要考虑到工程师的成长性,因为他们的产出不会永远都是“什么都不会的人的水平”。所以一开始就预料到面对这样艰巨的任务,这样的人力资源,要把时间细致地用。比如把一个月分为4个星期,每个星期根据不同的人属性成长安排各不相同。

2. 没有FRD的需求
这个项目没有FRD,基于几个前提:我们团队和客户方项目经理合作两年,彼此间较默契;工程师A和E之前在客户平台上做过类似的系统,对需求很清楚。但是一个项目光知道大体的需求还不行,对于iPhone平台细节的描述是之前没有的,所以有一个FRD则是非常必要的。客户的女项目经理承诺第一周给FRD,后来直到第三周都没能给出来,巧的是团队也刚好从第三周才开始做客户端具体的功能,所以之前影响不大。这个时候QA已经开始抱怨需求不明,对于点一个按钮该如何QA和DEV之间各有各的意见,最后只能求助Tech-Lead。但是诸如此类根据人的判断来定需求毕竟不踏实,于是就发邮件给项目经理要FRD。
以前提到过,项目经理一直忙于1月份展会的事情,所以没能做。有一次电话会议上一向强势的副总裁也帮项目经理低声求情,问能否先不要FRD,有不懂的随时沟通。连副总裁都低头了,再这么也要给个面子啊,于是发邮件给项目经理,大体的意思是“既然你们领导都帮你们求情了,这次就饶过你了吧,不要FRD了,不过我们会加强沟通以确保是你要的”,这邮件让那个女项目经理感激涕零,连夸我们团队专业,让她Very happy。
那怎么加强沟通呢?遇到需求不明的情况,我们会建立一个表格列个矩阵,把所有的情况列出来,然后写入我们的理解再发过去给她确认;或者画流程图,根据FRD屏幕的截图来表示我们对workflow的理解;每天跟她发邮件说今天的情况,以及需要从她那里拿到什么;团队内部每天两个会议,各10分钟或以下,晨会制定今天的任务,晚会总结今天的成果。

3. 你真的做完了吗?
前期DEV A做UI,实习生被安排在DEV A做的UI上面做逻辑(其他的工程师各有各自的安排)。结果实习生很快就来催DEV A做完了UI没有,因为他之前的逻辑做完了, DEV A很高兴因为逻辑做得很快,结果DEV A为了避免耽误实习生做逻辑的时间,特地周末赶来加班把事情提前做完了。结果一测试才发现实习生做完了的意思是“他认为”他做完了,实际上没有,甚至像没有做一样,结果不得不让这次中间版本推延。DEV A就是Tech-lead,因为他的UI做完后其他的工程师可以开始复用,所以DEV A就停止开发,转变为代码评审,专门针对实习生和基础不好的DEV。代码评审结果很不错,找出很多东西,经过总结,各个工程师的开发质量有所提高,也不会再出现“做完了”像没有做一样。

4. 技术能力和项目要求不匹配怎么办?
这个在项目初期就提出了Risk,并有三个解决方案:1. 加班,用时间弥补能力;2. 开通和上海总部资深工程师的沟通渠道;3. 让客户减需求。实际最后这三点解决方案都达到,
加班只用了第二个星期的周末一天,其余每天工作晚一点;
向上海总部的求援信基本都得到回复,而且效果很好;
减需求比较巧妙,不是我们提的,而是副总裁自己提出来的。减的需求都是技术上很困难实现的,我们去问了客户公司一个资深工程师,结果他也说“没想法”,所以副总裁自己就决定这功能不做了。

5. 不同时期,不同角色
DEV A是Tech-Lead,因为有经验所以需要写代码,另外这个项目人员大多不成熟,需求也不明确,所以需要大量的沟通成本。12月的开始两个星期几乎DEV A是最忙的,又要写代码,又要沟通管理团队。直到DEV A的第一个模块UI写完了,DEV A才变身为Tech-Lead,开始做代码评审,开始专注需求分析,沟通,管理。在第二个星期和第三个星期,团队成员开始成长,基本上到第三个星期中期以后,DEV A的角色就彻底消失了,全身

牵着客户还是被客户牵着

在软件开发的日常工作中,经常会遇到这样的场景:客户(专业咨询顾问)发来一个邮件说某项目有个新需求需要对原来的程序进行修改,然后客户会列举他想到的可能的业务逻辑,我们的工程师接到需求邮件后会先看看有没有什么需要补充的或者问题跟客户确认。

通常情况下,这样的需求邮件有70%是需要二次甚至多次确认的,原因如下:1. 业务需求模糊。我们见的还比较少,因为对方是专业咨询顾问,不是真正的客户。2. 需求说明没有覆盖所有的点。项目顾问毕竟不是工程师,思维逻辑没有非常缜密,不是因为项目顾问水平不行,而是因为他不是写代码的,很多业务冲突他在百忙之中不一定想得到。3. 需求改动成本估计。顾问发需求的同时往往会发deadline,说明什么时候必须交。有时候顾问“一句话的需求”在开发这边往往要“改动很多”,这个时候要么开发者和顾问辩论时间要么开发重新理一个estimation。

上周碰到的case是上面的第二点,这边的开发回信问“另外一种情况”怎么处理,用的是"what"开头的开放问题,然后客户回信说她要跟她的客户确认,不过在这之前请执行她想当然的“一句话需求”Plan A。

我在这个开发发出邮件后问他针对“另外一种情况”有无解决方案,他说有Plan B,符合业务需求逻辑并且改动代码不多,但是他没告诉客户他的解决方案。于是客户回复执行Plan A,改动非常大而且不太符合常规逻辑,但是又可以临时地满足需求。这个时候其实我们就被动了,因为是我们去问客户"what",然后客户回了Plan A客户就认为你会按照Plan A去做因为你“不知道”你才问,尽管你是有个备选方案Plan B,如果再提出来就有“怎么不先提出来”之嫌。

回到最原始的工作技巧:提出问题的同时提出解决方案
第一,客户没有开发者熟悉软件。这个软件之前是由一位开发者做的,那么客户肯定没有这个开发者熟悉这个软件,也不太清楚怎么用更合理的代码修改达到预期的业务需求改动效果。
第二,开发者提出解决方案是份内的事。咨询顾问从某种程度说是将客户的需求明晰化,转化为开发者能够看懂的需求甚至帮开发者定制了技术解决方案,尽管如此由于上一条,解决方案并不彻底。这个时候开发者理应通过客户需求和“部分解决方案”获得的感觉,提出“完整彻底的解决方案”然后跟客户确认。而不是又傻傻地回复"what", "how"之类的开放问题,这就相当于把开发者的工作转嫁到咨询顾问做去了。
第三,提出解决方案就占据了主动。正如这个case,其实Plan A和Plan B都可以解决问题,但是如果开发者在第一次确认的时候就已经提出了Plan B,那么客户的思维就不会再随意“发散”而是去思考Plan B,当然客户会同意Plan B。更重要的是,在这一封邮件回复中,开发者已经把客户的思维限定到对开发者有利的局面中了。率先提出解决方案的人从某种意义上讲在“控制”这个局。

那么话说回来,既然开发者已经有这么一个解决方案,他为什么又不告诉客户呢?其实一句话回答就够了,开发者不愿意或者惧怕承担责任
因为开发者已经有一个解决方案,说明他思考过而且结果还不错。不告诉客户是在想“我这个解决方案到底行不行”(不自信),“如果我的解决方案不行,客户或者上司会骂我,或者BS我,我很丢脸”(担心承担责任),“客户说不定有更好的解决方案呢”(转嫁工作,拒绝承担责任)。

牵着客户还是被客户牵着?“客户是上帝”告诉我们应该被“客户牵着”,但是客户之所以找到你帮他工作是因为“你在软件开发领域比他熟悉”。主动提出解决方案,帮客户想到他没有想到的问题,不知不觉你就会“牵着客户”了。

————————-后记————————-
跟同一个客户工作时间久了,双方应该产生足够的默契。软件开发中有很多问题,但是聪明的人不会每个小问题都问,因为问问题同样需要成本。客户希望看到的理想状况是他交给你一个任务,然后你下次接触到他的时候已经把任务做到他想要的一样了。意思很简单,火候到了,双方谁也不“牵着”谁,并行大步向前。

到底该不该发未完成的包

这大概是两个星期之前发生的事情了,这个星期一直很忙,于是没记下,再拖就一个月了,决定今天,现在,记下这个教训。

背景介绍:
一个新需求是关于老系统的升级的,要求team3准备一个升级包,里面包括自动解压安装的批处理和全部文件的升级包。客户发过来的需要升级的文件(注意,只有增量文件,不是全部文件)。
升级包是关于同步服务器组件包,这一块比较熟悉的是team1。
team3是新进团队的一个小伙子,对业务不太熟悉。

这个新需求开始之时,我告诉了小伙子大致的方向,以及他可以用到的资源,包括以前的自动解压安装的批处理,还有他可以求教的team1的同事,于是项目开始了。

项目持续了两天,到了发包的那天(deliverable day)的晚上,发现这个team3的小伙子还在准备包,自动解压安装已经没问题,可是新安装的Server运行不起来。一调查发现,这小伙子直接把这增量文件放到了客户目前的老系统包中,而不是我们目前手里的最新的包,也就是说他只升级了这次业务需要升级的文件,而最基础的Server组建还是用的老的,自然Server运行不起来了。而此时已经很晚了,即使你找到了最新的包,集成上去还不知道对不对,即使对,还需要大量的测试而此时已经没有时间。于是决定跟客户说今天不能发最终版本的包。

只不过有个小小的分歧:
到底应不应该把这个未完成的包发出去?

team3小伙子的观点以及其他团队成员的观点是:没完成就不该发。
我的观点是:这个包是没有完成,不过这个项目本身分为两块,第一是自动解压安装流程的批处理程序,第二是新升级后的Server要是运行无误的。我们虽然今天没能按规定时间完成,但是我们可以把我们已经做的工作给客户预览下,他可以提意见反馈。并且我们在邮件正文中强调告诉他这不是最终版本,里面有问题,我们明天会调查原因并完成它。由于客户本身也是技术部门,产品是他们做的,我也想让他看看新包是什么原因不能运行。

于是按照我的观点发出去了,而且邮件写得很清楚,包不是最终包,希望客户给点建议。

结果是客户有个不好的习惯–“他不喜欢看所有的邮件”,基于一系列机缘巧合,他知道我们发了包,但是不知道这不是最终的包!于是,开始责怪和质疑。根据“客户永远是对的”原则,这次错在我。

经验总结,关于该不该发未完成的包:

如果提交对象是非技术型客户,不能发,因为没有任何意义;

如果提交对象是技术客户,谨慎考虑,尽量不要发。如果实在有原因要发,要在邮件写清楚,并且注意把握可能发生的风险。

发未完成的包都会因为误解、沟通丢失等带来各种各样的问题,决定发的人要为此负责。

早点给code请个医生

有这么一个场景:

一位穿白大褂的医生脸色凝重地走进ICU(重症监护室),对躺在病床上的70岁老人的家属说:太太,CT显示您先生大脑里有一恶性肿瘤,不过这个恶心肿瘤现在是可以通过手术来完全移除的。
太太:那好啊,什么时候安排手术?
医生:不过。。您先生岁数太大,身体机能无法承受手术中的创伤。虽然手术可以完全移除肿瘤,但是只怕先生挺不到手术结束了。
太太:那怎么办?
医生:那就保守疗法,将就活着呗,直到自然死亡。虽然会有痛苦和随时死亡的风险,但是比在马上的手术中死亡要好。
太太:……

与此同时。。。

一位穿着衬衫的高级软件工程师脸色凝重地走进办公室,对底下的工程师说:你的代码在项目结束前的Code Review(代码评审)中发现一个严重的性能瓶颈风险,现在体现不出来,但是在客户那边数据到达一个数量级就会体现出来了。。还好我已经有解决方案了。
工程师:那好啊,现在开始改?
高级工程师:现在来不及了,项目已经接近尾声。这个项目必须在明天提交客户上线,现在做出如此多的变动风险太大。
工程师:那怎么办?
高级工程师:先发给客户呗,在Release notes里面写清楚风险。随后我们开始做软件更新,然后再发个Patch过去。不过这段时间成本客户是不会给钱的,而且客户满意度会因为这个patch下降。
工程师:……

上面的两个场景有一个共同的尴尬:有一个解决问题的方案,但是因为时间(或者岁数)的关系来不及执行下去。
引发这种尴尬的核心原因是:发现问题太晚,总是在deadline前后发现。

项目背景介绍:
一个团队有4个项目组,每个项目组负责不同的项目,甚至有的项目组是daily deliverable。换句话说,4个项目组每天都很忙,其次是每个项目组不知道其他项目组项目的细节。
公司的SQA制定了流程有Peer Review(同事之间互相看代码)以及FTR(Formal Technical Review,正式的Code Review)。Peer Review一直没被很好的执行:
第一,没有正式的写入流程框图,给成员感觉只是“建议”(Rec.)级别;
第二,其他项目组成员不太熟悉本项目的细节,觉得看得效果不大;
第三,本项目组成员忙得焦头烂额,更不想找另外一个人来找自己的碴,而且其他项目组成员也很忙不太好意思请别人出来。
基于以上客观和心理状态,所以一个项目基本上就是开发测试交替进行,然后到项目完全开发完后,安排一个FTR。也就是下面这张图:

从上面这个图可以清晰地发现,Code Review放在最后。之前的Testing主要是QA做的黑盒测试,而有些Bug在不看代码做白盒的情况下很难测出来,现实是QA很少有做白盒看代码的能力,于是所有“别人看代码”的工作被放在了项目的后期。这样带来的结果是:
1. 一些小的Coding style和比较容易改的Bug被改掉;
2. 一些需要改动多处,改动Common function的Bug因为时间关系被Pending。因为QA之前完成了测试,如果再次改动关键被引用点,那么QA需要从头到尾彻底地重新测试一遍才能确保改动有效且不会引入Regression bug(即因为改动其他Bug而引入的新Bug),而deadline已经不允许这么干了。
可以容易发现,第二种Bug的改动价值更大,能够更大的提升软件质量,但是因为时间带来的风险原因而不得不“明知道是Bug,但是不改了”。

针对这个问题,我们来看看基本上被弃用的原始版瀑布开发模型(讲解使用,切勿模仿):

Testing在最后才引用进来,中间没有迭代Testing。DEV一条道开发到黑,全部开发完成后,然后QA开始测试。现在看起来都比较可笑,因为Bug是越早发现越好,越晚发现,修复bug的effort(成本)会成倍增加。Testing如此,为何Code Review不如此?

现在的解决方案是:
1. 增加Code Review Sprint。在项目的编码和测试阶段,会有3-4个左右的迭代deliverable,那么在每次deliverable之前,必须组织一次Code Review。具体的时间可以根据各个项目组的繁忙程度灵活调节。
2. 将Code Review Sprint写入流程,并且准备好合适的文档Excel表格用来提交Bug和对Code Reviewer的效果统计,确保执行力。
3. 每次Code Review Sprint大概持续时间是半小时到一小时。
4. Code Review Sprint发现的Bug种类有Coding Style, 算法逻辑,代码的严谨性,甚至Business Logic。
5. 在每次需求分析阶段可以适当引入不太忙的其他项目组成员,他们不用知道太多业务逻辑,只要知道大概业务逻辑和软件大功能点,以便日后做Review。(在软件行业的人混长了都有感觉,看界面就能大概猜到基本的UI逻辑)
Test Case Review Sprint亦如此,找其他项目组的QA来Review 本项目组的Test case,确保Test case格式正确,功能的覆盖面,正反测试用例的比例。
这样一来,很多关键Bug或者影响性能的瓶颈Risk能够在早期就被发现并被扼杀在摇篮之中,改动的Effort很小并防止了对以后代码的进一步影响。当然由于时间和资源有限的关系,这种Code Review可能不彻底,所以最后仍然加上一个FTR,做一次全项目组的技术评审。(题外话:其实很多人不太重视Code Review, 公司SQA在统计中发现Code Review中发现的Bug价值比黑盒测试中高10倍以上)

最近的一次项目尝试使用上面的方案,客户在电话里面说非常满意软件质量。

于是,就出现下面一个场景:

一位穿白大褂的医生表情轻松地走入了病房,对一个躺在病床上的小伙子说:CT显示你的大脑里面有一颗良性的肿瘤,现在用手术可以轻松解决。但是如果现在不做手术,你70岁的时候可能要在ICU(重症监护室)里面度过了。
小伙子:谢谢医生,现在可以手术吗?
医生:嗯,马上!

与此同时。。。

一位穿衬衫的高级软件工程师表情轻松地走入办公室,对一个正在埋头写代码的工程师说:刚才我花了半个小时做了个Code Review Sprint,发现你的代码里面有一处性能瓶颈风险。现在如果不改的话,那么将对以后的代码造成严重的影响,最后到客户那边的大数据负载下会不堪重负。
工程师:谢谢,您辛苦了,现在我可以将改动Commit进去吗?
高级工程师:嗯,马上!

今日事,今日毕

一个人如果没有目标,就会迷失,就会拖沓,就会慢下来。

这句话用在大方面可以上升到职业或人生规划,小方面则可以具象到每天的工作。

背景

4月的一天,我被各种会议湮没。回到团队的时候,发现什么事情都没做完,很多工作才刚刚开始,于是当天晚上奋战到10点。走的时候跟经理说,我要去调查谁偷走了我们的时间。

调查结果

4个项目组中,主要有两种原因:

1. 没有目标。

团队成员知道任务有很多,今天也不一定全部做得完,但是也没有任何想法或者计划今天该做什么,该做完什么,于是没有计划地一路前行。没有目标驱动的情况下,人是很容易懒散的,所以工作中经常被各种事情打断,然后人就转入各种小事情的处理上,真正要做的主要工作却放下了。这就导致了快下班的时候一查看进度好像刚刚开始。

2. 忘记目标。

有的项目组任务单一,今天就是把这个任务搞定。但是程序员实际在做的时候,往往陷入了某个细节(某个算法)无法自拔,忘记今天的目标是交东西,不是研究这个算法。结果一天下来,算法还是没有研究出来,产出也为0.

对症下药

1. 在每天的daily meeting上,当每个项目组汇报项目进展情况的时候,增加回答两个问题

Q1. How much work do you think you can get done today? (今天你认为你可以完成多少工作?)

以前汇报的时候只是说“今天我们组将继续什么什么工作”,但是这个问题是强迫要求成员思考“今天我要做完什么事情”。一个参考的例子回答是“今天我将做完TaskA, TaskB 和 30%的TaskC”。注意问题是“你认为”,意思是作为项目组长应该有这个意识去主动思考和把握项目进度,而不要再让主管来告诉你今天“你应该”做什么事情。回答这个问题就让组长和组员对今天的目标心中有数。

Q2. How much percentage of that work do you think you can get done before 5:30PM? (你认为在下午5:30之前多少比例的事情可以做完?)

这个问题是用来提醒团队成员我们的标准下班时间是5:30PM,尽管IT行业经常加班,但是注意不要把你的下班时间默认设置到8:00PM之后,因为这个想法十分危险:你每天的工作时间无形中默认增加了几个小时,所以你可以享受上班时间不太有压迫感的节奏,你会对此上瘾,但是你的工作效率会无比低下,你会丧失工作之外生活的乐趣。这想法就像毒药一样,当时很有快感,长期以来身体和精神上都受到摧残。

另外一个作用是可以锻炼组长估计的能力(estimation),也许你前几天估计都与实际结果相差很大,但是你注意总结之后慢慢你的估计会越来越准。

一个参考的例子回答是“今天我在5:30之前能够完成今天全天工作(全天工作的具体是Q1的答案)的80%”。那意味着还有20%是晚饭后回来完成的。

2. 针对一个项目组有多个人,一天有多个任务,所以在daily meeting之后,要和项目组成员碰一下,具体什么人完成什么任务,这个时间大概是半分钟到1分钟

3. 对于“忘记目标”,有时候程序员因为个性原因是不容易跳出来,这就需要管理人员去为方向上把舵

举例:客户抱怨性能很差,经过调查发现是排序导致性能问题,但是不管怎么改变排序算法在移动设备上都会因为硬件性能瓶颈造成性能问题,还有可能因为真实数据导致性能问题加倍。于是不要再去研究“更好的排序算法”,对于今天而言,我们至少可以提交一个解决方案:取消排序功能。然后列出理由让客户明白,在当前状况下取消排序功能对用户体验影响非常小,问是否可以被接受。第二天,客户默默地将此defect关闭。

解决问题有很多方式,一种是直接正面解决掉,第二种是想办法绕过去。不管黑猫白猫,抓得住老鼠就是好猫。

效果

实际效果还不错,感觉上每天下班确实早了(没有数据统计过),团队成员在有目标的情况下做事也更积极带劲了。这一方面是任务不同造成的客观原因,一方面也有“药力”的作用。相信坚持下去,每天投入产出比曲线会保持增长。

对于一个每天都必须要有产出的团队,我们的风格是“敏捷”,我们的目标是把事情搞定。(Get Things Done)

 

技术是死的,人是活的

上一周的工作对我很有启发,本来想在周会上分享给大家的,可是后来谈我们的新年目标“敏捷”去了,由于时间关系也没有再多谈一周感悟了。

简单的说这周工作中的思考来自于和团队成员的几次争论,我是站在实用的观点,对方站在技术的层面,总结出来有三点:

1. 不要让技术指导业务

这里的业务不仅是指商业上的业务逻辑,也包含常理的意思。技术人员在讨论问题的时候往往容易陷入一个比较荒唐(ridiculous)的思路:先想技术的实现,然后再想业务逻辑。

这里有两个例子:

a). 某业务讨论会上,在场有DEV和QA。我们对某种屏幕跳转方面的逻辑不是很清楚,而且需求说明(FRD)上又没有指出,于是大家都在说自己的观点。某QAMM说话:我觉得应该是从A屏直接跳到B屏,当时用户完成了某种操作之后。。这里的record还没有创建。。那么肯定要先到B屏才能完成record的创建工作。。。我不得不站出来打断,等等,你是在分析业务逻辑,不要把技术的层面加进去,这会形成混沌(chaos)。你作为QA你的业务层面比DEV高,你就只站在用户的角度去分析这里的用户体验应该怎么样,然后我们DEV再来分析技术上的实现问题,技术上不能实现再说,而你不要帮我们分析技术的可行性,尤其是当你在分析业务的时候。

Comments: 从本例中,思考的方式比结果更重要,思考的方式不对即使结果对了,这样的成功也是无法复制的,而且会对未来的设计更大的架构带来隐患。

b). 技术上的DEV之间的讨论。对整形数组进行排序,排序规则自便,只要求客户和我们排序方式一样即可。比较两个整形之间的大小我们通常用>, < , == 之类的运算符,这也符合常理。可是某DEV认为,现在已经有现成的比较字符串的ASCII码进行排序,何不如把整形转成字符串然后用ASCII码进行排序。争论了半天,终将其说服:用整形大小排序比较符合常理,而且设计实现非常简单,并不会耽误我们很多时间。如果为了节省这么一点时间或者因为偷懒而用现成的string算法来排序,诚然是可以的,因为只要求客户和我们排序方式一样,但是会令人感到奇怪,这个非常荒唐。而且从技术角度来讲,这样的算法效率性能并不好。

Comments: 设计方案是给人看的,除非是遇到技术瓶颈不得已用非常猥琐的办法做之外,尽量用符合人之常情的做法,因为技术本身就是对业务的抽象实现。

先想技术的实现,然后再想业务逻辑。这种本末倒置的思考方式是被必杀的。当然也有例外,比如业务逻辑用现在的技术实现不了,或者用的代价太大,那么可以反过来通过思考技术实现来引导出来一个大家可以接受的业务逻辑替代方案,然后跟客户交涉:您的“业务逻辑实现”(注意是业务逻辑实现,不是业务逻辑)稍微改动那么一点点,可以加快项目的进程,从而让您省钱。

2. 设计模式不如实用模式

DEV之间讨论技术方案:一种方案是用三个参数的函数,另外一种是用两个参数的函数。其中都要有个描述排序规则的函数地址作为参数,第一个方案通过第三个参数描述是倒序还是正序,第二个方案则需要写两个函数来实现正序或者倒序。据某DEV说,第二种方案根据设计模式来(未证实),实现正序倒序与排序原函数分离。我要大家扪心自问一下:到底是哪种方案方便?第一种对于每种类型或者每个对象只用描述大小关系即可,而第二种设计模式主张的,需要描述正序或倒序。第二种方案每遇到一个排序需求就得写两个函数来实现倒序顺序,而且大量重复代码,只是返回值不一样。那要是作为一个公共方法,遇到一个大型的系统,那不写死了。

这里不是否定设计模式,而是希望灵活运用设计模式,毕竟在商业软件开发中要注重成本。同样的道理,用最简单代码实现的最优算法不一定好,团队其他成员都无法理解,给后期维护带来隐患。中国别的不多,就是人多,用if else堆来实现逻辑大有人在,虽然很丑,但是很实用。

Comments:马谡:书上说的居高临下,势如破竹,我要在山上扎寨。王平:丞相嘱咐过,万万不可啊,人家围山切断水源放火烧山,后果不堪设想。应该依山傍水,当道扎营。请主将三思。马谡:滚。。书中自有黄金屋,书上再找不到比这更好的设计模式了。。。魏军大喜果然围山并放火,蜀军大败,痛失街亭。诸葛亮不得不挥泪斩马谡,战略上退回汉中。

3. 最难的是承认错误

DEV之间讨论技术方案:某DEV想从数据库里面取出数据,放在一个内存的临时空间,然后遍历这个临时空间,再放到我们的目标临时空间。我认为很奇怪,为什么要放中间一个临时空间而不直接取出数据放到目标临时空间呢?他认为他可以用3行for循环代码简单的实现,而直接放要hardcode太丑了。。我说你这样影响性能,特别是在移动设备上,而且你的方案需要在前期hardcode 20行的数组来实现也很丑,最主要的是这个思路太荒唐了。不服,怎么都不服,于是叫来主管做评判。。评判很快出结果,于是某DEV推翻了以前的作品重来。。翌日,跑过来跟我说,改动之后性能果然提高了很多,而且代码更精简。。。

技术人员都有个心理:在技术上不服输,坚持自己的观点。这点挺好,但是如果在事实摆明的情况下依然坚决捍卫自己的代码,那就是不明智了。其实犯错很简单,因为是人只要活在这个世界都要犯错;不犯错也很简单,在自己容易犯错的地方多注意点,多检查几遍;最难的是当自己的错误被别人指出来后,勇敢并大气地承认错误,并推翻自己之前的方案重新来过。

Comments: Engineer protect his idea and the code which has been written, I respect his idea and his code, but I respect the right logic more.

嗯,技术是死的,人是活的。

 

一些基于大系统更新bug的经验

 

在最近的一段时间,工作上经常会扮演团队管理者的角色。随着新人慢慢适应了新环境,接下来要让他们真正成长的重任落到了我的肩上,当然,这也是我成长的过程,也是团队成长的过程。

上个星期接到了一个任务,我们开发的一个最大的系统在经过了上线的考验后,又来了一批共8个的需求更新。我想了想,决定让新人来做这次更新:如果让熟手做可以很快做完,但是新人又会少一次成长的机会;新人一上手就这样大的项目更新是有风险的,于是为了控制风险:新人写代码,熟手来看他们更新的代码并负责测试。这样在有效控制风险的同时,新人也得到了锻炼。

还是以案例来说,以下几个案例很有趣值得人思考:

1. 不注重用户行为的一致性(consistency)

有一个需求是需要用户在不完成一个item之前不能在items之间切换,用户如果切换,便弹出窗口提示。于是新人J做完了,我看代码并测试。发现行为不一致:用户有三处地方可以切换items,但是这三处地方的行为细节不一致,有两处是先弹窗后跳转到没有完成的页面,而有一个地方是先跳转到没有完成的页面再弹窗。我给他演示了一遍他写的代码效果,他没有发现有什么不同。

点评:用户的一致性在产品中非常重要,同样的规则用户不希望在这个按钮上是这样的处理效果,在另外一个页面的那个按钮上另外的处理效果,这样用户会感觉到迷惑(confuse),以及不习惯,这是有损用户体验的。

解决方案技巧:尽量跟已经上线的功能特性相同。比如已经上线的处理是弹窗,那么现在也弹窗。

2. 只看自己要更新的需求描述。

新人H被分配更新第五个需求点,于是他猛看第五个需求点并马上改完了。不过同时提出一个业务逻辑上的冲突(conflict)要我跟客户第二天确认, 我当时答应下来。不过回到家后想了想,发现第八个需求点把我们的担心给解决了。于是第二天把新人H和新人J叫在一起(新人J负责第八点需求),让新人H给新人J讲讲昨天他提出的业务逻辑的冲突,于是新人H讲了,不过马上新人J就提出了质疑的观点,因为第八点需求让冲突消失。

点评:其实每次的更新需求文档是个整体,在看分配给自己的任务同时,要过一遍所有的需求点,做到心中有数。因为客户的水平还没有到把所有需求都分类好地发给我们,所以需求需求之间也许是有关联和制约的。

解决方案技巧:开发人员除了自己的任务外,可以大致扫描下整个的需求更新范围;管理人员应该在开始就把所有的任务分配到个人,而不是按天今天分一点明天分一点,这样管理人员可以初期把相关的更新分给一个人,如此便可以避免这样的情况发生。

3. 不抓住本质核心

有一处更新,因为涉及到的逻辑比较多,所以如果想不到核心点上去就得花很多功夫。我一开始便想到了这个点,但是我故意没有说,而是让新人们去想该怎么办。于是三个人先用英语在办公室,然后用中文在会议室,花了两个小时的时间,提出了7种技术解决方案,一种比一种复杂,改动更多,而且最后能不能实现以及会不会带来二次bug(regression bug)都不知道,差点都想求助客户了。我提出了我的观点,站在业务逻辑上,只用简单的代码就搞定了需求。

点评:在改bug之前,一定要对业务逻辑一块熟悉,至少对那一块的业务逻辑熟悉。不要一上手就马上想用什么样的技术解决,往往最简单的东西是最厉害的。仔细理清思路,抓住最本质最关键的点然后解决掉,比在表面上想来想去好得多。

解决方案技巧:如果对业务不熟悉或者思路很乱,通过用笔在纸上画图或者到会议室用白板画图是个有效的理清思路的办法。找到核心点往往用简单的技术逻辑便可以解决,不用搬重型武器了。

其实在修复bug的时候,特别是针对这样的特大系统,思考力变得重要,开发人员不要仅局限于某一块任务,也不要上手就开始写代码,多思考可以让人尽快抓住bug核心,从而用最少的代码解决最正确的问题。

在这整个作业流程当中,特别是第三个案例,在我们会议室交流了两个小时的时间里面,发现了大量的沟通问题:往往两个人对话,听别人讲的那个人往往看似听到了,其实什么也没听。在沟通中不会听是致命的,这些沟通方面的问题暴露,大大坚定了我下一步抓沟通的决心。