原文地址: http://www.agiledon.com/post/2008/03/Deadline-Solution.aspx
最后期限(Deadline)是软件从业人员必须面临的最大困难与挑战,准确地说,它是所有程序员包括项目管理者的可怕梦魇。当堂吉珂德看到郊野之上的数十架风车,风车的翅翼如巨人的胳膊,正耀武扬威地奚落着这位中世纪后期没落的骑士时,堂吉珂德如勇敢的斗士一般,跃马而上,用长枪狠狠地刺向风车,换来的却是长枪折断,人仰马翻,最后大败而归。没错,最后期限之于程序员,正如风车之于堂吉珂德,确实是太强大以至于无法战胜。
那么,我们真的要知其不可为而为之吗?就像孟子老夫子说的那般,虽千万人吾往矣!虽然充满了风萧萧兮易水寒的悲壮,但铩羽而归的感觉,无疑会一次次挫败程序员的信心。更重要的是,IPO变成了负值,投资方是否还能够将项目交付与你呢?
风车看起来是不可战胜的,但如果善于分析风车的关键,找到其“罩门”,也未始没有击破的可能。例如,我们可以找到风车的枢纽部分,击破一点即可使其全线瓦解。有时候,最后期限真的是貌似强大,但若能仔细分析,认真对待,也未尝不可突破壁垒,找到制胜之道。
我曾经参与过多个项目的开发和管理工作,坦白说,最后期限总是如内心的毒蛇一般盘绕,始终是挥之不去的阴影。在客户的声声催促中,就像是听到了定时炸弹最后计时的“嘀嘀”声。明知炸弹就要爆炸,自己却无能为力,这样的感觉令人沮丧。我的一个长处是善于从失败中挖掘教训,所谓“亡羊补牢犹未晚”,即使这个项目失败了,至少在下一次项目中还存在成功的可能。总结下来,大约有如下几点可以用来对付“最后期限”。
1、与客户协商最后期限。听起来是一个笑话,如果最后期限可以协商,就不成其为最后期限了。然而,固执的管理者们,为何要未战而退,却不尝试一下可能会出现的万分之一机会呢?当你充满绝然的勇气与神情去面对客户,以专家的口吻斩钉截铁地说道:“没错,按照您规定的最后期限,我们绝对能够完成您的要求。只可惜我们却没有充分测试的时间。您是否愿意给出测试的时间,这样我们就能够交付一件让您绝对满意的高质量产品了。”或许你得到的是断然的回绝,然而如果你能够合理有效地与客户协商,仍有回旋妥协的余地。前提是,当你在向客户倒苦水的时候,千万不要说产品在最后期限之前无法完成。因为这个最后期限往往是你的市场代表为了拿到项目而做出的一次妥协决定。如果你否决了这一期限,会让客户怀疑你所在公司的诚意与能力。关键是质量!因为对于客户而言,时间固然是一个决定因素,但高质量的产品才是最后的关键。尝试与客户协商,或许你会冲破最后期限的壁垒,看到海阔天空,呼吸一口新鲜空气。
2、与客户协商功能要点。如果不能从时间上做文章,那么就另辟蹊径,在功能上夺回你失守的阵地吧。功能总是有轻重之分的,将那些可有可无,或者是客户不太关注的功能砍去,就等同于你争取到了更长的时间。想想那些已经投入使用的产品吧,例如微软的Word。我们可以做一下调查,世界上的所有Word用户,有多少人全部使用过Word的所有功能?或者我们从使用概率来分析,产品中还有哪些使用概率不超过30%的非关键功能点?找到这些功能点,打印一个清单,然后鼓动你的如簧之舌去与客户谈判吧。或许,你能得到一个理想的结果。
不幸的是,你碰到了一个极其顽固的老古董客户,就像那些整日呆在办公室里无所事事,却有着鹰隼一般锐利的目光,专以折磨人为乐的奴隶主监工一般。他们不会听取你的友好协商,而会像孩子一般,关闭上两只耳朵,只是抱着手里的玩具使劲摇头,即使你递给他的玩具可能会更漂亮更好玩,他仍然会固执地抓住自己的玩具死死不放。现实世界中,我们总会碰到这种情况,我们会在客户那里碰得头破血流。那么,我们该怎么办?
让我们从开发过程中寻找答案吧。唐柳宗元道:“苛政猛于虎”,我们常常会畏“最后期限”如虎,然而殊不知错误的开发过程或方法有时候会比这条“虎”更为凶猛!此外,我们还可以从计划执行、任务安排、团队合作等诸多方面找到可以挤出来的时间。这个时候,项目管理者必须像葛朗台老头一般,精打细算,珍惜每分钟项目时间的运用。然而,项目管理者绝对不能因为时间紧促,而像周扒皮那样半夜学鸡叫,让团队成员加班加点,像牲口一般的对待。偶尔为之,或许无伤大雅,然而每日都如此,那么只能说明这个项目已经到头了,赶紧准备失败的毒药吧。因此,我们要做到:
1、合理裁减开发过程。在项目管理过程中,必须执行相应的开发流程,例如计划评审、同行评审、阶段评审等。此外,QA会拿着众多检查点,每日走查项目组是否在质量保证方面存在缺陷。因此,在项目周期紧张的情况之下,项目管理者与QA就必须针对项目的实际情况,合理地裁减开发过程,省去一些不必要的官僚会议以及QA检查的表面文章。同时,随之而来的利益则是大量工件,尤其是文档的减少。如果能够让开发人员能够从文山会海中解脱出来,谢天谢地,他会成为项目开发的急先锋。要知道,世界上所有的程序员都在为文档的编撰而苦恼。减少文档不等于说不写文档,即使是敏捷开发,注重代码与可工作的产品胜过完整的文档,仍然不会忽略基本文档的编写。虽然在对需求和设计进行分析期间,我们可以考虑用面对面交谈的方式,或者在白板上写下我们的设计方案,但为了项目沉淀或者产品维护与重构,以及考虑成员变化等种种因素,文档的编写仍然是项目开发中不可缺失的重要环节。关键是编写文档的“度”。敏捷的布道者Alistair Cockburn在其书《敏捷软件开发》中写道:“团队成员应当在为将来的使用而超支的成本与未来文档不足的风险之间进行平衡。找到两者之间的平衡点是一门艺术……”我对那种形而上学的开发过程管理深恶痛绝。为了通过阶段评审,我们必须要腾出时间来编写阶段评审文档,然后请来那些大多数尸位素餐的评审委员会专家,然后不痛不痒地提出几个缺陷或错误,最后一团和气的结束会议。显然,这是一种官僚思想,是集体的资源浪费。即使为了某些办公室政治考虑,那么项目经理也应该像牧羊犬那样,保护自己的团队成员免受这方面的干扰,就像Scrum所要求的那样。
2、合理的设定功能优先级,并以此制定开发计划。这里我们可以玩弄一个花招,即使我们无法在客户那里寻求到裁减功能的支持,但我们仍然可以在功能优先级方面大作文章。例如将客户要求的优先级高的功能,以及技术实现必须的高优先级功能先行实现,那么,到了最后期限来临之际,即使我们还有一大堆低优先级的功能未曾实现,但由于客户最关心的功能点能够高质量地运行,最后的产品虽然没有完全满足客户的需求,但凭借着优先级的合理划分,也可以让我们在后面的商务谈判中占据先机。此外,我们还可以信誓旦旦地向客户承诺,我们会在交付产品之后,继续完成剩下的功能。客户是否完全满意,谁知道呢?但至少我们交付了产品!以己之见,虽然这个产品不够全面,但总比交付一个全面的产品,却错误频现要来得好。
3、提高会议效率。无论是传统的软件开发方法,还是敏捷方法,在软件开发过程中,不可避免要召开各种各样的会议。毕竟软件是人开发的,而且是组成一个团队的人开发的,因而交流成为必然。我并不反对召开这样的会议,相反,我很乐于参加这样的会议,因为这样可以让我的口才在全体同僚面前得到充分地展示。然而,会有多少的宝贵时间淹没在这样的夸夸其谈,或者口沫横飞之中啊!与其要求团队成员加班加点,还不如提高会议效率。我很认同Scrum对于会议时间的明确规定。例如Sprint的计划会议保持在4个小时,而评审会议和回顾会议则保持在2个小时左右。至于Scrum的每日例会,更是短小精悍,只有15分钟。是谁发明了“站立会议”这个名词呢?发明者完全就是一位天才!改传统的枯坐会议为站立会议,就可以收住那些夸夸其谈、口若悬河的家伙了。在我的一个团队里,就有这样一个家伙,总是啰里啰唆,讲了半天也说不到重点。我每次看到他要发言,我就有头晕的感觉,甚至有一种冲动,想用胶布封住他的嘴。不过,在我主持会议的时候,我常常发现会议成员看我的眼神,有几分熟悉。会议之后仔细思考,发现他们看我的眼神,和我看那个家伙的眼神竟然惊人的一致!Larry L. Constantine在《人件集》的“因地制宜”篇中写道:“如果想要团队工作获得最大成功,会议的主持人和记录者都应该以局外人的身份参加讨论会。……作为整个团队的最高负责人,项目领导者应该积极参与团队中的讨论和工作,而不是对工作指手画脚。……会议应该是在一种中立的气氛下进行。……另一方面,……陷入无休止的争论中,这时候,最好由项目领导出面中止争论,暂时地放开当前的话题,或者很偶尔的,如果话题已经进入了死锁状态,那么就由领导做出一个仲裁。”
4、合理安排人手。通常在我们面临最后期限的压力时,第一想到的是加班,然后闪入脑海中的念头则是增加人手。加班策略素来为我所唾弃。以每人每日的生产效率来看,虽然加班可以延长工作时间,但长期的过度疲劳必然会降低生产效率,如此以时间换来低下的效率与团队成员的抱怨,完全得不偿失。在长期积怨的情况之下,开发人员会产生一种破罐子破摔的思想,心里认为反正都要加班,那么在正常上班情况下,反而会“磨洋工”,敷衍搪塞项目经理安排的工作。那么增加人手呢?且不说这会增加项目成本,我们还要考虑团队的新兵需要多长时间才能上战场?业务培训、团队磨合是新增成员必然存在的两大痼疾。如果没有处理好这两个问题,不仅不能提高开发进度,反而会有拖慢或者打乱原有开发节奏的危险。另外,如果添加的新手不幸是一个刺头或者“害群之马” 呢?需要明确的是,往往在项目经理提出增加人手的情况下,项目经理并没有亲自挑选新成员的权利。这些新成员要么是闲置的,要么是其他团队转过来的,要么是新招聘的。考虑前面两种情况,你觉得这样的成员能够达到及格乃至于优秀的几率会有多大呢?如果是新招聘的,那么拜托,赶快在心里多念几遍“菩萨保佑”吧。总体而言,如果项目经理没有挑选新成员的权利,最佳的选择是非到万不得已不要添加成员。所谓“万不得已”,即是无论如何改进,如何协商,如何提高效率,都无法达成既定目标的情况。
兵贵在精而不在于多。关键在于知人善用,以及合理调度。一个项目经理在组建自己的团队时,必须要了解自己成员的人格特点与技术特点。在理想状态下,如果项目经理具有挑选成员的权利,会具有更大的成功率。如果项目过大,那么必须建立层级式的组织架构,而在划分出的各个小组中,却应该以扁平的平等架构为最佳。这样就能够自由而不失于集中,平等而又不至于缺乏效力。当然,具体的组织架构应依据企业文化、产品性质、开发规模、团队成员特点等各个因素综合考虑,不能死搬硬套。在安排人手时,要注意对技能型人才和管理型人才的使用,注意对领域专家和系统架构师的使用,注意对开发人员和测试人员的使用,注意对编档人员、QA、配置管理员的使用。此外,还需要养成从容不迫的心理,即使最终期限火烧眉毛,迫在眉睫,仍然要保证对架构的设计、对编码的测试以及合理考虑产品性能、可用性和产品质量。
5、开发环境的保护与基础设施的维护。兵家云:天时、地利、人和。没有一个好的开发环境,很难想象开发人员能够高效率的工作。开发环境必须是相对独立,又利于交流与沟通的工作室。具体的说,项目组的工作环境必须拒绝项目无关人员的干扰与破坏,但却无阻于项目成员,特别是同一小组成员的交流。此外,会议室的数量非常重要。我在管理一个项目时,竟然常常为寻找会议室而东奔西走,将大量的时间浪费在会议准备上。此外,服务器、客户机、网络、打印机、白板、卡片,以及开发工具和软件,例如IDE开发环境、版本控制工具、Bug管理工具等,都需要在团队建立之初就要准备好。对于计算机、网络和相关工具,则必须保证在项目开发期间的稳定性、畅通性。我曾经在项目开发中,因为网络中断、病毒侵袭以及服务器坏掉从而破坏了SVN的版本管理等诸多突发事件,让我在本来就紧张的开发时间里,牺牲了不低于三天的时间,真是让我抓狂不已!所以说,一个好的网络管理中心、一个好的配置管理员,在关键时刻,可以抵得上半打高效的开发人员呢。如果你在项目开发过程中,频繁遭遇这样的问题,我的忠告是,赶紧准备换一家公司吧。
6、合理控制需求变更。需求变更是软件开发必然遭遇的暴风雪,也是导致“没有银弹”的渊薮。传统的瀑布开发模型在项目后期遭遇需求变更时,只能束手无策,但RUP与敏捷方法却能够坦然面对需求的变更,Kent Beck甚至在敏捷开发中提出了拥抱变化,真是足够勇敢与足够信心的宣言啊!在软件开发中,若要应对软件开发,一般的做法是合理设计,以求系统与架构具有足够的可扩展性;其次则是采用迭代的开发方式,通过定期甚至是短周期地交付可工作的产品,以印证需求与实现是否一致。同时,在项目中通过引入客户的积极参与,使得项目组与客户的交流能够畅通无阻,从而避免因为隔阂而导致需求分析产生的误差,以及需求变更无法及时提出。此外,利用原型快速开发方式,可以尽快地交付一个无具体实现的产品框架或原型,以验证业务规则、业务流程以及客户对GUI的要求。然而,需求变更绝对不能无休止地进行,这会导致迭代的永无眠日。即使是敏捷开发,我们仍然要设定客户委托事项的基本线,一旦超出这一基本线,变更委员会(CCB)或其他担负这一职责的角色就必须提出异议,与客户协商或探讨这种变更是否是必须的。控制需求变更的一个实践是,获得客户对分析出来的功能点的书面确认。虽然在发生变更时,客户的意见甚至可以无视这种书面文章,但至少可以在与客户的谈判中抢得先机。根据Mark Lines所说,通过变更控制的增强还可以降低项目风险。确实如此,在与客户谈判中,我们要学会说出“拒绝”两个字。当然,在对需求变更做出决定性意见之前,必须分析判断这样的变更是否合理,是否必要,或者优先级高。一种折中的办法则是,欣然承诺此次变更,但需要延迟最后期限,或者放在下一次版本迭代之后。
7、预先评估风险。风险无处不在。Cockburn将软件开发形容为攀岩或者穿越沼泽,已经充分说明了软件开发过程中的风险。孙子兵法云:夫未战而庙算胜者,得算多也;未战而庙算不胜者,得算少也。先预先着失败的可能,方能够谨慎地做好各种准备,考虑各种风险以及驱避措施,方能够最大可能地取得胜利。软件开发的风险有很多,其中至关重要的是进度风险、技术风险、需求变更风险、成员变动风险。
软件是可以度量的吗?看起来是,因为已经有了很多方法来完成软件的度量。从控制学的理论来看,你无法控制那些你无法度量的。因而软件度量对于控制软件开发而言,就成为了关键。软件度量甚至因此成为了一门学问。然而,我可以肯定地说,软件的度量不可能准确,尤其是对进度的把握而言。即使一个项目的开发周期看起来是如此的充裕,以至于感受不到最后期限的压力,我们仍然要对软件进度的控制采取如坐针毡的谨慎态度,即使这样在某些人的眼中,我成为了持怀疑论者,或者悲观主义者,我仍然愿意背着这样的名身恶意地怀疑项目时间不够。原因有二。其一是我们的工作量估算无法做到精确,即使是经验丰富的天才程序员,在估算项目的整体工作量时,都会出现偏差。是的,我们采用了分而治之的方式,对功能进行分解,从最小单元来评估工作量。但我们无法估算各个功能单元之间存在的各种显式和隐式关系,以及各种非功能性需求带给项目的影响。其二,我们无法事先完全预知开发过程中的各种风险。我们得为这种风险买上一份保险,这样才不至于在风险真正产生时要我们自己来买单,或者追悔莫及。
关于技术风险,最佳方式莫过于事先进行技术预演。不要揣测,或者从理论上去推导。在这个过程中,我们可以应用经验,但最保险的方式还是对系统中的核心问题以及关键问题进行研究,创建技术原型。它才是规避技术风险的定心丸。
成员变动风险是最难以预知的,因为人是最难以通过数据分析得出正确结论的动物。人的心理太复杂了,因此在软件业中还专门诞生了“人件(Peopleware)”这门学问。在我们进行项目开发过程中,谁知道有多少人会因为各种各样的因素,而萌生去意呢?此外,正所谓“人有旦夕祸福”,我们总不能预测哪些成员会在开发过程中生病或者失恋吧?若要解决这个问题,一个办法是“结对编程”。虽然提出这一方法的目的并不是为了应对成员变动的风险,但事实上这种互相协作的方式确实能够将成员离开所造成的损失降到最低。以我的经验,要发生那种编程开发的一对都离开项目的情形,实在是少之又少。还有一种办法则是Constantine提出的“交叉培训”。在其《人件集》的《稳步提升的质量》一篇中,他提出“将交叉培训纳入项目的组织形式中,……是最有效、最有影响的办法之一。这种方法同时也增加了工作透明度。通过增加团队中面对面工作的机会,团队成员间自然也就增加了相互学习的机会”。此外,他还提出 “在团队中进行软件开发角色轮循,也为成员增加了实践的机会,可以帮助大家掌握更多的技巧和知识。”这里固然在说培训,但它带来的结果是让团队中各个成员都能够了解彼此的工作,这就能够弥补因为某些成员离开项目带来的空白。
这里同样牵扯出一个话题,就是关于团队的培训。我的理解是,即使最后期限泰山压顶,也千万不要节省团队培训的时间,除非你的团队已经熟悉了项目开发的所有领域知识,以及解决领域问题的所有技术知识,同时,这个团队已经固定不变的合作过三个项目以上,因而团队成员已经达到了一个微小动作就能够心领神会的境界。有这样的团队么?或许有,不过我还没有看见。