兵贵在精而不在于多。关键在于知人善用,以及合理调度。一个项目经理在组建自己的团队时,必须要了解自己成员的人格特点与技术特点。在理想状态下,如果项目经理具有挑选成员的权利,会具有更大的成功率。如果项目过大,那么必须建立层级式的组织架构,而在划分出的各个小组中,却应该以扁平的平等架构为佳。这样能够自由而不失于集中,平等而又不至于缺乏效力。当然,具体的组织架构应依据企业文化、产品性质、开发规模、团队成员特点等各个因素综合考虑,不能死搬硬套。在安排人手时,要注意对技能型人才和管理型人才的使用,注意对领域专家和系统架构师的使用,注意对开发人员和测试人员的使用,注意对编档人员、QA、配置管理员的使用。此外,还需要养成从容不迫的心理,即使终期限火烧眉毛,迫在眉睫,仍然要保证对架构的设计、对编码的测试以及合理考虑产品性能、可用性和产品质量。
5、开发环境的保护与基础设施的维护。兵家云:天时、地利、人和。没有一个好的开发环境,很难想象开发人员能够高效率的工作。开发环境必须是相对独立,又利于交流与沟通的工作室。具体的说,项目组的工作环境必须拒绝项目无关人员的干扰与破坏,但却无阻于项目成员,特别是同一小组成员的交流。此外,会议室的数量非常重要。我在管理一个项目时,竟然常常为寻找会议室而东奔西走,将大量的时间浪费在会议准备上。此外,服务器、客户机、网络、打印机、白板、卡片,以及开发工具和软件,例如IDE开发环境、版本控制工具、Bug管理工具等,都需要在团队建立之初要准备好。对于计算机、网络和相关工具,则必须保证在项目开发期间的稳定性、畅通性。我曾经在项目开发中,因为网络中断、病毒侵袭以及服务器坏掉从而破坏了SVN的版本管理等诸多突发事件,让我在本来紧张的开发时间里,牺牲了不低于三天的时间,真是让我抓狂不已!所以说,一个好的网络管理中心、一个好的配置管理员,在关键时刻,可以抵得上半打高效的开发人员呢。如果你在项目开发过程中,频繁遭遇这样的问题,我的忠告是,赶紧准备换一家公司吧。
6、合理控制需求变更。需求变更是软件开发必然遭遇的暴风雪,也是导致“没有银弹”的渊薮。传统的瀑布开发模型在项目后期遭遇需求变更时,只能束手无策,但RUP与敏捷方法却能够坦然面对需求的变更,Kent Beck甚至在敏捷开发中提出了拥抱变化,真是足够勇敢与足够信心的宣言啊!在软件开发中,若要应对软件开发,一般的做法是合理设计,以求系统与架构具有足够的可扩展性;其次则是采用迭代的开发方式,通过定期甚至是短周期地交付可工作的产品,以印证需求与实现是否一致。同时,在项目中通过引入客户的积极参与,使得项目组与客户的交流能够畅通无阻,从而避免因为隔阂而导致需求分析产生的误差,以及需求变更无法及时提出。此外,利用原型快速开发方式,可以尽快地交付一个无具体实现的产品框架或原型,以验证业务规则、业务流程以及客户对GUI的要求。然而,需求变更不能无休止地进行,这会导致迭代的永无眠日。即使是敏捷开发,我们仍然要设定客户委托事项的基本线,一旦超出这一基本线,变更委员会(CCB)或其他担负这一职责的角色必须提出异议,与客户协商或探讨这种变更是否是必须的。控制需求变更的一个实践是,获得客户对分析出来的功能点的书面确认。虽然在发生变更时,客户的意见甚至可以无视这种书面文章,但至少可以在与客户的谈判中抢得先机。根据Mark Lines所说,通过变更控制的增强还可以降低项目风险。确实如此,在与客户谈判中,我们要学会说出“拒绝”两个字。当然,在对需求变更做出决定性意见之前,必须分析判断这样的变更是否合理,是否必要,或者优先级高。一种折中的办法则是,欣然承诺此次变更,但需要延迟后期限,或者放在下一次版本迭代之后。
7、预先评估风险。风险无处不在。Cockburn将软件开发形容为攀岩或者穿越沼泽,已经充分说明了软件开发过程中的风险。孙子兵法云:夫未战而庙算胜者,得算多也;未战而庙算不胜者,得算少也。先预先着失败的可能,方能够谨慎地做好各种准备,考虑各种风险以及驱避措施,方能够大可能地取得胜利。软件开发的风险有很多,其中至关重要的是进度风险、技术风险、需求变更风险、成员变动风险。
软件是可以度量的吗?看起来是,因为已经有了很多方法来完成软件的度量。从控制学的理论来看,你无法控制那些你无法度量的。因而软件度量对于控制软件开发而言,成为了关键。软件度量甚至因此成为了一门学问。然而,我可以肯定地说,软件的度量不可能准确,尤其是对进度的把握而言。即使一个项目的开发周期看起来是如此的充裕,以至于感受不到后期限的压力,我们仍然要对软件进度的控制采取如坐针毡的谨慎态度,即使这样在某些人的眼中,我成为了持怀疑论者,或者悲观主义者,我仍然愿意背着这样的名身恶意地怀疑项目时间不够。原因有二。其一是我们的工作量估算无法做到精确,即使是经验丰富的天才程序员,在估算项目的整体工作量时,都会出现偏差。是的,我们采用了分而治之的方式,对功能进行分解,从小单元来评估工作量。但我们无法估算各个功能单元之间存在的各种显式和隐式关系,以及各种非功能性需求带给项目的影响。其二,我们无法事先完全预知开发过程中的各种风险。我们得为这种风险买上一份保险,这样才不至于在风险真正产生时要我们自己来买单,或者追悔莫及。
关于技术风险,佳方式莫过于事先进行技术预演。不要揣测,或者从理论上去推导。在这个过程中,我们可以应用经验,但保险的方式还是对系统中的核心问题以及关键问题进行研究,创建技术原型。它才是规避技术风险的定心丸。
成员变动风险是难以预知的,因为人是难以通过数据分析得出正确结论的动物。人的心理太复杂了,因此在软件业中还专门诞生了“人件(Peopleware)”这门学问。在我们进行项目开发过程中,谁知道有多少人会因为各种各样的因素,而萌生去意呢?此外,正所谓“人有旦夕祸福”,我们总不能预测哪些成员会在开发过程中生病或者失恋吧?若要解决这个问题,一个办法是“结对编程”。虽然提出这一方法的目的并不是为了应对成员变动的风险,但事实上这种互相协作的方式确实能够将成员离开所造成的损失降到低。以我的经验,要发生那种编程开发的一对都离开项目的情形,实在是少之又少。还有一种办法则是Constantine提出的“交叉培训”。在其《人件集》的《稳步提升的质量》一篇中,他提出“将交叉培训纳入项目的组织形式中,……是有效、有影响的办法之一。这种方法同时也增加了工作透明度。通过增加团队中面对面工作的机会,团队成员间自然也增加了相互学习的机会”。此外,他还提出 “在团队中进行软件开发角色轮循,也为成员增加了实践的机会,可以帮助大家掌握更多的技巧和知识。”这里固然在说培训,但它带来的结果是让团队中各个成员都能够了解彼此的工作,这能够弥补因为某些成员离开项目带来的空白。
这里同样牵扯出一个话题,是关于团队的培训。我的理解是,即使后期限泰山压顶,也千万不要节省团队培训的时间,除非你的团队已经熟悉了项目开发的所有领域知识,以及解决领域问题的所有技术知识,同时,这个团队已经固定不变的合作过三个项目以上,因而团队成员已经达到了一个微小动作能够心领神会的境界。有这样的团队么?或许有,不过我还没有看见。