构建之法-现代软件工程笔记

P={做事的,不做事的,不让别人做事的,P4=做假的事的,P5=假装做事的}
在这里插入图片描述
和人类制造出来的其他产品相比,有许多共性,也有一些特殊性。随着人类社会的发展,技术的进步,一些事情总是变得越来越容易,例如旅行,现在人们旅行的方便程度和速度是几百年前所不可想象的。另一些事情,像怀孕生小孩,几千年来的确变得比较容易了,但还是需要大约九个月的时间。我们知道许多计算机硬件的能力大致以每两年提高一倍的速度发展[注释7],而软件开发的流程却没有这样的提速过程,为什么?软件开发过程有什么特别的难题?学者们总结了下面五点:

  1. 复杂性(Complexity)

软件可以说是人类创造的最复杂的系统类型。大型软件(操作系统、办公软件、搜索引擎)有超过百万行的源代码,上万个不同的文件。而软件工程师通常一次只能看到30—80行源代码(相当于显示器的一屏),他们的智力、记忆力和常人差不多。软件的各个模块之间有各种显性或隐性的依赖关系,随着系统的成长和模块的增多,这些关系的数量往往以几何级数的速度增长。

  1. 不可见性(Invisibility)

软件工程师能直接看见源代码,但是源代码不是软件本身。软件以机器码的形式高速运行,还可能在几个CPU核上同时运行,工程师是“看”不到自己的源代码如何具体地在用户的机器上被执行的。商用软件出现了错误,工程师可以看到程序在出错的一瞬间留下的一些痕迹(错误代号、大致的目标代码位置、错误信息),但是几乎无法完整重现到底程序出现了什么问题。

  1. 易变性(Changeability)

软件看上去很容易修改,修改软件比修改硬件容易多了。人们自然地期待软件能在下面两种情况下“改变”: a) 让软件做新的事情;b) 让软件适应新的硬件。但是与此同时,正确地修改软件是一件很困难的事情。

  1. 服从性(Conformity)

软件不能独立存在,它总是要运行在硬件上面,它要服从系统中其他组成部分的要求,它还要服从用户的要求、行业系统的要求(例如银行利率的变化)。

  1. 非连续性(Discontinuity)

人们比较容易理解连续的系统:增加输入,就能看到相应输出的增加。但是许多软件系统却没有这样的特性,有时输入上很小的变化,会引起输出上极大的变化。

这些特性的前四个是佛瑞德·布鲁克斯(FredBrooks Jr.)在No Silver Bullet一文中提到的,第五个特性是瓦茨拉夫·拉里奇(Vaclav Rajlich)提到的。

这些特性是由软件的本质所决定的,软件还有其他特性:

有许多不同的程序设计语言、软件工具和软件开发平台
存在许多不同的软件开发流程
软件团队中存在许多不同的角色
软件通常既可以存储在磁带上,也可以存储在
CD/DVD上但是这些非本质、临时的特性并不能决定软件工程的本质问题。例如,有人发明了一种新的程序设计语言,或者又出现了一个新的软件开发流程,或者网上出现了又一个程序员技术社区……这些事并不能改变软件工程的根本难度,这也是著名的“没有银弹(No Silver Bullet)”论断所阐述的道理。软件的这些本质特性让“做一个好软件”变得很难,同时也让软件工程有它独特的挑战和魅力。

1.2.2 软件工程与计算机科学的关系
软件工程中的“工程”二字也大有来历,人们把下面的活动称之为工程:

创造性地运用科学原理,设计和实现建筑、机器、装置或生产过程;或者是在实践中使用一个或多个上述实体;或者是实现这些实体的过程[注释8]。远古时期,人们互相协作建成了不少工程奇迹,其中有些现在还能看到(例如希腊雅典的帕特农神庙、古罗马帝国的罗马水道、中国的长城等),我们想象这些工程在设计和建造的过程中一定牵涉到了大量的计算、计划、各类角色的协作,以及成百上千的人、动物、机械的劳作。这些因素在后来出现的各种“工程”(如化学工程、土木工程)中依然存在。中国大陆的高校中大致有下面三种讲计算机软件的机构:

计算机科学与技术系或学院
软件学院
软件工程系、软件工程学院
很多同学在报名时不知道它们的区别,进去之后发现除了收费高低不同,学的科目差不多,毕业后大部分同学都是写程序,似乎差别不大13?其实,它们的区别还是挺大的。和数理化相比,计算机科学是一门相当年轻的学科,虽然我们可以追溯到巴贝奇(Charles Babbage,1791—1871)、埃达(AdaLovelace,1815—1852)、图灵(Alan Turing,1912—1954)等计算机科学的先驱,但是“ComputerScience”这个学科的名字是1959年才正式提出,综合维基百科中“计算机科学”的词条和微软学术搜索(Microsoft Academic Search)[注释9]对于计算机科学子领域的划分,计算机科学(Computer Sci-ence)这一学术领域可以分为下面这些领域:

计算理论(Theoretical Computing)
信息和编码理论(Information and Coding The-ory)
算法和数据结构(Algorithm and Data Struc-ture)
形式化方法(Formal Methods)
程序设计语言(Programming Language)偏实践的领域:
计算机体系结构(Computer Architecture)
并行计算和分布式系统(Concurrent, Parallel and Distributed System)
实时系统和嵌入式系统(Real Time and Embed-ded System)
操作系统(Operating System)
计算机网络(Networking)
科学计算(Scientific Computing)
安全和密码学(Security and Cryptography)
人工智能(Artificial Intelligence)
这个领域涵盖了许多相关的领域,如模式识别(Pattern Recognition)、机器学习(MachineLearning)、数据挖掘(Data Mining)、信息提取(Information Retrieval)等。
计算机图形学(Computer Graphics)、计算机视觉(Computer Vision)、
多媒体(Multimedia)
数据库和大规模数据处理(Database and Large Scale Data Processing)
万维网(World Wide Web)
自然语言处理和语音(Natural Language Pro-cessing and Speech)
人机交互(Human Computer Interaction)
软件工程(Software ngineering)
1.2.4 软件工程的知识领域
软件工程这个学科到底包含了什么样的知识,这些知识又是在什么基础上建立的呢?2014年,IEEE发布了SWEBOK V3.0(Software Engineering Bodyof Knowledge),完整地回答了这一问题,下面是其中提到的15个知识领域(Knowledge Area,KA)[注释11]:

  1. Software Requirements
  2. Software Design
  3. Software Construction
  4. Software Testing
  5. Software Maintenance
  6. Software Configuration Management
  7. Software Engineering Management
  8. Software Engineering Process
  9. Software Engineering Models and Methods
  10. Software Quality
  11. Software Engineering Professional Practice
  12. Software Engineering Economics
  13. Computing Foundations
  14. Mathematical Foundations
  15. Engineering Foundations

需要指出的是,在上面的15个KA中,KA1—12描述了软件工程学科本身的知识领域;KA13—15描述了软件工程的三大类基础知识领域:计算基础、数学基础和工程基础。在本书后面的章节中,我们会列出每个章节具体涉及的知识领域和知识点。
2.3 个人开发流程
卡内基梅隆大学(CMU)的能力成熟度模型(CMM和CMMI),是用来衡量一个团队能力的一套模型。CMU的专家们针对软件工程师也有一套模型,叫Personal Software Process(PSP),PSP和任何其他方法论一样,也不是一蹴而就的。表2-2显示了CMU PSP各个版本的内容[注释2]。黑体字标出了每个版本新增的内容。

在这里插入图片描述

表2-2 CMU PSP各个版本的内容

我们根据最新的版本(PSP2.1)来看看一个软件工程师在接到一个任务之后应该怎么做,如表2-3所示。

在这里插入图片描述

表2-3 软件工程师的任务清单(中英对照)

下面的表2-4对比显示了笔者2011年收集的两组统计数据。

大学四年级学生(Senior Student):在中国科技大学“现代软件工程”课程中,每个学生记录了自己在完成个人项目时所花费的时间(学生情况:大学四年级上学期,专业:计算机/电子/数学)
工作三年的软件工程师(SDE):一群平均工作时间在3年左右,平均毕业学位为硕士的职业软件工程师的匿名调查

在这里插入图片描述
表2-4 个人项目耗时对比记录表

软件工程师比大四学生多读了3年书,多工作了3年,两类人任务的质量要求也不一样。我们可以看到,工程师在“需求分析”和“测试”这两方面明显地要花更多的时间(多60%以上);但是在具体编码上,工程师比学生要少花1/3强的时间。显然,从学生到职业程序员,并不是更加没完没了地写程序—花在写代码上的时间反而少了许多。PSP有如下的特点。

不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这样,开发不同应用的软件工程师可以互相比较。
不依赖于考试,而主要靠工程师自己收集数据,然后分析,提高。
在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输入质量不高。在这种情况下,程序员的输出(程序/软件)往往质量也不高,然而这并不能全部由程序员负责。
PSP依赖于数据。
需要工程师输入数据,记录工程师的各项活动,这本身就需要不小的时间代价。
如果数据不准确或有遗失,怎么办?让工程师编造一些?
如果一些数据不利于工程师本人(例如:花很多时间修改缺陷),我们怎么能保证工程师愿意如实地记录这些数据呢?
PSP的目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度。
工程师有可能很高效地开发出一个顾客不喜欢的软件(例如用户界面很差,功能未能解决用户实际问题,等等),那么这位工程师还是一个优秀的工程师么?
3.1 个人能力的衡量与发展
软件工程包括了什么呢?第1章提到:软件工程包括了开发、运营、维护软件的过程中的很多技术、做法、习惯和思想。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”,软件开发流程的目的是为了提高软件开发、运营、维护的效率,以及提升用户满意度、软件的可靠性和可维护性。软件开发流程不光指团队的流程,还包括个人开发流程,因为软件团队是由个人组成的。在团队的大流程中,是每一个具体的个人在做开发、测试、用户界面设计、管理、交流等工作。因此,个人在团队中也有独立的流程。把每个人的工作有序地组织起来,就是团队的流程。这里说的“有序”,并不是“无争论”。在大部分成功的软件团队模型中,各个角色(开发、测试、项目管理等)考虑问题的出发点是有区别的,不同意见的冲突在所难免,一个好的团队流程能把冲突的积极方面(各自尽力把自己的工作做好,说服别人)释放出来,而避免消极方面(因为冲突而产生的消极、抵触情绪等)。我们可以用足球来作一个比喻,足球队中有没有个人流程?当然有,职业足球队对于球员有很严格的要求,例如:体能、技术、意识、斗志具体技术有传接、盘带、射门、定位球、跑位,等等。对一些特定的角色(如守门员),还有独特的技术要求。足球队有没有流程?当然有:阵型、配合、临场应变足球队有不少“阵型”:442、433、451以及它们的各种变体。还有不少风格:南美、欧洲;技术、力量;小快灵、抢逼围、两翼齐飞、全攻全守,等等。然而,尽管有这么多理论,足球的每一次盘带、传球、跑动、射门、扑救,依然都是单个球员完成的。如果单个运动员的技术、体能不行 ,无论是什么阵型用处都不大,有些阵型还会起反作用,例如,让体力弱的球队去打全攻全守。足球队有没有交流?当然有,教练和球员之间、球员之间都有很频繁的交流,有战前的计划和训练,有事后的总结和分析,当然还有争论。软件团队和团队中的工程师也是这样。软件系统的绝大部分模块都是由个人开发或维护的。在软件工程的术语中,我们把这些单个的成员叫做Individ-ual Contributor(IC)。IC在团队中的流程是怎么样的呢?以开发人员为例,流程如下。

通过交流、实验、快速原型等方法,理解问题、需求或任务
提出多种解决办法并估计工作量
其中包括寻找以前的解决方案,因为很多工作是重复性的
与相关角色交流解决问题的提案,决定一个可行的方案
执行,把想法变成实际中能工作的代码,同时验证方案的可行性和其他特性(例如程序的效能等)
和团队的其他角色合作,在测试环境中测试实现方案,修复缺陷(Bug)。如果此方案有严重的问题,那么就考虑其他方案
在解决方案发布出去之后,对结果负责每个人的工作质量直接影响最终软件的质量。
在这里插入图片描述
5.2 软件团队的模式
软件团队有各种形式,适用于不同的人员和需求。基于直觉形成的团队模式未必是最合适的。例如小朋友们刚开始踢足球的时候,大家都一窝蜂地去抢球,球在哪里,一堆人就跟到哪里,这样的模式可以叫一窝蜂模式(Chaos Team)。不能否认,这样的团队也有,只不过他们在这样的模式下存活的时间一般都不长,没有机会让别人很好地观察。一窝蜂模式可能是一个欢乐而随意的模式,但这是一个好的团队形式么?当然不是。要把一群小朋友培养成一个团队(如下),需要时间:

图5-3 分工明确的(足球)团队

