第14章 祸起萧墙
① 项目进度经常以一种难以察觉,但是残酷无情的方式慢慢落后。
② 进度落后是难以识别、不容易防范和难以弥补的。
Part 1 里程碑还是沉重的负担?
如何根据一个严格的进度表来控制项目?
第一个步骤是制订进度表。
a.必须是具体的、特定的、可度量的事件,能够进行清晰定义。
b.澄清了那些划分得比较模糊的阶段——计划、编码、调试。
c.好的里程碑对团队来说实际上是一项服务,可以用来向项目经理提出合理要求的一项服务,而不确切的里程碑是难以处理的负担。
Part 2 “其他的部分反正会落后”
① 对软件开发队伍,进取同样是非常必要的。进取提供了缓冲和储备,使开发队伍能够处理常规的异常事件,可以预计和防止小的灾祸。而对任务进行计算和对工作量进行度量,会对进取超前会造成一些消极的影响。
② 如何判断哪些偏离是关键的呢?只有采用 PERT 或者关键路径技术才能判断。(它显示谁需要什么样的东西,谁位于关键路径上,他的工作滞后会影响最终的完成日期。另外,它还指出一个任务在成为关键路径时,可以落后的时间。)
③ 严格地说,PERT 技术是关键路径计划的细化,如果使用 PERT 图,它需要对每个事件估计三次,每次对应于满足估计日期的不同可能性。
④ PERT 的准备工作是 PERT 图使用中最有价值的部分。它包括整个网状结构的展开、任务之间依赖关系的识别、各个任务链的估计。这些都要求在项目早期进行非常专业的计划。
⑤ 它展示某人为了使自己的工作远离关键路径,需要超前多少,也建议了补偿其他部分失去的时间的方法。
Part 3 地毯的下面
每个老板都需要两种信息:
① 需要采取行动的计划方面的问题,用来进行分析的状态数据。
② 出于这个目的,需要了解所有开发队伍的情况,但得到状态的真相是很困难的。
有两种掀开毯子把污垢展现在老板面前的方法,它们必须都被采用。一种是减少角色冲突和鼓励状态共享,另一种是猛地拉开地毯。
① 减少角色的冲突。首先老板必须区别行动信息和状态信息。他必须规范自己,不对项目经理可以解决的问题做出反应,并且决不在检查状态报告的时候做安排。如果老板把会见、评审、会议明显标记为状态检查(status-meeting)和问题-行动(problem-action)会议,并且相应控制自己的行为,这对整个过程会很有帮助。
② 猛地拉开地毯。PERT 图以及频繁的里程碑是这种评审的基础。使得每个人都知道问题的所在,而产品构件经理应准备解释延迟的原因,什么时候结束,采取的步骤和需要的任何帮助——老板提供的,或者是其他小组间接提供的。
PERT 图的准备工作是老板和要向他进行汇报的经理们的职责。需要一个小组(一至三个人)来关注它的更新、修订和报告,这个小组可以看作是老板的延伸。对大型项目,这种计划和控制(Plan and Control) 小组的价值是非常可贵的。
③ 计划和控制小组作为监督人员,明白地指出了不易察觉的延迟,并强调关键的因素。他们是早期预警系统,防止项目以一次一天的方式落后一年。
(其他:在里程碑报告中很容易记录“计划”和“估计”的日期。计划日期是项目经理的工作产物,代表了经协调后的项目整体工作计划,它是合理计划之前的判断。估计日期是最基层经理的工作产物,基层经理对所讨论的工作有着深刻的了解,估计日期代表了在现有资源和已得到了作为先决条件的必要输入(或得到了相应的承诺)的情况下,基层经理对实际实现日期的最佳判断。项目经理必须停止对这些日期的怀疑。)
作者总结
14.1 一天一天的进度落后比起重大灾难,更难以识别、更不容易防范和更加难以弥补。
14.2 根据一个严格的进度表来控制项目的第一个步骤是制订进度表,进度表由里程碑和日期组成。
14.3 里程碑必须是具体的、特定的、可度量的事件,能进行清晰能定义。
14.4 如果里程碑定义得非常明确,以致于无法自欺欺人时,程序员很少会就里程碑的进展弄虚作假。
14.5 对于大型开发项目中的估计行为,政府的承包商所做的研究显示:每两周进行仔细修订的活动时间估计, 随着开始时间的临近不会有太大的变化;期间内对时间长短的过高估计,会随着活动的进行持续下降;过低估计直到计划的结束日期之前大约三周左右,才有所变化。
14.6 慢性进度偏离是士气杀手。[Microsoft 的 Jim McCarthy 说:“如果你错过了一个最终期限(deadline),确保制订下一条 deadline。”]
14.7 进取对于杰出的软件开发团队,同优秀的棒球队伍一样,是不可缺少的必要品德
14.8 不存在关键路径进度的替代品,使人们能够辨别计划偏移的情况。
14.9 PERT 的准备工作是 PERT 图使用中最有价值的部分。它包括了整个网状结构的展开、任务之间依赖关系的识别、各个任务链的估计。这些都要求在项目早期进行非常专业的计划。
14.10 第一份 PERT 图总是很恐怖的,不过人们总是不断进行努力,运用才智制订下一份 PERT 图。
14.11 PERT 图为前面那个泄气的借口,“其他的部分反正会落后”,提供了答案。
14.12 每个老板同时需要采取行动的异常信息以及用来进行分析和早期预警的状态数据。
14.13 状态的获取是困难的,因为下属经理有充分的理由不提供信息共享。
14.14 老板的不良反应肯定会对信息的完全公开造成压制;相反,仔细区分状态报告、毫无惊慌地接收报告、决不越俎代庖,将能鼓励诚实的汇报。
14.15 必须有评审的机制,从而所有成员可以通过它了解真正的状态。出于这个目的,里程碑的计划和完成文档是关键。
14.16 Vyssotsky:我发现在里程碑报告中很容易记录“计划(老板的日期)”和“估计(最基层经理的日期)”的日期。项目经理必须停止对这些日期的怀疑。”
14.17 对于大型项目,一个对里程碑报告进行维护的计划和控制(Plan and Control)小组是非常可贵的。
第15章 另外一面
① 公共应用程序的用户在时间和空间上都远离它们的作者,因此对这类程序,文档的重要性更是不言而喻! 对软件编程产品来说, 程序向用户所呈现的面貌和提供给机器识别的内容同样重要。
② 文章剩余部分将对那些说教之辞一笔带过, 而把重点放在如何做(才能产生一篇优秀的文档)上。
Part 1 需要什么样的文档
不同用户需要不同级别的文档。某些用户仅仅偶尔使用程序,有些用户必须依赖程序,还有一些用户必须根据环境和目的的变动对程序进行修改。
① 使用程序。
1. 目的。主要的功能是什么?开发程序的原因是什么?
2. 环境。程序运行在什么样的机器、硬件配置和操作系统上?
3. 范围。输入的有效范围是什么?允许显示的合法范围是什么?
4. 实现功能和使用的算法。精确地阐述它做了什么。
5. 输入-输出格式。必须是确切和完整的。
6. 操作指令。包括控制台及输出内容中正常和异常结束的行为。
7. 选项。用户的功能选项有哪些?如何在选项之间进行挑选?
8. 运行时间。在指定的配置下,解决特定规模问题所需要的时间?
9. 精度和校验。期望结果的精确程度?如何进行精度的检测?
② 验证程序。
每一份发布的程序拷贝应该包括一些可以例行运行的小测试用例,为用户提供信心—他拥有了一份可信赖的拷贝,并且正确地安装到了机器上。
在程序修改之后,进行常规运行。这些用例可以根据输入数据的范围划分成三个部分。
1. 针对遇到的大多数常规数据和程序主要功能进行测试的用例。它们是测试用例的主要组成部分。
2. 数量相对较少的合法数据测试用例,对输入数据范围边界进行检查,确保最大可能值、最小可能值和其他有效特殊数据可以正常工作。
3. 数量相对较少的非法数据测试用例, 在边界外检查数据范围边界,确保无效的输入能有正确的数据诊断提示。
③ 改程序。调整程序或者修复程序需要更多的信息。
1. 流程图或子系统的结构图,对此以下有更详细的论述。
2. 对所用算法的完整描述,或者是对文档中类似描述的引用。
3. 对所有文件规划的解释。
4. 数据流的概要描述——从磁盘或者磁带中,获取数据或程序处理的序列——以及在每个处理过程完成的操作。
5. 初始设计中,对已预见修改的讨论;特性、功能回调的位置以及出口;原作者对可能会扩充的地方以及可能处理方案的一些意见。另外,对隐藏缺陷的观察也同样很有价值
Part 2 流程图
① 流程图显示了程序的流程判断结构,它仅仅是程序结构的一个方面。只适用于绘制在一张图上。
② 一页纸的流程图,成为表达程序结构、阶段或步骤的一种非常基本的图示。
Part 3 自文档化(self-documenting)的程序
① 把文档整合到源代码。这对正确维护是直接有力的推动,保证编程用户能方便、即时地得到文档资料。这种程序被称为自文档化。
② 文档是我们以及前人都不曾成功背负的重担。作为基本目标,我们必须试图把它的负担降到最小。
③ 方法。
第一个想法是借助那些出于语言的要求而必须存在的语句,来附加尽可能多的“文档” 信息。
第二个方法是尽可能地使用空格和一致的格式提高程序的可读性,表现从属和嵌套关系。
第三个以段落注释的形式,向程序中插入必要的记叙性文字。
④ 一些技巧。
- 为每次运算使用单独的任务名称。
- 使用包含版本号和能帮助记忆的程序名称。
- 在过程(PROCEDURE)的注释中,包含记叙性的描述文字
- 尽可能为基本算法提供参考引用, 通常它会指向更完备的处理方法。
- 显示和算法书籍中的传统算法的关系
- 声明所有的变量。
- 用标签标记出初始化的位置。
- 对程序语句进行分组和标记,以显示与设计文档中语句单元的一致性。
- 利用缩进表现结构和分组。
- 在程序列表中,手工添加逻辑箭头。
- 使用行注释来解释任何不很清楚的事情。
- 把多条语句放置在一行,或者把一条语句拆放在若干行,以吻合逻辑思维,表示和其他算法描述一致。
⑤ 为什么不?
最强烈的反对来自必须存储的源代码规模的增加。随着编程技术越来越向在线源代码存储的方向发展,这成为了一个主要的考虑因素。
作者总结
15.1 对于软件编程产品来说,程序向用户所呈现的面貌与提供给机器识别的内容同样重要。
15.2 即使对于完全开发给自己使用的程序,描述性文字也是必须的,因为它们会被用户-作者所遗忘。
15.3 培训和管理人员基本上没有能向编程人员成功地灌输对待文档的积极态度—文档能在整个生命周期对克服懒惰和进度的压力起促进激励作用。
15.4 这样的失败并不都是因为缺乏热情或者说服力,而是没能正确地展示如何有效和经济地编制文档。
15.5 大多数文档只提供了很少的总结性内容。必须放慢脚步,稳妥地进行。
15.6 由于关键的用户文档包含了跟软件相关的基本决策,所以它的绝大部分需要在程序编制之前书写,它包括了 9 项内容。
15.7 每一份发布的程序拷贝应该包括一些测试用例,其中一部分用于校验输入数据,一部分用于边界输入数据,另一部分用于无效的输入数据。
15.8 对于必须修改程序的人而言,他们所需要程序内部结构文档,同样要求一份清晰明了的概述,它包括了 5 项内容。
15.9 流程图是被吹捧得最过分的一种程序文档。详细逐一记录的流程图是一件令人生厌的事情,而且高级语言的出现使它显得陈旧过时。(流程图是图形化的高级语言。)
15.10 如果这样,很少有程序需要一页纸以上的流程图。[在这一点上,MILSPEC 军用标准实在错得很厉害]
15.11 即使的确需要一张程序结构图,也并不需要遵照 ANSI 的流程图标准。
15.12 为了使文档易于维护,将它们合并至源程序是至关重要的,而不是作为独立文档进行保存。
15.13 最小化文档负担的 3 个关键思路:
借助那些必须存在的语句,如名称和声明等,来附加尽可能多的“文档”信息。
使用空格和格式来表现从属和嵌套关系,提高程序的可读性。
以段落注释,特别是模块标题的形式,向程序中插入必要的记叙性文字。
15.14 程序修改人员所使用的文档中,除了描述事情如何以外,还应阐述它为什么那样。对于加深理解,目的是非常关键的,但即使是高级语言的语法,也不能表达目的。
15.15 在线系统的高级语言(应该使用的工具)中,自文档化技术发现了它的绝佳应用和强大功能。