体育团队从一窝蜂抢球演变到有明确的分工、阵型、战术的团队,需要时间。类似地,软件团队的模式,最初是混沌的一窝蜂形式:一群人开始写代码,希望能写出好软件。随着团队的成熟和环境的变化,团队模式会演变成下面几种模式之一。

5.2.1 主治医师模式(Chief Programmer Team,Surgical Team)
就像在手术台上那样,有一个主刀医师,其他人(麻醉,护士,器械)各司其职,为主刀医师服务。这样的软件团队中,有首席程序员(Chief Pro-grammer),他/她负责处理主要模块的设计和编码,其他成员从各种角度支持他/她的工作(后备程序员、系统管理员、工具开发、编程语言专家、业务专家)。佛瑞德·布鲁克斯(Frederic BrooksJr.)在主管IBM System360项目时就采用了这种模式。在一些学校里,软件工程的团队模式往往从这一模式退化为“一个学生干活,其余学生跟着打酱油”。

5.2.2 明星模式(Super-star Model)
主治医师模式运用到极点,可以蜕化为明星模式,在这里,明星的光芒盖过了团队其他人的总和,2004年到2012年的“翔之队”就是一个例子。明星也是人,也会受伤,犯错误,如何让团队的利益最大化,而不是明星的利益最大化?如何让团队的价值在明星陨落之后仍然能够保持?是这个模式要解决的问题。真正有巨大成就的明星都能意识到团队的作用,迈克尔·乔丹说过,“Talent winsgames, team work wins championship.”

5.2.3 社区模式(Community Model)
社区由很多志愿者参与,每个人参与自己感兴趣的项目,贡献力量,大部分人不拿报酬。这种模式的好处是“众人拾柴火焰高”,但是如果大家都只来烤火,不去拾柴;或者捡到的柴火质量太差,最后火也就熄灭了。“社区”并不意味着“随意”,一些成功的社区项目(例如开发和维护Linux操作系统的社区),都有很严格的代码复审和签入的质量控制。

5.2.4 业余剧团模式(Amateur Theater Team)
这样的团队在每一个项目(剧目)中,不同的人会挑选不同的角色。在下一个剧目中,这些人也许会换一个完全不同的角色类型。各人在团队中听从一个中央指挥(导演)的指导和安排。在学生实践项目或培训项目中,这样的事情经常发生。

5.2.5 秘密团队(Skunk Work Team)
一些软件项目在秘密状态下进行,别人不知道他们具体在做什么。苹果公司1980年代在研发Macin-tosh之后的系统时,就有两三个团队在不同时期进入秘密状态开发。21世纪的一些创业团队也是处于类似状态。这种模式的好处是:团队内部有极大的自由,没有外界的干扰(不用每周给别人介绍项目进展,听领导的最新指示,等等),团队成员有极大的投入。

5.2.6 特工团队(SWAT)
就像电影电视中的特工组《加里森敢死队》等一样,软件行业的一些团队由一些有特殊技能的专业人士组成,负责解决一些棘手而有紧迫性的问题。例如2000年之前,很多公司都需要专业人士去解决Y2K问题。这些团队成员必须了解传统语言和老式系统,才能胜任这样的任务。现在还有一些专门做网站安全性服务的团队,也属于这一类型。

5.2.7 交响乐团模式(Orchestra)
想象一下交响乐团的演奏,有下面的特点。

家伙多,门类齐全。
各司其职,各自有专门场地,演奏期间没有聊天、走动等现象。
演奏都靠谱,同时看指挥的。
演奏的都是练习过多次的曲目,重在执行。

图5-4 交响乐团乐器多
在这里插入图片描述

当某个软件领域处于稳定成长阶段的时候,众多大型软件公司的开发团队就会采取这种模式,例如微软公司的Office软件,从Office97、Office XP、Office2003、Office2007到Office2011、Office2013……

5.2.8 爵士乐模式(Jazz Band)
爵士乐是另外一种演奏模式,我们观察这个视频(So What)[注释2]来体会一下爵士乐的代表人物迈尔斯·戴维斯(Miles Davis)[注释3]领导的乐队的演奏方式。

图5-5 迈尔斯·戴维斯领导的爵士乐队

从外行看热闹的角度看,和交响乐团相比,这种模式有以下特点。

不靠谱。他们演奏时都没有谱子。
没有现场指挥,平时有编曲起到协调和指导作用(和迈尔斯合作的编曲吉尔·伊文斯(GilEvans)也是很有造诣的音乐家)。
也有模式,迈尔斯(姑且称之为架构师)先吹出主题,然后他走到一旁抽烟去了,其余人员根据这个主题各自即兴发挥;最后迈尔斯加入,回应主题,像是对曲子的总结。
人数较少。评论家归纳迈尔斯·戴维斯的特点是:
individual expression, emphatic interac-tion, and creative response to shifting con-tents.

强调个性化的表达,强有力的互动,对变化的内容有创意的回应。这看上去跟“敏捷的开发模式”有点类似。这样的团队模式和上面的“交响乐团模式”在很多方面都对立,但是两种模式都产生了很受欢迎的音乐作品,因此不能简单地说孰优孰劣。

5.2.9 功能团队模式(Feature Team)
很多软件公司的团队最后都演变成功能团队,简而言之,就是具备不同能力的同事们平等协作,共同完成一个功能。

图5-6 功能团队

在这个功能完成之后,这些人又重新组织,和别的角色一起去完成下一个功能。他们之间没有管理和被管理的关系。大型软件公司里的不少团队都是采用这种模式。这些功能小组也称为Feature Crew,小组内的交流比较频繁。约翰·巴克斯在1955年管理FORTRAN语言项目时,就用了类似的团队架构。巴克斯以蜂窝状的架构来组织工作。每个小组都由一到三个人组成,每个小组都是一个有自主权的单元,可以自由选用最有利于他们完成工作的任何技术。但是,每个小组必须与其他小组就编程规范达成一致……

5.2.10 官僚模式(Bureaucratic Model)
还有一个团队模式可以叫官僚模式。

图5-7 层层领导的官僚模式

这种模式脱胎于大机构的组织架构,几个人报告给一个小头目,几个小头目报告给中头目,依次而上。这种模式在软件开发中会出问题。因为成员之间不光有技术方面的合作和领导,同时还混进了组织上的领导和被领导关系。跨组织的合作变得比较困难,因为各自头顶上都有不同的老板。这种模式如果应用不好,最后会变成“老板驱动”的开发流程,见后面的介绍。
在这里插入图片描述
在这里插入图片描述
在这种瀑布群下,要把各个子系统统一到最后做系统测试(System Testing)的阶段,难度不是一般的大啊!另外,在这样的开发流程中,用户只有到了最后才能看到结果,用户真是等不起。

5.3.4 Rational Unified Process
统一流程(RUP)从瀑布模型开始的各种模型都有一个共同点:重计划,重事先设计,重文档表达。这一类的方法中集大成者要算Rational统一流程(Rational UnifiedProcess,RUP)[注释5]。RUP把软件开发的各个阶段整合在一个统一的框架里。要完成一个复杂的软件项目,团队的各种成员要在不同阶段做不同的事情,这些不同类型的工作在RUP中叫做规程(Discipline)或者工作流(Workflow)。简介如下。

业务建模

为用户提供软件,就要理解目前用户的业务流程,但是精通计算机语言细节的工程师并不能马上理解对用户活动和期望值的各种自然语言描述。为了解决这个问题,业务建模(Business Modeling)工作流用精确的语言(通常是UML)把用户的活动描述出来。这个词有时也翻译为“商业建模”,但并不是只有存在金钱交易的商业活动才能符合建模的要求,任何和客户的正常工作相关的业务活动(例如政府为居民提供网上服务,学生到图书馆借书)都是建模的对象。这个工作流的结果通常是用例(Use Case),后面章节对用例有专门介绍。

需求

有了用例之后,开发人员和用户(或者用户代表)要分析并确认软件系统得提供什么样的功能来满足用户的需求,功能有什么约束条件,如何验证功能满足了用户需求。这就是需求(Requirement)工作流的作用。

分析和设计

分析和设计(Analysis & Design)工作流将需求转化成系统的设计。这一步结束之后,团队成员就能知道系统有哪些子系统、模块,它们之间的关系是怎样的。

实现

在实现(Implementation)工作流中,工程师按照计划实现上一步产出的设计,将开发出的组件(Module),连同验证模块(例如:单元测试)提交到系统中。同时,工程师们集成由单个开发者(或小组)所产生的结果,通过手工或自动化的手段,把可执行的系统搭建出来。

测试

测试(Test)工作流要验证现阶段交付的所有组件的正确性、组件之间交互的正确性,以及检验所有的需求已被正确地实现。在这个过程中,发现、报告、会诊、修复各种缺陷,在软件部署之前保证质量达到预期要求。

部署

部署(Deployment)工作流的目的是生成最终版本并将软件分发给最终用户。具体过程可以参考本书“典型用户和场景”一章。

配置和变更管理

配置和变更管理工作流(Configuration andChange Management)负责管理RUP各个阶段产生的各种工作结果(例如源代码控制系统管理和备份各种源文件),要记录修改人员、修改原因、修改时间等属性,有些团队还可以考虑并行开发、分布式开发等。

项目管理

软件项目管理工作流(Project Management)平衡各种可能产生冲突的目标,管理风险,克服各种约束并成功地在各个阶段交付达到要求的产品。

环境

环境(Environment)工作流的目的是向软件开发组织提供软件开发环境,包括过程和工具。RUP把软件开发分成几个阶段,一个大阶段的结束称为一个里程碑(Milestone),每个阶段内可以有几个迭代,以比较灵活的形式实现本阶段的任务。从这一点来说,RUP在大尺度上像瀑布模型,在每个阶段内像迭代模型。下面是RUP四个阶段的介绍:

初始阶段——此阶段的目标是分析软件系统大概的构成,系统与外部系统的边界在哪里(我们的系统究竟和什么别的外部实体打交道),大致的成本和预算是多少,系统的风险主要来自哪里。成功度过初始阶段的项目会达到生命周期目标(LifecycleObjective)里程碑。

细化阶段——它的目标是分析问题领域,建立健全的体系结构基础,编制项目计划,按优先级处理项目中的风险。团队要确定项目的具体范围、主要功能、性能、安全性、可扩展性等非功能需求。同时为项目建立支持环境,包括创建开发案例、创建模板并准备工具。细化阶段结束时,项目到达了第二个重要的里程碑:生命周期结构(Lifecycle Archi-tecture)里程碑。

构造阶段——在这一阶段,团队开发出所有的功能集,并有秩序地把功能集成为经过各种测试验证过的产品。构造阶段结束时是第三个重要的里程碑:初始功能(Initial Operational)里程碑。此时的产品版本也常被称为“beta”版。

交付阶段——这时候,团队工作的重点是确保软件能满足最终用户的实际需求。交付阶段可以有迭代(beta1,beta2等),基于用户的反馈,团队利用这些迭代对系统进行修改、调整。除了对功能的调整,团队还要注意处理用户设置、安装和可用性等问题。在交付阶段的终点是第四个里程碑:产品发布(Product Release)里程碑。
在这里插入图片描述
6.1 敏捷的流程
在软件工程的语境里,“敏捷流程”是一系列价值观和方法论的集合。从2001年开始,一些软件界的专家开始倡导“敏捷”的价值观和流程,他们肯定了流行做法的价值(见表6-1左列),但是强调敏捷的做法(见表6-1右列)更能带来价值。

表6-1 现有的做法vs.敏捷的做法

现有的做法 敏捷的做法
流程和工具 个人和交流
完备的文档 可用的软件
为合同谈判 与客户合作
执行原定计划 响应变化
6.1.1 敏捷开发原则[注释1]

  1. 尽早并持续地交付有价值的软件以满足顾客需求

  2. 敏捷流程欢迎需求的变化,并利用这种变化来提高用户的竞争优势

  3. 经常发布可用的软件,发布间隔可以从几周到几个月,能短则短

  4. 业务人员和开发人员在项目开发过程中应该每天共同工作

  5. 以有进取心的人为项目核心,充分支持信任他们

  6. 无论团队内外,面对面的交流始终是最有效的沟通方式

  7. 可用的软件是衡量项目进展的主要指标

  8. 敏捷流程应能保持可持续的发展。领导、团队和用户应该能按照目前的步调持续合作下去

  9. 只有不断关注技术和设计,才能越来越敏捷

  10. 保持简明—尽可能简化工作量的技艺—极为重要

  11. 只有能自我管理的团队才能创造优秀的架构、需求和设计

  12. 时时总结如何提高团队效率,并付诸行动

6.1.2 敏捷流程概述
在“敏捷”的大旗下面,我们可以看到好几种软件开发的方法论。我们在这里剖析Scrum 这个方法论。从理论上看,这个方法论真是美妙无比:

图6-1 敏捷流程图[注释2]

微软MSDN也有类似的流程介绍[注释3],看起来也是高屋建瓴,很流畅:

图6-2 MSDN上的敏捷流程图

根据上面的两幅图,我们不难看出敏捷的步骤。

第一步:找出完成产品需要做的事情—Product Back-log。Backlog翻译成“积压的工作”、“待解决的问题”、“产品订单”,都可以。产品负责人主导大家对于这个Backlog进行增/删/改的工作。每一项工作的时间估计单位为“天”。

第二步:决定当前的冲刺(Sprint)需要解决的事情—Sprint Backlog。整个产品的实现被划分为几个互相联系的冲刺(Sprint)。产品订单上的任务被进一步细化了,被分解为以小时为单位。如果一个任务的估计时间太长(如超过16个小时),那么它就应该被进一步分解。订单上的任务是团队成员根据自己的情况来认领。团队成员能主导任务的估计和分配,他们的能动性得到较大的发挥。

第三步:冲刺(Sprint)。在冲刺阶段,外部人士不能直接打扰团队成员。一切交流只能通过Scrum大师(Scrum Master)来完成。这一措施较好地平衡了“交流”和“集中注意力”的矛盾。有任何需求的改变都留待冲刺结束后再讨论。

冲刺期间,每天要开一个每日例会(Scrum Meet-ing),团队成员大多站着开会,所以又称每日立会。大家依次报告:

我昨天做了啥
我今天要做啥

我碰到了哪些问题每日立会强迫每个人向同伴报告进度,迫使大家把问题摆在明面上。同时启动每日构建,让大家每天都能看到一个逐渐完善的版本。用简明的图表展现整个项目的进度,这个图最好放在大家工作的环境中,或者每天传达给各个成员:图表可以是燃尽图(Burn Down Chart,想象我们把一堆Backlog的木头给烧光)。

图6-3 燃尽图

也可以是简单的看板图(Kanban):把一堆任务从最初的“待定”推动到“工作中”等各个状态,直至“完成”。

图6-4 看板图

冲刺阶段是时间驱动的(Time-boxed),时间一到就结束。这个特点看似不起眼,但其实它有效地断了各种延期想法的后路,很高明[注释4]。

第四步:得到软件的一个增量版本,发布给用户。然后在此基础上又进一步计划增量的新功能和改进。
6.2 敏捷流程的问题和解法
美妙的理论在实践中都会碰到这样那样的问题,下面是一些例子。

第一步:各个需求和任务之间是有种种复杂的依赖关系的,除了优先级之外,我们还要考虑相互的依赖关系。怎样在计划(Backlog)中体现依赖关系呢?

第二步:把一个任务从产品层级的描述逐步细化到技术实现层面,是很需要技术能力和交流能力的。例如,产品订单上写着:希望这个英语单词学习软件能在各个移动平台上实现用户学习进度的同步。那么,在把这个任务分解到一个可以执行的冲刺任务时,我们要考虑这些因素:

什么是用户学习进度?用户如何衡量这个功能的优劣?

PC平台和各个移动平台分别用什么来表示“学习进度”?

同步是通过什么样的技术手段实现?

如何解决可能的同步冲突问题?

……这些问题未必能在短时间内完成,然而时间不等人,那么程序员会冒着风险先尝试着在某些平台上实现—也许以后要返工。如果团队成员都对某个任务不感兴趣,都不认领这个任务,怎么办?团队成员小飞想认领某个任务A,但是A的实现要依赖于任务B,但是B没人认领,小飞也不具备足够的知识去完成B,怎么办?有些成员认领的任务很多,有些成员认领的任务很少,忙闲不均,怎么办?

第三步:每日例会(Scrum Meeting)看起来很爽:

我昨天做了啥
我今天要做啥
我碰到了哪些问题

爽了之后,也许会流于形式。我们想象一帮狗熊开每日例会时,大家的发言是:

我昨天掰棒子
我今天继续掰棒子
我没碰到困难

这样的会议有用么?也许昨天掰的棒子没处理,今天就掰另一个棒子去了,明天又来一个新棒子……一群狗熊级的程序员会这么说:

我昨天写代码
我今天继续写
我没碰到困难

每天这样写代码,我们离冲刺的终点线到底是更近了,还是更远了?如果流于形式,无论多么敏捷的每日立会也会被忽悠[注释5]。一个改进是,定义好任务究竟是什么?任务的完成(Done)到底意味着什么?每个人的任务必须是明确定义的,狗熊们不能笼统地说“我在掰棒子”,而是要说明标号为123的棒子现在是什么状态,你做好之后交给谁了。另一个改进是,要在每一个任务中记载我们完成这个任务还需要多少时间。已经花了多少时间虽然重要,但那不是关键(那是沉没成本),关键是要看我们离最后目标有多远。就像某部门展览“反腐成果”给群众看—“已经抓出来N个腐败分子”固然解恨,但关键是“还剩多少在台上”,这个问题不说明,再抓多少个都不解决问题。冲刺到一半的时候,产品负责人突然发现要马上做重要的改动!或者某个大佬要看某个不在计划中的功能的演示,怎么办?这种情况非常考验ScrumMaster。如果一个运动员在跑一百米冲刺,但是跑到一半的时候,领导突然想看一百一十米栏的比赛,前面马上会摆起栏架,大家要准备8步上栏!怎么办?一个有正常头脑的运动员和教练员会说:去你的,要改主意,也要等到老子冲刺完了再说啊!关于每日立会—如果团队成员不在同一个地方,怎么开会呢?我听到一些敏捷的专家说,一个团队的成员必须面对面开会,才有效果。肯·施瓦伯(Ken Schwaber)说:

I also recom-mended eliminating all of the development arti-facts - like design documents… Scrum relies onhigh-bandwidth, face-to-face communication andteamwork; cubicles and unneeded artifacts pro-mote isolation and misunderstandings.

如果项目的所有人都坐在一起,连工位之间的矮墙都没有,那的确很爽,但是在很多公司中那是不可能的,有些团队成员甚至在不同的时区工作,怎么办?他们就不能敏捷了?这时候我们的确需要文档和其他辅助手段来沟通。再说说燃尽图。有些燃尽图只是列出了任务的数目,这种图无法展现项目的拖延情况,一个任务有大有小,它们在图表中都是一个点,一个16小时的任务需要3天完成,一个2小时的任务出于种种原因也花了3天时间,它们在图表中的表现是一样的。在实践中,我个人认为以时间为度量的燃尽图更有效果。下面是一个实际项目的燃尽图,有三个每天跟踪的时间值:

实际剩余时间(Remaining Hour):每个团队成员所有任务的剩余时间的总和。
预估剩余时间(Projected Remaining Hour):根据每个人每天的理论进度推算的剩余时间。
实际花费时间(Completed Hour):实际花费的时间。

图6-5 Sprint 进行中

图6-6 Sprint 最后结果

注解1:Sprint从8/22到9/28,中间9/15—9/18整个团队外出参加部门年会。

注解2:开始预计所有工作量为340小时,每个工作日能减少(Burn)17小时。

注解3:开发人员有5.5名,绝大多数第一次接触正式商业项目和Scrum的团队开发模式。最终完成的工作量为524小时,是预计的1.5倍。(这暴露了什么问题呢?)

注解4:有0.5名UX设计人员、0.5名PM和2名测试人员。

注解5:Sprint结束后,各个任务宣告完成,并且没有P1(最严重的)Bug,但是P2及以下的Bug有80多个,加上前一个版本遗留下来的70个Bug,总共还有150个Bug要解决,才能发布。

注解6:Sprint结束后,发现有两个原来的设计问题很大,团队决定在Sprint结束之后进行重新设计,或者叫Design Change Request(DCR)。

(敏捷流程中的)第三步半:做过项目的人都知道,当你说“任务都完成了”的时候,那只是说,开发人员认为该写的代码都写完了,但其实还有很多事情没做完。例如写一个Windows客户端的功能,显示一张新闻图片,加上与它相匹配的文字(假设这些图片/文字都可以从互联网上拿到),做完之后,还有下面的事情。

a. 验证这个功能在Windows XP、Windows Vista、Windows7、Windows Server2008 R2、Win-dows Server2012下都显示正确。(开发人员表示自己的机器是Windows Server2008,UI看起来不错,其他平台想必也不错!)

b. 验证这个功能的显示布局和字体在100%到150%的DPI上都显示正确,在各种色彩配置中都显示正确。

c. 验证文字无论是中文、英文、阿拉伯文都能正确显示。(联合国五种工作语言我们得支持吧?)

d. 验证程序效能上没有问题。

e. 验证程序长时间运行,没有内存和资源泄露。

f. 验证这个功能和其他功能有较好的集成。谁来做这第三步半呢?程序员写完功能的时候,我们感觉好像项目完成了80%,殊不知后面的20%往往要花费80%的时间,敏捷流程没有明确表明到底何人何时以何种优先级来完成这20%的任务。

长期任务:软件项目中常常有一些比较艰难和底层的任务,完成这些任务需要超过Sprint所计划的时间,这时候我们怎么安排呢?在作者的经验中,这些任务往往在短周期的迭代中得不到应有的重视,一直拖着,最后导致团队要花大量的时间来解决问题。软件团队中还有一个重要的角色—测试。测试人员在一个冲刺中怎么工作呢?有敏捷专家建议测试人员可以担负起产品负责人(Product Owner)的部分责任,同时掌握验收测试(Acceptance Test)流程,对产品的最终质量负责。但是测试人员的开发技术能力在团队中并不占优(在有些中国公司中甚至是最弱的一环),他们在大家都要“烧光”所有任务的压力下,能担当起产品负责人这一责任么?本书的“稳定和发布阶段”一章讲到了“第三步半要做什么事情”,它的流程图可以作为Scrum/Sprint的补充:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
问:敏捷的方法论有哪些?

答:比较有名的是:

爱抚弟弟(FDD – Feature Driven Design)
史克朗姆(SCRUM)
极限编程(XP)
问:那比较有名的最佳实践是什么?

答:这就太多了,你把任意三个字母组合一下,说不定就是一个最佳实践,例如TDD(踢弟弟,TestDriven Development)就是一个最佳实践。很多程序员老大哥都喜欢踢弟弟。

问:为什么人们以前没有总结出来敏捷,而是最近这几年才醒悟呢?

答:这个……原始人为什么不知道吃方便面?敏捷的原则并不是从石头缝里面蹦出来的,它和前人总结的软件工程原则有着千丝万缕的联系[注释10]。稍稍正经一点来说,有几个原因导致敏捷在互联网时代出现:

最初的软件(20世纪六七十年代)的顾客都是大型研究机构、军方、美国航空航天局、大型股票交易公司,他们需要通过软件系统来搞科学计算、军方项目、登月项目、股票交易系统等超级复杂的项目。这些项目对功能的要求非常严格,对计算的准确度要求相当高。
+20世纪八九十年代,软件进入桌面软件时代,开发周期明显缩短,各种新的方法开始进入实用阶段。但是软件发布的媒介还是软盘、CD、DVD,做好一个发布需要较大的经济投入,不能频繁更新版本。
互联网时代,大部分的服务是通过网络服务器端实现,在客户端有各种方便的推送(Push)渠道。一般消费者成为主要用户。网络的传播速度和广度,使得知识的获取变得更加容易,很多软件服务可以由一个小团队来实现。同时,技术更新的速度在加快,那种一个大型团队用一种成熟技术开发2——3年再发布软件的时代已经过去了。用户需求的变化也在加快,开发流程必须跟上这些快速变化的节奏。
于是敏捷就产生了。

问:什么样的牛人一夜之间想出了这么多敏捷的东东?

答:首先,很多方法已经在实践中运用了很多年,不是牛人们一夜之间想出来的;其次,很多方法论把原来单个的实践方法结合起来,运用到极致,吸引了不少眼球。不过,一些牛人的确在几个晚上搞出了一个“敏捷宣言”。2001年2月,17位软件绿林好汉聚集在美国犹他州的滑雪胜地雪鸟(Snowbird)雪场。白天除了滑雪,没啥鸟事;晚上除了喝酒侃大山,鸟没啥事……但是他们都感觉“世易时移,变法宜矣”。经过讨论,《敏捷宣言》应运而生,这一组宣言并没有带来新的程序开发语言,或者具体的开发方法,它只是说在当代做软件开发的时候更应该注意哪些方面。

问:为啥很多研究都证明敏捷很有效果?

答:大多数被测试、被研究的新东西都很有效果,这是Hawthorne效应[注释11]。例如你可以测试“给每一个程序员发毛绒玩具,然后测试劳动生产率”,你会发现毛绒玩具能提高劳动生产率!

问:敏捷是万能的么?我上学的时候,老师教我们“形式化的软件开发方法(Formal Method)”、“里程碑式的开发(Plan-driven development)”,它们都被淘汰了?

答:不是,和任何武功、战术一样,敏捷有它最适用的范围,我借着酒劲,画一个表。

7.1 MSF简史
前面的章节介绍了软件开发的各种方法论以及一些原则和宣言。宣言令人激动,但是宣言不能代替软件,用户不会看了宣言就掏钱买软件。那么世界上最大的软件公司——微软公司有没有什么软件开发的思想和宣言呢?它倒是有一个方法论——微软解决方案框架(Microsoft Solution Framework,MSF),也就是微软推荐的软件开发方法。大约在1993年,微软在总结了自己产品团队的开发经验和教训,以及微软咨询服务部门的业务经验后,推出了MSF。当时的MSF只是这些经验和教训的初步总结。在以后的几年中,MSF进一步吸收了微软各个部门和微软的合作伙伴在实际项目中的经验。2002年,随着Visual Studio .NET的发布,微软发布了一系列关于MSF3.0的白皮书,针对MSF3.0的大规模培训也开始在中国举办。

2006年,MSF4.0随着Visual Studio Team Foun-dation Server2005发布。它增加了不少敏捷开发的内容,并且明确描述了团队协作的典型流程和在新的团队协作软件包VSTS中的应用。2008年,MSF4.2随着Visual Studio Team Foun-dation Server2008发布,它在文字和表达上有一些变化,但实质精神和MSF4.0是非常一致的。2010年之后,随着Visual Studio软件开发系统的更新,MSF也发生了一些变化,对于敏捷的流程(Scrum、Agile)有更多的支持。
7.2 MSF基本原则
MSF没有像敏捷那样搞一个宣言,但是它也有一套思想框架—9条基本原则[注释1],下面来分别讨论。

  1. 推动信息共享与沟通(Foster open communications)

  2. 为共同的远景而工作(Work toward a shared vision)

  3. 充分授权和信任(Empower team members)

  4. 各司其职,对项目共同负责(Establish clear accountability and shared responsibility)

  5. 交付增量的价值(Deliver incremental value)

  6. 保持敏捷,预期和适应变化(Stay agile, expect and adapt change)

  7. 投资质量(Invest in quality)

  8. 学习所有的经验(Learn from all experiences)

  9. 与顾客合作(Partner with internal and external customers)

7.2.1 推动信息共享与沟通
第一个原则,就是所有信息都保留并公开,讨论要包括所有涉及的角色,决定要公开并告知所有人。当然,对牵涉到技术机密、安全性等信息要采取必要的保护措施。

二柱:我们以前都是“老板让你知道,你就会知道,别多问”。看起来比较好控制吧?

阿超:以前两三个哥们一起捣鼓软件,大家都知根知底,好像没有意识到“沟通”的重要性,但是随着项目复杂度和团队规模的增加,没有信息共享与沟通是万万不行的。

二柱:如果有一些事情,我个人也没拿准是不是要通知某一方面的人员,怎么办?

阿超:在这种情况下,宁可过分沟通。

小飞:这是不是很烦?我得不断地告诉别人—我刚做了某事,我刚做了某事,好像网上有不少关于“修改了文档的一个文字错误,就要发邮件告知天下”这样的事儿……

阿超:对,人不能被规则累死,最好是让这些通知能随着事件的发生而自然地传递给关心这些事情的人。例如,在TFS中,你可以设置提醒(Alert),让TFS主动提醒你,你所关心的事发生了变化。另外,在TFS中,所有和项目有关的信息都会保存起来。例如:所有工作项及其历史;所有源代码的修改记录。TFS用户经常问的一个问题是:在TFS中,我为什么不能删除工作项?答案很简单,MSF的第一原则:所有的信息都保留,并公开。TFS的记录就像银行账户里的资金流动记录,是不可以删除的。

大牛:有人犯了一些比较愚蠢的错误(比如一个很低级的Bug),TFS把它们都记录下来了,从个人角度来看,有人会说:“我知道我做错了,已经改正,那最好把原来的记录删除了吧。”这样做,不是有利于打造和谐的团队么?

阿超:和谐的“谐”,是一个“言”和一个“皆”字,说的就是大家都可以发言,所有的事情都要记录。记录留下来,可以做事后分析,给后来的同事,或者别的项目的同事学习。如果删除,那也就违反了第8条原则“学习所有的经验”。如果历史是一笔糊涂账,某些事件被删除了,或者不能提,哪来的和谐?!我们公司要建立“对事不对人”的文化,好像有一句古话,把人的错误比做日食……

果冻:“君子之过也,如日月之食焉:过也,人皆见之;更也,人皆仰之。”还有,“人谁无过?过而能改,善莫大焉。”

大牛:我们以前关于项目的好多事,都装在几个头头的肚子里,最开放的,也不过是把一些问题列在Excel文件,或者是MS Project文件中,但是也没有历史记录。

阿超:看不到所有的信息,那么项目进度以及项目中存在的各种问题就不能及时让所有人知道,这样MSF中其他的原则也就不能实行了。没有开放的信息,也就谈不上“授权”,或者“建立清晰的责任和共同的职责”,以及“保持敏捷,预测并适应变化”。这也是为什么“推动信息共享与沟通”是第一个基本原则。MSF团队模型和MSF过程模型也是建立在“信息共享与沟通”原则上的。

7.2.2 为共同的远景而工作
阿超:“为共同的远景而工作”,对于这句话,大家是怎么理解的?

杂曰:这就是所谓同心同德。兄弟同心,其利断金。我们当然是同心的啦,大家都是哥们,都是为了移山公司的兴旺才来的。

阿超:好,但是这里面提到一个“共同的远景”,这是什么玩意?大家注意这个“共同的远景”是指产品的远景。我们做一个产品,不管是应用软件、行业软件,还是通用软件,要明确项目的目标是什么。

(1)这个目标必须是明确的,没有二义性;

(2)这个目标不是当前就能达到,必须是通过努力才能达到的;

(3)这个目标不是空泛的,它应该对项目成员每天的工作都有指导作用。每天你来上班,如果发现你做的事情对项目的远景没有帮助,你应该跟老板提出来。

小飞:我们有些项目好像没法订出来这样的目标,或者老板也不清楚我们到底要干什么。

阿超:那么,很显然这些项目的带头人没有及格,这些项目最后没有达到预期的目标,也就不奇怪了,因为我们连预期的目标是什么都没有搞清楚。这样的远景也不见得错,但是不要忘了我们讲的是“共同的远景”,即团队的领导人要让全体成员都同意并为之奋斗的项目的远景。如果一部分人还为远景1.0而奋斗,但是另一半人却在为远景2.0而努力,那是要出乱子的。

二柱:如果没有“共同的远景”,即使团队发布了产品,不同的成员对项目是否成功,以后如何发展,也会有不同的看法,因为他们心里的远景(参照物)是不一样的。

阿超:另外,在项目到了关键时刻,我们再和大家统一思想,向往远景,已经晚了。另一个事例,说明远景也和实际工作有密切关系。大松博文在中国女排搞“魔鬼训练”的时候[注释2],如果大家的远景不是世界冠军,干嘛费那么大的劲?每天随便练练,早点洗洗睡得了。如果我们的目标只是业余玩玩网站,大家干嘛费劲学什么MSF?

小飞:远景是由领导决定,还是自下而上形成的?

阿超:一般是由“有远见的人”提出,然后公开讨论,在讨论的过程中,可以消除误解,凝聚共识。这是一个项目的关键,是项目第一阶段要达到的主要目标。

二柱:这是不是俗话说的“统一思想”,或者另一个俗话说的“洗脑”?不是说国外不兴洗脑的么?

阿超:可以这样看,但是我们下面要说另一个基本原则,需要你的大脑有原创精神。

7.2.3 充分授权和信任
这一点的关键是“授权”这个词,授权(Empower)有两个意思:一是给某人权力和权威(Give au-thority to somebody:to give somebody power orauthority);二是给予某人更多自信和自尊(In-spire somebody with confidence: to give some-body a sense of confidence or self-esteem)。在一个高效的团队中,所有的成员都应该能得到充分的授权,他们有权在职权范围内按照自己的承诺完成任务,同时,他们也充分信任其他同事能实现各自的承诺。类似地,团队的顾客(包括内部和外部的顾客)也认为团队能兑现承诺,并进行相应的规划。

二柱:这样做好像很危险哪!

阿超:那应该怎么办?采用“命令”的方式?!充分授权的管理方式是MSF的核心观念之一。MSF团队模型就是建立在以下两个原则上的:

(1)平等协作—成员之间、团队之间是平等协作的关系;

(2)充分授权给团队和成员。

这就是为什么MSF团队模型是网状,而不是层次结构。这样做有什么好处?好处有两点:

(1)被授权的人会承担起自己对项目的责任,同时也期望同事们也同样对项目负责;

(2)MSF提倡自下而上的计划,每个人有充分的权力估计并决定自己的任务需要多长时间,而不是上级交给的时间,这意味着让真正做这件事的人按照自己的估计去完成任务。这样做的结果是啥?是人人都会支持项目的计划和时间表,因为这个时间表是每个人自下而上订出来的!

二柱:听上去很美,但是我作为一个组长,给我的组员充分授权,到头来发现事情都没做完,咋办?我只好不断地问:你做到哪里了,还差多少?

阿超:这要靠工具的支持,在VSTS系统中,由于所有工作的进展都记录在案,任何延迟都会被及时发现,这样组长(或其他层次的领导)就不用把力花在“询问”,而花在“帮助解决”上,在最关键的时候提供指导和帮助。领导在项目中的角色是“支持成员完成任务”,而不是“控制成员,迫使他们完成任务”。充分授权在MSF团队模型的另一个含义是:信任,鼓励团队成员成长,每人都可以在某一时段、某一领域当领导。比如二柱是程序安全性的专家,他就可以带领其他成员对项目进行安全性检查。如果测试工程师果冻刚刚学习了如何做压力测试,他可以带领其他测试人员对产品进行全面的压力测试。

果冻:能不能推而广之,如果企业的各级领导秉持充分授权的信念,让员工觉得被充分授权,从而对工作产生热情,变得积极,进而能够充分发挥自我潜力,企业整体即能够产生良性循环。果冻:在《致加西亚的信》中,我觉得如果没有总统对罗文的授权和信任,罗文也不可能完成这一艰巨的任务。比如,如果总统信不过罗文,派另一个“助手”和他一起走;或者,让罗文每天向领导汇报进展,然后决定下一步行动,这样的话,罗文肯定就不能把信送到。

大牛:果冻,我觉得你的发言,不同于网上成千上万条的《致加西亚的信》读后感,提供了新的视角,真不简单。这一原则还对企业传统招人、用人的方式有冲击,我觉得这是MSF最难在中国公司实行的一部分,“授权”、“放权”的管理理念和很多公司的企业文化不相符。

果冻:我国古代也有充分授权和信任的例子,看这一段—

“郢人垩慢其鼻端,若蝇翼,使匠石斫之。匠石运斤成风,听而斫之,尽垩,而鼻不伤。郢人立不失容。宋元君闻之,召匠石曰:‘尝试为寡人为之。’匠石曰:‘臣则尝能斫之,虽然,臣之质死久矣。’自夫子之死也,吾无以为质矣,吾无言之矣!”大家一致反映要听白话文的解释,果冻解释完了以后,大家七嘴八舌地议论,这里面有授权和信任么?

大牛:有啊,郢人授权匠石,他并没有管匠石的操作细节(用斧头,还是菜刀、匕首或者手术刀);然后他“立不失容”,才能让整个操作成功,这里面体现了信任。

阿超:要注意这种信任是两方面的,匠石也信任郢人会“立不失容”,不会缩头缩脑,因此他才能“运斤成风,听而斫之”。如果有互相猜疑,就会出乱子,例如,匠石心里琢磨“我估计他会害怕,脑袋会往里缩二寸,我要往里再砍两寸”,而郢人心里想“我得再伸出去一些,这样斧子才够得着”……如果没有双方互信的基础,宋元君真的敢试?匠石真的敢砍?这个故事里的相互信任,可以与“高山流水”中伯牙、子期的相互理解相媲美。另外,充分授权之后,领导是不是显得有点没用了呢?

7.2.4 各司其职,对项目共同负责
团队中的每个角色都有自己的职责(见表7-1),如果出了问题,这个角色就要负责任。
7.3 MSF团队模型
MSF团队模型定义了小组同级成员的一些角色和职责,如图7-1所示。

图7-1 团队模型

在MSF团队模型中,任何技术项目都必须达到特定的关键质量目标,才能够被认为是成功的项目。任何一个角色无法实现其目标,都将危及整个项

问:我们发现了问题,但是我们目前的“处理”不能让用户满意,怎么办?

答:测试团队就要和别的角色(如:产品管理/程序管理/开发)一起研究用户需求,在可能的方案中选出一个,比如:

(1)按照目前的状态交付,向用户作出说明(如:在某个操作系统/浏览器版本下,某个功能不能正常工作);

(2)推迟交付时间,让团队有足够的时间来解决问题;

(3)修改产品的约束条件(如要求客户的操作系统/浏览器必须是某一个版本以上,或者增加一个附加条件:产品发布后半年会出新的插件解决问题)。在讨论处理方案时,每个角色从自己的质量目标出发并对其负责。

问:那有冲突怎么办?

答:那就吵呗。各个角色的利益是有一定冲突的,MSF没有掩饰这一点。MSF团队模型的核心是,成功的技术项目必须符合各种利益相关人(Stakeholder)完全不同且常常对立的质量观点。

问:这么说在团队中有矛盾是正常的了?

答:对!例如,用户代表觉得新增加一个功能很酷,因为新功能“让产品更好用”,但是程序管理角色觉得会影响“按约束条件内交付产品”的目标,测试会觉得“保证所有问题都得到处理”的目标受到威胁,用大白话说,就是“我没有时间测试你的新功能,因此不能加这个功能”。这就要各方在整个项目的共同利益之下,协商解决,寻求多赢。

问:我原来认为测试人员说“我没有时间测试你的新功能,因此不能加这个功能!”是态度问题,会被开发人员鄙视的。

答:这是对产品质量负责的态度,你要代表你角色的利益,如果你有充分的授权和信任,你就要直言不讳。除了项目的各个角色之外,MSF团队模型还可以推广到包括操作、业务和用户等外部因素。在对立中寻找共同利益,在冲突中达到平衡。MSF团队模型推动了不同利益代表在追求共同利益过程中的融合。

果冻:“在对立中寻找共同利益,在冲突中达到平衡”,其实我们的孔夫子对此早看得门儿清——子曰:君子和而不同,小人同而不和。
7.5 MSF敏捷开发模式
在Visual Studio TFS中,MSF演化为以下两个分支:

MSF敏捷开发模式;
MSF CMMI开发模式。
MSF敏捷开发模式吸收了近几年来在软件业界流行的各种“敏捷”开发模式的优点,认识到目前大部分软件是以网络应用相联系的,强调和用户更紧密地交流,快速迭代,避免不必要的过程。在继承MSF3.0基本原则的基础上,MSF敏捷开发模式和以前有什么不同?下面分几个小节逐一介绍。

7.5.1 更强调与用户的交流
项目的商业价值要由用户说了算,那些“我觉得用户会喜欢”的东西要及早和用户交流。因为“我觉得”和“用户觉得”是两码事。

小飞:我说一句可能不太中听的话,我觉得有时用户好像很,嗯,很不愿意交流,很自负。有时又很傻,很天真。和他们交流有时好像是对牛弹琴。

二柱:那就派大牛去弹好了。

大牛:有这么几种情况:

(1)用户不懂他想要什么。有些用户只有一个模糊的需求,他们说:我们企业要上ERP!你给我整出来。这种情况下,我们得和用户一起做需求分析,先把牛找出来;

(2)用户想要的和商业价值无关。比如有些用户说,我想让每个按钮都是半透明的,还要有三维效果,就像一些网络聊天软件一样酷!这些要求和他的企业管理项目的价值没有直接联系。也许这个用户代表是一头牛,而不是用户代表,我们要找管牛的人;

(3)用户想要的我们还不懂。这种情况下,我们是牛,用户是在对我们弹琴;

(4)大家心里想的不是牛,也不想弄清牛想什么,只要有钱就行。例如:

客户:你能不能做4G?

我们:上4G干啥?我们还搞不懂4G,好像没有多人真正需要4G。

客户:对,我也不懂4G,但是我手里有四百万预算要花掉……

我们:啊呀,你干吗不早说,那咱们就搞一个四百万的4G项目好了!

7.5.2 质量—防患于未然
防止缺陷的发生成为团队质量控制的首要任务,在防止缺陷的发生和确保缺陷被修复上,所有的角色都要负责。有一些团队把开发和测试有意无意地对立起来,好像二者是矛盾的。一个典型的例子是,有时开发人员不想给测试人员足够的信息,好像不想“帮”测试人员找到缺陷;与此同时,测试人员一旦找到缺陷,会有些得意,“看,你写的代码那么臭,我又发现了N个Bug”。这种对立情绪,也许在短期内能刺激成员的工作热情,而从长远来看是有害的。很少有人会希望在这种充满对立情绪的环境中工作。微软公司内部做过统计,在一个中大规模的团队中,一个“缺陷”从发生到被改正,中间经过了近20道工序,平均总的时间开销是12小时。优秀的团队能做到这一点:可能的缺陷在设计阶段之前就讨论过,并且在代码中已经避免了,因此在“缺陷跟踪系统”中,并没有出现很多缺陷记录在案,但是软件的质量仍然很高。

7.5.3 重视在实战条件下的质量
这一点要求我们保持随时可以发布的高质量。如果用户说:时间到了,网站要上马。我们应该很快地交给用户一个可用的版本,也许功能不多,但是现有的功能都可用。这就要求我们必须保证项目的质量是“随时可用”。为了达到这一点,我们要重视产品的安装和发布—产品要尽早能够达到随时安装、发布的标准。在一些项目中,安装和发布都是最后阶段才做,这就导致几个问题:

  1. 开发过程中,测试团队很难安装产品,阻碍了测试团队的进展。很多情况下,测试人员不得不从多个源头拷贝不同的文件到测试环境中,才能开始测试,浪费了大量时间。

  2. 关于安装的缺陷得不到重视—用户拿到一个Beta版,意见最大的就是安装不上!或者好不容易装好了,却卸载不了,不得不重新安装系统。

7.5.4 精简过程,直奔主题
我们一帮人吭哧吭哧干活是为了什么?主题是什么?是为了解决用户的问题。用户给项目投资了成千上万,不是为了看到一堆过时的文档。同样,在团队成员之间的交流要简明,不必为了交接而搞出许多文档。另外一个重要的因素是,如果团队在整个软件生命周期都使用团队协作服务器(TFS),那么很多活动、决定、文档都自然地记录在TFS上,不必额外去为了文档而再写一些东西。
在这里插入图片描述
9.1 PM是啥
软件团队里除了能写代码、测试代码和画图做设计的成员,还有一类角色,不做上面这些事情但也很重要,我们叫他们项目经理——PM。PM的M就是Manager,但是P有这几种:Prod-uct Manager、Project Manager、Program Man-ager,在不同的行业和公司,他们的作用各不相同。这一章主要介绍微软的项目经理——ProgramManager。Product Manager:产品经理——正确地做产品。目前国内公司大部分PM都是指这个职位。产品经理对一个或多个产品或产品线负责,而互联网产品涉及到这些方方面面:产品定位、市场发展、需求分析、运营、营销、市场推广、商务合作。产品经理横跨这些部门,寻找资源,持续推进产品。随着产品的发展,不同公司,对PM要求会不一样。核心要求是,根据市场和用户需求,协调各部门资源,正确地把握产品定位和方向,解决用户的痛点,持续优化产品。Project Manager:项目经理——正确地做流程。在某些公司,这个职位与产品经理分开单列。他们对项目流程负责,即项目从立项到上线按时完成。正确地协调团队内部外部,调配各部门资源和时间,有效进行风险管理,保证一个项目顺利按计划结项,是一个项目经理的核心价值。Program Manager:微软的职位名称。微软产品团队三足鼎立的角色分配就是PM、开发、测试。PM负责除产品开发和测试之外的所有事情。从某种意义上说,是前面两种角色的综合。微软通常有专门的产品策划(Product Planner),他们和市场部门的专职人员一起,负责产品的长期发展和市场推广。
在这里插入图片描述
10.1.1 Visual Studio的典型用户
Visual Studio是一个非常成功的软件开发集成环境(IDE),它支持VB/C/C++/C#/ASP.NET/Silverlight/Windows Phone等等不同的开发语言和套件,用户可以在上面写几行的Hello World程序,也可以写几万行的多线程软件,它还支持项目管理、测试工具,以及第三方的插件;它的用户遍布全球,说不同的语言,做各行各业的业务,属于大大小小的团队,有些是业余爱好编程,有些是老师和学生,有些是专业开发人员……很多用户对它也有很多改进意见,那我们到底为哪些用户服务呢?同时,VS的微软团队也有很多开发人员,他们也是用户,只听取他们的意见是不是就够了呢?在开发Visual Studio的新版本时,如果你来主持需求分析工作,你怎么才能让上千名工程师、UI设计师、PM和市场推广人员在未来两年中明确地知道他们为什么样的用户而设计和开发?下表列出的是微软在Visual Studio2005设计阶段使用的几个典型用户(Persona)。
在这里插入图片描述
技术说明书又叫设计文档,它用于描述开发者如何去实现某一功能,或相互联系的一组功能。软件的功能多种多样,放之四海而皆准的模板是不太实用的,但是软件的设计总是要遵循一些规律,不遵循这些规律,工程师们往往在实现后面软件的演化中吃苦头。在本书“软件工程师的成长”一章中,我们提到了不少设计原则,在设计中,这些原则就要发挥作用。设计文档应该说明工程师的设计是如何体现下列原则的。

抽象(Abstraction)
内聚/耦合/模块化(Cohesion, Coupling,Modularization)
信息隐藏和封装(Information Hiding, Encap-sulation)
界面和实现的分离(Separation of Interface and Implementation)
如何处理错误情况(Error Handling)
程序模块对于运行环境、相关模块、输入输出参数有什么假设?这些假设和相关的人员验证过么?
应对变化的灵活性(Adapt to Change)
例如,一个企业的流程管理软件,它能处理员工的各种请假需求,程序员会把每一种假期当作一个假期的子类(Sub Class)来处理。如果现在新增一个假期类型(例如“志愿服务者假期”),程序怎么变?有些设计要求工程师必须改源代码,添加子类,且在所有和假期相关的地方添加相应的处理,并要求所有管理软件都更新到最新版本。另一种做法是把所有的假期类型定义为数据,这样一来,新增一种假期类型时,只是数据增多了一项,相应的逻辑(也用数据表示)有一些变动而已。而源程序仍然保持不变。软件如何应对变化,是软件设计最重要的一个方面。

对大量数据的处理能力(Scalability)
如果数据量增大,程序还能保持高效率么?
在这里插入图片描述
在这里插入图片描述
3.2 各种测试方法
13.2.1 单元测试(Unit Test)
请参看本书第2章“单元测试”一节,并思考以下问题:

有时单元测试报了错,再运行一次就好了,于是后来大家就不想花时间改错,多运行几次,有一次通过就行了;
单元测试中的好多错都与环境有关,在别人的机器上都运行不成功;
单元测试耗费的时间要比写代码的时间还多,把代码覆盖率提高到90%以上太难了;
单元测试中我们还要测试效能和压力,花了很多时间;
我们都这么费劲地测了,那还要测试人员干什么?
13.2.2 代码覆盖率测试(Code Coverage Analysis)
前面单元测试中提到了代码覆盖率,简单来说代码被执行过,就是被“覆盖过”。如果一段程序运行一组测试用例之后,100%的代码被执行了,是不是意味着再也不用写新的测试用例了呢?答案是否定的。这是因为——

  1. 不同的代码是否执行,有很多种组合。一行代码被执行过,没有出现问题,并不表明这一行代码在所有可能条件的组合下都能正确无误地运行。

  2. 代码覆盖不能测出未完成的代码(所缺少的逻辑)导致的错误。比如:

1)没有检查过程调用的返回值;

2)没有释放资源。

  1. 代码覆盖不能测出效能问题。

  2. 代码覆盖不能测出时序问题,即由时序导致的程序错误(例如:线程之间的同步)。

  3. 不能简单地以代码覆盖率来衡量代码中与用户界面相关的功能的优劣。

13.2.3 构建验证测试(Build Verification Test,BVT)
顾名思义,构建验证测试是指在一个构建完成之后,构建系统会自动运行一套测试,验证系统的基本功能。在大多数情况下,这些验证的步骤都是在自动构建成功后自动运行的,有些情况下也会手工运行,但是由于构建是自动生成的,我们也要努力让BVT自动运行。

问:一个系统有这么多功能点,什么是基本的功能,什么不是基本的功能?

答:基本功能的特点是:第一,必须能安装;第二,必须能够实现一组核心场景。例如,对于字处理软件来说,其基本功能是必须能打开/编辑/保存一个文档文件,但是它的一些高级功能,如文本自动纠错,则不在其中;又如,对于网站系统,其基本功能是用户可以注册/上传/下载信息,但是一些高级功能,如删除用户、列出用户参与的所有讨论,则不在其中。在运行BVT之前,可以运行所有的单元测试,以保证系统的单元测试和程序员的单元测试版本一致。因为在不少情况下,开发人员修改了程序和单元测试,却忘了将修改过的单元测试同时签入源代码库中。通过BVT的构建可以称为可测(Testable),意思是说团队可以用这一版本进行各种测试,因为它的基本功能都是可用的。反之,通不过BVT的构建称为“失败的构建”(Failed,Rejected)。如果构建验证测试不能通过,那么自动测试框架会针对每一个失败的测试自动生成一个Bug(小强)。一般来说,这些Bug都有最高优先级,开发人员要首先处理。大家知道,维持每日构建,并产生一个可测的版本是软件开发过程中质量控制的基础。对于导致问题的小强,我们该怎么办?答案是——

  1. 找到导致失败的原因,如果原因很简单,程序员可以立即修改并直接提交。

  2. 找到导致失败的修改集,把此修改集剔出此版本(程序员必须修正Bug后再重新把代码提交到源代码库中)。

  3. 程序员必须在下一个构建开始前修正该Bug。

方法1和2都可以使今天的构建成为“可测的”,但是有时各方面的修改互相依赖,不能在短时间内解决所有问题,那就只能采用方法3了。

问:有人提到一种“冒烟测试”,是怎么回事?

答:事实上这是一种基本验证测试,据说是从硬件设计行业流传过来的说法。当年设计电路板的时候,很多情况下,新的电路板一插上电源就冒起白烟,烧坏了。如果插上电源后没有冒烟,那就是通过了“冒烟测试”,可以进一步测试电路板的功能了。我们正在讨论的BVT也是一种冒烟测试。

13.2.4 验收测试(Acceptance Test)
测试团队拿到一个“可测”的构建之后,就会按照测试计划,测试各自负责的模块和功能,这个过程可能会产生总共10来个甚至100个以上的Bug,那么如何才能有效地测试软件,同时在这一阶段该怎样衡量构建的质量?在MSF敏捷模式中,我们建议还是采用场景来规划测试工作。在“基本场景”的基础上,把系统在理论上目前支持的所有场景都列出来,然后按功能分类测试,如果测试成功,就在此场景中标明“成功”,否则,就标明“失败”,并且用一个或几个“小强”/Bug来表示失败的情况。当所有的测试人员都完成了对场景的测试后,我们自然就得出了表13-5。

表13-5 场景测试报告

这样就能很快地报告“功能测试56%通过”等。如果所有场景都能通过(有些情况下可以将该标准从100%降至90%左右),则这个构建的质量是“可用”的,这就意味着这一个版本可以给用户使用了。在这种情况下,客户、合作伙伴可以得到这样的版本,这也是所谓“技术预览版”或“社区预览版”的由来。但是,有一个重要的问题要提请大家注意:“可用”,并不是指软件的所有功能都没有问题,而是指在目前的用户场景中,按照场景的要求进行操作,都能得到预期的效果。注意以下两种情况:

  1. 在目前还没有定义的用户场景中,程序质量如何,还不得而知。例如:场景中没有考虑到多种语言设置。

  2. 对不按照场景的要求进行的操作,结果如何,还不得而知。例如:在某一场景中,场景规定用户可以在最后付款前取消操作,回到上一步,如果一个测试人员发现在多次反复提交/取消同一访问后,网页出现问题,但这并不能说明用户场景失败,当然,对于这个极端的Bug,也必须找出原因并适时修正。

这种测试有时也称为验收测试(Acceptance Test),因为如果构建通过了这样的测试,这一个构建就被测试团队“接受了”。同时,还有对系统各个方面进行的“验收”测试,如系统的全球化验收测试,或者针对某一语言环境、某一个平台做的验收测试。

13.2.5 “探索式”的测试(Ad hoc Test)
“Ad hoc”原意是指“特定的,一次性的”。这样的测试也可以叫Exploratory Test。什么叫“特定的”测试或者“探索式”的测试?就是指为了某一个特定目的而进行的测试,且就这一次,以后一般也不会重复测试。在软件工程的实践中,“Ad hoc”大多是指随机进行的、探索性的测试。比如:测试人员小飞拿到了一个新的构建,按计划是进行模块A的功能测试,但是他灵机一动,想看看另一个功能B做得如何,或者想看看模块A在某种边界条件下会出现什么问题,于是他就“Ad hoc”一把,结果还真在这一功能模块中发现了不少小强。“Ad hoc”也意味着测试是尝试性的,“我来试试,在这个对话框中一通乱按,然后随意改变窗口大小,看看会出什么问题……”,如果没问题,那么以后也不会再这么做了。

问:我听说有人是“Ad hoc”测试的高手,这是什么意思?

答:有很多测试人员会按部就班地进行测试,但是还有一些人头脑比较灵活,喜欢另辟蹊径,测试一些一般人不会想到的场景,这些人往往会发现更多的小强。开发人员对这样的“Ad hoc”高手是又爱又恨。

问:看问题要分两方面,有些“Ad hoc”发现的小强在正常使用软件时几乎不会出现,我们要不要花时间“Ad hoc”?

答:现在一些成功的通用软件的用户以百万计,按部就班的测试计划很难涵盖很多实际的场景,这时,探索式测试能够发现重要的问题;另外,一些风险很大的领域,例如安全性,一旦出了问题,威胁就会相当大,这时要多鼓励一些探索式测试,以弥补普通测试的不足。从这个意义上说,探索式测试可以用来衡量当前测试用例的完备性,如果你探索了半天,都没有发现什么在现有测试用例之外的问题,那就说明现有的测试用例是比较完备的。探索式测试的测试流程是不可重复的,因为它的测试都是“特定”测试,没法重复。这一原因,使得探索式测试不能自动化,就这一点而言,还达不到CMMI二级——可重复级。作为管理人员来说,如果太多的小强是在探索式测试中找出来的,那我们就要看看测试计划是否基于实际的场景,开发人员的代码逻辑是否完善,等等。同时,要善于把看似探索式的测试用例抽象出来,囊括到以后的测试计划中。因此,探索式测试太多是团队管理不佳的一个标志,因为探索式测试是指那些一时想到要做但以后并不打算经常重复的测试。

13.2.6 回归测试(Regression Test)
请看本书第2章“回归测试”一节的介绍。要说明的是,回归测试不仅仅包括单元测试,也包括其他类型的测试。

13.2.7 场景/集成/系统测试(Scenario/ Integration / System Test)
在软件开发的一定阶段,我们要对一个软件进行全面和系统的测试,以保证软件的各个模块都能共同工作,各方面均能满足用户的要求。这类测试叫系统/集成测试。

问:有一种测试叫场景测试,是什么意思?

答:就是指以场景为驱动的集成测试,关于“场景”,大家可以看本书第10章“典型用户和典型场景”一节,里面有对场景专门的介绍。这一方法的核心思想是:当用户使用一个软件时,他/她并不会独立使用各个模块,而是把软件作为一个整体来使用。我们在做场景测试的时候,就需要考虑在现实环境中用户使用软件的流程是怎样的,然后模拟这个流程,看看软件能不能满足用户的需求。这样,才能使软件符合用户的实际需求。以一个图像编辑软件为例,这个软件的各个模块都是独立开发的,可是用户有一定的典型流程,如果这个流程走得不好,哪怕某个模块的质量再高,用户也不会满意。用户的典型流程是:

  1. 把照相机的存储卡插入电脑

  2. 程序会弹出窗口提示用户导入照片

  3. 用户根据提示导入照片

  4. 用户对照片进行快速编辑

  5. 调整颜色、亮度、对比度

  6. 修改照片中人物的形象(红眼、美白、美颜等)

  7. 用户选择其中几幅照片,用E-mail发送给朋友,或分享到社交网站上。

其中任何一步出现问题,都会影响用户对这一产品的使用。如果这里面各个模块的用户界面不一致(即使是“确认”和“取消”按钮的次序不同),用户使用起来也会很不方便。这些问题都是在单独模块的测试中不容易发现的。

问:应该什么时候做集成测试?是不是越早越好?

答:原则上是当一个模块稳定的时候,就可以把它集成到系统中,和整个系统一起进行测试。在模块本身稳定之前就提早做集成测试,可能会报告出很多Bug,但是这些由于提早测试而发现的Bug,有点像汽车司机在等待绿灯时不耐烦而拼命地按喇叭——也就是说,有点像噪音。我们还是要等到适当的时机再开始进行集成测试。

问:但是开发人员也想早日发现并修复所有的Bug,软件工程的目标不就是要早发现并修正问题么?总是要等待,听起来好像没有多少效率。

答:对,这就要提到在微软内部流行的另一种测试——伙伴测试(Buddy Test)。

13.2.8 伙伴测试(Buddy Test)
如上所述,在一个复杂系统的开发过程中,当一个新的模块(或者旧模块的新版本)加入系统中时,往往会出现下列情况。

  1. 导致整个系统稳定性下降。不光影响自己的模块,更麻烦的是阻碍团队其他人员的工作。

  2. 产生很多Bug。这些Bug都要录入到数据库中,经过层层会诊(Triage),然后交给开发人员,然后再经历一系列Bug的旅行,才能最后修复,这样成本就变得很高。

如何改进呢?一个办法当然是写好单元测试,或者运用重构技术以保证稳定性等。我们这里要讲的伙伴测试是指开发人员可以找一个测试人员作为伙伴(Buddy),在签入新代码之前,开发人员做一个包含新模块的私人构建(Private Build),测试人员在本地做必要的回归/功能/集成/探索测试,发现问题直接与开发人员沟通。通过伙伴测试把重大问题都解决了之后,开发人员再正式签入代码。在项目后期,签入代码的门槛会变得越来越高,大部分团队都要求缺陷修正(Bug Fix)必须经伙伴测试的验证才能签入代码库。

13.2.9 效能测试(Performance Test)
用户使用软件,不光是希望软件能够提供一定的服务,而且还要求服务的质量要达到一定的水平。软件的效能是这些“非功能需求”或者“服务质量需求”的一部分。效能测试要验证的问题是:软件在设计负载内能否提供令用户满意的服务质量。这里涉及如下两个概念。

  1. 设计负载首先要定义什么是正常的设计负载。从需求说明出发,可得出系统正常的设计负载。例如,一个购物网站,客户认为正常的设计负载是每分钟承受20次客户请求。

  2. 令用户满意的服务质量其次要定义什么样的质量是令用户满意的。比如,同一个购物网站,用户满意的服务质量可以定义为:每个用户的请求都能在2秒钟内返回结果。

针对以上两点还可以逐步细化。

  1. 设计负载的细化上面我们只提到“承受20次客户请求”,那么这些客户的请求到底是什么,可以按请求发生的频率来分类。

1)用户登录(10%)。

2)用户查看某商品详情(50%)。

3)用户比较两种商品(10%)。

4)用户查看关于商品的反馈(20%)。

5)用户购买商品,订单操作(5%)。

6)所有其他请求(5%)。

  1. 服务质量的细化有些请求,是要对数据进行“写”操作,可以要求慢一些,比如“用户下订单,购买商品”,对这一服务质量,请求可以放宽为5秒钟,甚至更长。

除了用户体验到的“2秒钟页面刷新”目标外,效能测试还要测试软件内部各模块的效能,这要求软件的模块能报告自身的各种效能指标,通过Perf-mon或其他测试工具表现出来。和别的测试不同,效能测试对硬件要有固定的要求,而且每次测试需要在相同的机器和网络环境中进行,这样才能避免外部随机因素的干扰,得到精准的效能数据。

问:我们以前做效能测试的时候,服务器上都没有任何负载,数据库里也没有几条记录,所以效能都很不错,可是当系统真的运行起来时就不行了。这些效能测试是自欺欺人的,对么?

答:在做效能测试的时候,的确要避免在不现实的环境中测试,例如要避免在没有任何用户、商品记录的系统上做测试;但是也没有必要为了追求真实而过分模拟随机的环境。简单地说,现实的环境有如下两方面。

  1. 现实的静态数据比如上面提到的数据库的各种记录,如果要模拟一个实际运行的商业网站,除了一定数量的用户和商品记录外,还得模拟在运行一段时间后产生的交易记录。

  2. 现实的动态数据这就是负载,现实中总会有一些人在同时使用这一个系统。效能测试中要考虑到“负载”,可以分为:

1)零负载,即只有静态数据,在这种情况下测试的结果应该是稳定的,可以不断地收集数据进行回归测试;

2)加上负载,根据具体情况可以分负载等级进行测试。

同时,客户会问,“如果我的系统慢了,怎么办,我是增加机器的数量,还是提高每个机器的处理能力?”这是我们要回答的问题。效能测试的结果应该成为“用户发布指南”的一部分,为用户发布和改进系统提供参考。在VSTS中如何进行效能测试,本章后面还会详细讲解。在进行效能测试的过程中,可以得到系统效能和负载的一个对应关系,这时,就可以看到能维持系统正常功能的最大负载是多少。如果负载足够大,或者过分大,那就成了下一个测试的目标——压力测试。

13.2.10 压力测试(Stress Test)
压力测试严格地说不属于效能测试。压力测试要验证的问题是:软件在超过设计负载的情况下是否仍能返回正常结果,没有产生严重的副作用或崩溃。

问:为啥不要求软件在这种情况下仍然在2——3秒钟内返回结果?

答:因为我们做不到。

提示:我们在这一部分要求返回“正常结果”,啥叫“正常”?我们也要就此与客户达成一致。比如,同一个购物网站,所有请求都能在网络返回“超时”错误前返回,就可以认为是“正常”。或者网站返回“系统忙,请稍候”,也是正常结果。但是,如果用户提交的请求一部分执行,另一部分没有执行,或者出现用户信息丢失,这些都是不正常的结果,应该避免。那我们怎样增加负载呢?对于网络服务软件来说,主要考虑以下两个方面。

  1. 沿着用户轴延长

以刚才的购物网站为例,正常的负载是20个请求/分钟,如果有更多的用户登录,怎么办?那么负载就会变成30、40、100个请求/分钟,或更高。

  1. 沿着时间轴延长

做过网络服务的都知道,网络的负载有时间性,负载压力的波峰和波谷相差很大,那么如果每时每刻负载都处于峰值,程序会不会垮掉?这就是我们要做的第二点:沿着时间轴延长。一般要模拟48小时的高负载才能认为系统通过测试。与此同时,可以减少系统可用的资源来增加压力。注意,压力测试的重点是验证程序不崩溃或产生副作用。即看看在超负载的情况下,我们的程序是否仍能正确地运行,而不会死机。在给程序加压的过程中,程序中的很多“小”问题就会被放大,暴露出来。最常见的问题是:

内存/资源泄漏,在压力下这会导致程序可用的资源枯竭,最后崩溃;
一些平时认为“足够好”的算法实现会出现问题。比如,Windows Platform SDK有一个GetTickCount()函数,它返回自系统启动后所经过的毫秒数,用DWORD来表示。经过47.9天之后DWORD会溢出,GetTickCount()会从0开始重新计数,你的程序如果用了不同的TickCount来计算时间,不要假设后来的Tick-Count一定会比先前的TickCount大,也许系统在运行一段时间后会出现莫名其妙的错误,但是系统重新启动后,又找不到原因。
进程/线程的同步死锁问题,在压力下一些小概率事件会发生,看似完备的程序逻辑也会出现问题。在VSTS中如何进行压力测试,本章后面部分会有详细讲解。
13.2.11 内部/外部公开测试(Alpha/Beta Test)
在开发软件的过程中,开发团队希望让用户直接接触到最新版本的软件,以便从用户那里收集反馈,这时开发团队会让特定的用户(Alpha/Beta用户)使用正处于开发过程中的版本,用户会通过特定的反馈渠道(E-mail、BBS、微博等)与开发者讨论使用中发现的问题,等等。这种做法成功地让部分用户心甘情愿地替开发团队测试产品并提出反馈。按惯例来说,Alpha Test一般指在团队之外、公司内部进行的测试;Beta Test指把软件交给公司外部的用户进行测试,与之对应地,软件就有Alpha、Beta1、Beta2版本。在网络普及之前,做Beta Test费时费力,成本较高,现在由于网络的传播速度很快,与外部用户的联系渠道很畅通,很多外部用户都想先睹为快。因此,现在开发团队增加了反馈的密度,不必再局限于Alpha或者Beta发布,而是不断地把一些中间版本发布出去以收集反馈。

13.2.12 易用性测试(Usability Test)
问:作为测试人员,我们是不是也要做易用性测试?

答:测试人员,以及其他的团队成员都可以对软件的可用性提出意见,包括以Bug的形式放在TFS中。软件的可用性并不神秘,就是让软件更好用,让用户更有效地完成工作。但是我觉得“易用性测试”似乎更多地用来描述一套测试软件可用性的过程,这个过程一般不是由测试人员来主导的,而是由对软件设计和软件可用性有大量研究的“可用性设计师”来实行。可以参考本书相关章节和网络的相关文章。为了弄清楚软件的可用性,并了解用户的需求,移山公司的员工特地做了一次易用性测试——小飞学了很酷的“WPF/我佩服”Web界面技术,然后做了一个小游戏——3D挖雷。大家用了之后,都觉得不错,用鼠标单击/双击,左键/右键都可以进行各种不同的操作。于是他们迫不及待地想找一个“典型用户”来做易用性测试。王屋村的村民石头他爹刚好路过,就被移山公司的小伙子们拉了进来,成为第一个“典型用户”。大家七嘴八舌地介绍了游戏的功能,就让石头他爹试一试。石头他爹看到鼠标,说,这个怎么和俺家里的不一样?小飞说:这是光电鼠标,好用得很!三分钟过去了,游戏还没有开始;五分钟、十分钟过去了,游戏还是没有进展。阿超走过去看看到底是怎么回事——原来,石头他爹手指不灵活,按鼠标时鼠标会稍稍移动,导致程序无法捕捉鼠标双击事件。问题是小飞设计的游戏支持鼠标单击、双击操作,而且分别对应不同的功能。此外,有些功能还只能通过右键弹出菜单来执行。石头他爹看起来很迷惑。这时,小飞说:左键/右键/单击/双击都可以。从此之后,石头他爹对每一个操作都问:是按左键还是按右键?是按一下还是两下?小飞露出了“faint”的表情。半个小时后,大家送走了石头他爹,同时送他一个鼠标垫作为礼物。

阿超:(目送石头他爹的背影)幸好……

小飞:幸好啥?

阿超:幸好你还没有介绍你那超级功能,要按住Ctrl键,同时拖动鼠标才能使用。否则我们还要花半个小时陪石头他爹一起学习玩这个游戏。苹果公司的Macintosh团队在发布革命性的Mac电脑之后,收到了不少用户的反馈,说用鼠标拖拽文件进行拷贝时,总是要反复操作很多次才能成功,团队内部反复试验,都不能重现这个问题。后来才发现,出现这个Bug的关键是拖拽时手指离开鼠标按钮一会儿,然后重新拖拽。一般用户都是第一次使用这一革命性的设备(鼠标),所以经常会犯错;但是Mac团队的成员使用鼠标都已经非常熟练,所以没有人会犯这个错误,也就找不到这个Bug。

13.2.13 “小强”大扫荡(Bug Bash)
问:我们已经讲了太多的测试了,好像微软还有一个叫“Bug Bash”的活动,是啥意思?

答:Bug Bash,或者叫Bug Hunt,简而言之,就是大家一起来找小强的活动——小强大扫荡。一般是安排出一段时间(如一天),这段时间里所有测试人员(有时也加入其他角色)都放下手里的事情,专心找某种类型的小强。然后结束时,统计并奖励找到最多和最厉害的小强的员工。

问:这是不是可以看做是“全体动员探索式测试”?

答:一般情况下是的,但是并不是全体人员用键盘鼠标一通乱敲乱点就可以搞定,大扫荡的内容也应该事先安排好。这种活动,如果运用得当,会带来这样的功效:

鼓励大家做探索式的测试,开阔思路
鼓励测试队伍学习并应用新的测试方法,例如在做完“软件安全性测试”培训后,立马针对“安全性”做一次小强大扫荡,或者为“全球化/本地化测试”做一次小强大扫荡也是很常见的
找到很多小强,让开发人员忙一阵子当然,小强大扫荡也有一些副作用:
扰乱正常的测试工作
如果过分重视奖励,会导致一些数量至上、滥竽充数的做法因此,这里有必要提醒两个细节:
一定要让“小强大扫荡”有明确的目标、明了的技术支持。
一定要让表现突出的个人介绍经验,让其他成员学习。要记住,最好的测试,是能够防止小强的出现。
13.4.1 运用工具记录手工测试
不管有多少人写了多少文章来描述“测试自动化”及其前景,可这些自动化的东西最初还是得有人“手动”地进行。下面的步骤演示了如何创建手工测试。

  1. 在VSTS(有Team Edition for Software Testers套件)中,新建一个项目,在Visual C#或其他类型中,选中Test。填入适当的项目名字和解决方案的名字,可以把它加入到源代码控制中。我们会看到新的项目新建了不少文件,如图13-2所示,其中有我们之前提到过的UnitTest1.cs,另一个文件是ManualTest1.mht。

图13-2 创建新的测试项目

  1. 打开ManualTest1.mht,你会看到它是模板(又一个模板),在这个文件中,你可以填入下面的内容:

1)测试的标题(Test Title)——简明的标题。

2)测试的详情(Test Details)——测什么。

3)测试的对象(Test Target)——测试什么功能。

4)测试的步骤(Test Steps)——提供详细的测试步骤和每一步期望的结果。

5)修改的记录(Revision History)——对这一测试进行修改的历史记录。

九条:不就是这样一个简单的文件么,我自己不用写也可以记住。

阿超:好记性不如烂笔头,当测试矩阵有上百个可能的设置,产品又日趋复杂的时候,我们需要把一些手工测试结果记下来。另外,如果来了个新手接班,项目要移交给他/她,怎么办?

13.4.2 运用工具记录自动测试
对于网络程序,对网页的访问和操作可以像录音一样录下来,“录音”主要是指记录HTTP请求的URL,以及header和body中的各个参数。记录是否成功取决于服务器返回的状态码。当然,我们也可以自己定义Pass/Fail的条件,这样后续测试只要重新“放录音带”即可。操作:鼠标右键选中测试项目,选择Add | WebTest…(如图13-3所示)。

图13-3 增加一个Web Test

于是,IE浏览器就会打开,同时Web Test Recorder也会激活,测试人员就可以按照场景测试网站的各项功能了,可以注意到Web Test Recorder会记录每一个网页的地址,以及可能的参数。测试人员可以进一步增加测试的内容(如图13-4所示)。

图13-4 进一步增加Web Test的功能

其中值得一提的是,测试人员可以选中“GenerateCode…”,生成测试脚本,可以在脚本一级开发测试。测试人员可以用脚本建立循环测试,或者根据某一步测试的结果选择不同的测试分支(Path),这更加灵活。另外,我们还可以用C#作为测试代码的语言,这比其他通用工具的脚本强大许多,这也是用VSTS做测试的好处之一。不同的测试可以把不同的次序结合起来运行,测试人员可以用“Ordered Test”来管理这样的测试集合。Ordered Test的创建方法与Web Test类似。

13.4.3 如何测试效能
除了功能方面的测试外,我们还要测试那些“服务质量”。如效能测试、负载测试、压力测试。我们在本章前面讲到了这三种测试。在Stone项目中,以产品搜索为例,这三种测试的区别如下:

效能测试:在100个用户的情况下,产品搜索必须在3秒钟内返回结果。

负载测试:在2000个用户的情况下,产品搜索必须在5秒钟内返回结果。

压力测试:在高峰压力(4000个用户)持续48小时的情况下,产品搜索的返回时间必须保持稳定。系统不至于崩溃。

我们可以举一个现实生活中旅客乘坐列车的例子来做对比。

效能测试:在80%上座率的情况下,期望:列车按时到达,并且乘客享受到优质服务。乘务员不要太累。

负载测试:在100%上座率的情况下,期望:列车大部分按时到达,乘客享受到基本服务。乘务员的疲劳在可恢复范围内。

压力测试:在高峰压力是200%上座率,全国铁路系统增加20%的列车,持续15天的情况下,期望:列车能到站,乘客能活着下车,系统不至于崩溃。乘务员也能活着下车。

说一句题外话,飞机如何做压力测试?波音公司在早期是用沙袋或铅块压在飞机机翼上的不同部位,来模拟飞机在各种激烈运动中各个部位的受力,受力的上限一般是平常水平飞行受力的7倍。当然,现在的飞机设计公司都有一系列完备的模拟和测试工具(如风洞和计算机模拟工具等)。效能、负载、压力这些方面的测试会产生很多数据,这些数据最好保存在数据库中,以便于日后跟踪分析。这些数据将为以后做网站容量规划(CapacityPlanning,又称能力规划)提供重要的依据。在VSTS中,效能和压力测试都可以用“Load Test”来实现,Load Test牵涉到许多因素,因此我们需要按部就班地设置,如图13-5所示。

图13-5 创建负载测试向导

负载测试的一个核心概念是“场景”,这与软件设计的场景有所区别,它主要包含负载测试的各种参数。

  1. 停顿时间(Think Time):在每次请求之间和一批测试之间的停顿。

  2. 负载模型(Load Pattern):模拟的用户量是恒定在一个数值的(如:总是30个用户),或者是分级进行的(如:开始是5个用户,每分钟增加10用户,直到最高50个用户)。

  3. 测试混合模型(Test Mix):此次负载测试要运行多少种测试,每种测试所占的比例是多少。

  4. 浏览器混合模型(Browser Mix):各种浏览器的选择及比例。

  5. 网络混合模型(Network Mix):各种带宽的网络及比例。

设置好场景后,下一步要决定我们收集什么样的效能数据(Performance Counter),这时,我们可以收集代理机器(Agent,模拟的服务请求从这里发出)和控制机器(Controller)的效能数据,更重要的是收集网络服务器的效能数据(如图13-6所示)。

在这里插入图片描述

图13-6 收集效能数据

这些效能数据会反映在负载测试中。最后一步是设置运行负载测试中的各种参数。图13-7是某次网络负载测试的运行结果。

图13-7 负载测试运行结果

网络应用的负载测试比较复杂,要下一番苦功才能掌握。一般来说,我们会将所有数据都保存到数据库中,以便将来做分析。至于这次测试的目标:确认网络服务器能否在规定时间内处理用户的请求,服务器上有没有出现错误。这两种数据都能立即得到。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
17.2 其实还是人的问题
在“现代软件工程”这门课程中,大家分成6—7人的小组进行项目开发,有项目经理(PM)、开发人员(Dev)、测试人员(Test)等。不久就有PM抱怨,怎么小组里有些人就是不干活?最早,大家假设所有人都是热心干活的。抽象出来,就是:

P = {做事的}
后来,大家发现这个集合可以细分成:P = {P1=做事的,P2=不做事的}不做事,也就罢了,不过这些人还偏偏在团队中占个位置,仿佛要给大家做贡献,布置任务时,他/她仿佛也同意了……这让我们的PM大伤脑筋。大家不但要操心软件中各个模块的问题,还要操心负责这些模块的人的问题,这的确是很多同学没有经历过的。其实,随着经历的丰富,我们还可以看到集合中出现了第三类人,他们会更让我们头痛:

P = {做事的,不做事的,P3=不让别人做事的}
我原来以为学术界应该比较纯洁,没想到这第三类人也不少,我所尊敬的科学家韦钰老师在回忆她科研的经历时[注释3]说:

中国这个问题是很严重的。我们建立第一个学科的时候,我遇到了很大的困难。这些困难都不是来自政治界的,而是来自学术界本身,来自学术界某些权威。有位权威就是不同意给我立题和资助,说“你怎么能研究这个,你怎么能进到我的领域来”……

这位权威的话让我想起很多动物也有这样的行为,在自己的领地周边洒点体液,以告诫其他动物不得擅入;或者一只正要享用腐鼠的猫头鹰,“吓”的一声,警告天空飞过的大鸟(鹓鶵)。林子大了,什么鸟都有,作为万物之灵的人类,是不能满足于仅仅只有三种花样的。很快,我们可以看到第四、第五类人的出现:

P={做事的,不做事的,不让别人做事的,P4=做假的事的,P5=假装做事的}
P4 = 做假的事的人,可以举打磨芯片的例子4。而假装做事的人(P5)往往和P4成对出现,例如负责评审汉芯并给予其很高评价的各位院士和专家。有了这样的榜样,我们也不难发现身边的例子。2008年夏天,在与某学院合作的“软件实现技术”课程中,有一个小组没有参加最终评比,得分为零。为什么呢?原来他们的“电梯作业”原封不动地抄袭了前一年同学的方案。微软的工程师在评审时发现这个小组的作业看起来眼熟,后来注意到所有文件的日期都是一年以前的……如果我们也敷衍过去,那我们就成了P5了(写程序蒙到微软工程师头上了,也真是令人佩服)。人无完人,人非圣贤,总会犯错误,原因很多,有的是个人一念之差,有些是时间安排的问题,有的是有仿生学的原理,有的可以追溯到社会的潜规则或种种因素。但是我们上的不就是一门普通的软件工程课么?为什么耍这么多花招?为什么不能都当一回简单的P1呢?
17.5 团队合作的几个阶段
与本书4.6节提到的“两人合作的不同阶段和技巧”一样,团队合作也有类似的阶段。平时大家似乎相安无事,但是一旦出现催化剂(软件未能按时发布,项目推广受挫,绩效评估结果公布,团队接受新的任务,等等),团队合作的状态就会出现剧烈变化。变好或者变坏,还要看团队成员,特别是领导者的智慧了。我们这里说的“领导”,除了有明确领导职责的人员之外,还包括技术带头人、产品经理等。

17.5.1 萌芽阶段
萌芽阶段(Forming),就像小苗破土而出,柔弱但充满希望。在这一时期,团队成员刚刚接触到团队的宗旨,同时很可能刚刚互相认识。团队的目标没有真正达成一致,而成员则非常依赖于团队领导的指导。其他特征如下。

  1. 个人的角色和职责不清楚,做事的规程往往被忽略。

  2. 这时大家都很有礼貌,一般交流不少,每个人可能都想得到队友的接纳,试图避免冲突和容易引起挑战的观点。团队的成员在有意无意地探知同伴和领导的做事方式和容忍度。

  3. 成员也在琢磨任务到底有多大,怎么去完成它。

  4. 每个人都忙着适应环境、团队结构、角色、日常流程等。有鉴于此,严重的问题不一定能够及时地提出来讨论。重要的事情并不能够真正得到解决。

  5. 开始各种各样的讨论。成员们对于组织结构有不少看法,对完成任务的困难也有不少讨论,但是还没有把注意力集中到解决问题上。

在这一时期,领导要回答很多问题:我们要做什么,怎么做,如何才是成功,与其他团队是什么样的关系,等等。由于百废待兴,没有太多时间进行详细的讨论以达成共识,因此,领导要快刀斩乱麻地决定一些重要的问题,让团队在短时间内看到一些成果。

17.5.2 磨合阶段
磨合阶段(Storming)就像一个人的青少年时期,充满了对个人、同伴和团队的疑惑和冲突。团队中的一团和气只能维持一小段时间,大家不得不认真地面对问题,开展讨论。随着讨论的深入,有些人会沉不住气,就会出现小的意见分歧和冲突。这些冲突不一定都是技术问题,也许是关于角色、职责、相互关系,甚至是各自性格、文化的冲突。这时,成员之间会出现竞争,不少人都想成为某个领域的“拥有者”(在软件项目中,谁负责哪方面,每个方面要怎么做,等等)。同时也有一些人以不同的方式进行挑战。也许会形成小团体,甚至有权力斗争。有人专注于解决问题,有人喜欢“与人斗,其乐无穷”,有人想回到当初一团和气的阶段。冲突的结果是有人觉得自己“赢了”,有人反之。有时即使大家有相同的论点,还是有争论(因为大家想充分表达自己)。这个阶段还有一种现象,即开会时谁嗓门大,谁往往会赢。在团队中解决争端,有下面的几种方法,各有利弊:

追求最大和谐,达到全体共识(Consensus):好处是大家能同心协力行动,坏处是需要很长时间才能达到共识,也许达到不了。
投票(Voting):好处是能较快地形成结论,坏处是投票会产生一些赢家和输家,输家总是不太满意,如果处理不好,会导致对立。
咨询(Consulting),由领导私下和几位专家讨论,形成决定:团队的其他成员也许会有不被重视的感觉。
独裁(Dictatorship):领导很爽,但是副作用较多。
交换决定权(Trade Off):几个主要角色的代表轮流做决定,行使独裁权。这个模式执行起来也许会让团队的方向游移不定。
这个时期最有可能出现谣言和误解,对此,团队领导最好让矛盾和分歧充分地暴露,将各种冲突公开化,并且学会倾听、理解和调整。有时候,团队领导不得不妥协,以便项目继续向前推进,因为没有时间去说服每个人,从而得到最优结果。积极、公开的信息流动是消除谣言和误解的最好方式。如果缺乏足够的信息交流平台(如SharePoint服务器,公开的电子邮件组,公开的项目进度表),成员之间会互相猜疑。领导必须做出明确规定,要求公司上下都要进行充分的交流,并且告知团队成员,不允许将信息滞留在小团队内部。领导在这个阶段会发现成员的一些特点,要区别对待,例如:

  1. 对于技术能力强,并且通过实际工作得到大家认可的成员,应鼓励他们发挥更多技术领导作用。

  2. 对一些经常持有不同意见、特立独行、看似拖团队后腿的成员,这时不应该妄下判断,其实他们很可能是不错的员工,只是没有掌握适当的表达方式,不懂如何说服别人,应该鼓励他们找到与队友相处、共事的途径。

  3. 有的成员可以应付自己的工作,但他们不爱讨论、分享经验,似乎没有更高的要求。对这类成员,应该让他们与更自信、积极的同事合作,给予他们要求更高的工作,让富有挑战性的工作激发他们的热情。

  4. 有的成员在实际工作中显示出较差的技能,不怎么胜任工作。对这类成员,要考虑安排他们做得来的事,调整其在团队中的位置,做到人尽其用;如果的确不适合团队,那就要有壮士断腕的决心。

长期处于磨合阶段的团队,自信心会下降,会出现久病乱投医的现象,我们用什么开发方法,这个模式还是那个模式?我们为啥升职提薪比别的团队差……等等。就像某国国家足球队不断变更打法和风格,一会儿是平行站位,一会儿是双后腰,有时过分保守,有时过于冒进,有时学习欧洲,有时模仿南美,走马灯一样换教练,最后找不着北,沦为笑柄。如果磨合未能成功,那么团队就会出现崩溃的迹象,例如:领导像走马灯一样来来往往,带来全新的战略却没有实质内容;技术能力强的同事突然离职;团队业绩拿不出手,在市场上打不过竞争对手,只好把一些内部指标鼓吹成巨大成就(例如再一次重构了代码,测试覆盖率再次小幅度提高);团队内形成小团体,等等。

17.5.3 规范阶段

从磨合阶段毕业,进入规范阶段(Norming)的团队,成员们意识到光争吵是没有用的,大家还是要协同作战。成员们就很多事情取得了一致。角色和职责定义得非常清楚。团队还进行过有趣的团队建设活动。这一时期的团队有如下特点。

  1. 团队公开地讨论流程和工作的方式。团队的领导得到广泛的尊重,有能力的成员也分担了一定的领导职责,并自然地获得大家的尊重。

  2. 随着项目的开展和成员们的互动,一些成文或不成文的规则逐步建立起来了。

  3. 作为一个整体,团队要做什么、不做什么,都更加明确。团队定下了更现实的目标和决心。

  4. 通过聆听、讨论,成员互相之间更加了解,认识到并欣赏各自的能力和经验。在工作中互相支持,大家意识到并尊重各人的个性。

在这一阶段,领导主要扮演促成者和鼓励者的角色,协调成员之间的矛盾和竞争关系,建立起流畅的合作模式。要注意到,并不是团队一进入规范阶段,就万事大吉了。经验表明,很多情况下团队会由规范阶段回到磨合阶段,或者在两个阶段间徘徊。团队成员们必须努力工作,才能使团队保持在这一阶段,同时还要抵御外界的压力,以免使团队分裂或回到磨合阶段。另外,一个人要是刚刚加入一个有一定历史的团队,要注意了解这个团队的规范(Norm)是什么,入境随俗。正如西方谚语说——When in Rome, doas the Romans do。

17.5.4 创造阶段
经历了萌芽、磨合、规范阶段,现在团队终于可以创造一些有意义的东西——这就是创造阶段(Per-forming)。当然并不是所有的团队都能到达这一阶段。这一阶段的现象如下。

团队知道为何而战,并将注意力集中到如何创造、实现目标上。共同的远景不再是空话,而是实实在在的阶段性成果。这些成果鼓舞了士气,整个团队成为其他团队羡慕的对象。
高度自治,不再需要领导的时时教诲与介入。不同意见仍会出现,但是成员都以一种积极的心态和方式来解决。团队成员相互支持,互相依赖并保持各自的灵活性。团队成员之间都比较熟络,同时也互相信任,个人可以放手独立工作。
角色和职责能够根据项目的要求自然地转换,没有人为此担心或发牢骚。在这种情况下,所有人都能把大部分精力花在工作上。团队士气高涨。能够避免冲突,即使发生冲突,也能妥善解决。
这一阶段团队的效率达到了巅峰状态,而领导则要实践“充分的授权”这一原则,委派得力的人员解决问题,并按期检查。其次是要完善团队业绩和个人绩效相结合的考评体系,最大限度地调动团队成员的积极性。同时安排未来的领导者有机会崭露头角。这样的团队有一个特点:他们一般不会关心或者争执“方法论”的问题——我们究竟是瀑布模型,还是改良的螺旋模型,或者超级敏捷型。我们是CMMI2级还是3级。方法论对于他们,就像水对于鱼一样自然。一个实际的例子就是:微软公司很多员工都不知道何为MSF。当然,这时也必须认识到危险所在。优秀团队有时会骄傲自满,团队成员自我感觉太好,过分亲近也可能导致过度利己,不重视与别的团队合作,不重视客户需求等。最近IT行业的故事一再验证了“伟大的公司离破产只有十八个月”这一规律,优秀团队的领导切莫等闲视之。

17.5.5 团队的效能曲线和假团队

讲团队管理的书籍很多,其中的经典著作The Wis-dom of Teams提到团队的效能曲线

猜你喜欢

转载自blog.csdn.net/c2289206/article/details/85261190