读书:《人月神话》摘录版11-15章

读书:《人月神话》摘录版11-15章_第1张图片
人月神话.PNG

第十一章 未雨绸缪
不变只是愿望,变化才是永恒。普遍的做法是,选择一种方法,试试看;如果失败了,没关系,再试试别的。不管怎样,重要的是先去尝试。
你必须“是否构建一个实验性系统,然后抛弃它?”,问题是“是否预先计划抛弃原型的开发,或者是否将该原型发布给用户?”将原型发布给客户,可以获得时间,但代价高昂-用户痛苦/重新开发人员分散了精力/产品影响了声誉。为舍弃而计划,无论如何,你一定要这样做。
一旦认识到试验性的系统必须被构建和丢弃,具有变更思想的重新设计不可避免。第一步是接受这样的事实,变化是与生俱来的,不是不合时宜和令人生厌的异常情况。开发人员交付的是用户满意程度,而不仅仅是有形的产品。用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。目标/设计策略/技术的一些变化无可避免,事先为它们做准备总比假设它们不会出现要好得多,也不建议顾客所有的目标和需求变更必须、能够、或者应该整合到设计中。抛弃原型概念本身就是对事实的接受-随着学习的过程更改设计。
为变更计划系统:包括细致的模块化、可扩展的函数、精确完整的模块间接口设计和完备的文档。另外,还可能会采用包括调用队列和表驱动的一些技术。最重要的措施是使用高级语言和自文档技术,以减少变更引起的错误。变更的阶段化是一种必要的技术。每个产品都应该有数字版本号,每个版本都应该有自己的日程表和冻结日期,在此之后的变更属于下一个版本的范畴。
为变更计划组织架构,现在编程小组失败的主要原因是管理控制得太少而不是太多。技术和管理线,不愿为设计书写文档的原因,不仅仅是由于惰性或者时间压力。相反,设计人员通常不愿意提交尝试性的设计决策,再为它们进行辩解。“通过设计文档化,设计人员将自己暴露在每个人的批评之下,他必须能够为他书写的一切进行辩护。如果团队架构因此受到任何形式的威胁,则没有任何东西被文档化,除非架构是完全受到保护的”。
管理人员需要参与编程,高级人才需要进行管理培训。项目目标、进展和管理问题必须在高级人员整体中得到共享。只要能力允许,高层人员必须时刻做好技术和情感上的准备,管理团队或者亲自参与开发工作。
对一个广泛应用的程序,其维护总成本通常是开发成本的40%或更多。用户越多,所发现的错误也越多。缺陷修复总会以固定(20%-50%)的几率引入新的BUG。全局范围修复难度/维护人员不是代码人员,回归测试成本高。
第十二章 干将莫邪
首先,项目的关键问题是沟通,个性化的工具妨碍而不是促进沟通。其次,当机器和语言发生变化时,技术也会随之变化,所有生命周期都是很短的。毫无疑问,开发和维护公共的通用编程工具的效率更高。专业需要和个人偏好同样需要很多专业工具,作者建议为每个团队配备一名工具管理人员。这个角色管理所有通用工具,能指导他的客户和老板如何使用工具。同时,他还能编制老板需要的专业工具。因此,项目经理应该制定一套策略,并为通用工具的开发分配资源,将所有分散的工具管理人员集中起来形成公共的工具小组未必会更有效率,但实际上却不是这样。项目经理必须考虑、计划、组织的工具到底有哪些呢?首先是计算机设施,他需要硬件和使用安排策略;它需要操作系统提供服务;它需要语言,语言的使用方针必须明确;然后是实用程序、调试辅助程序、测试用例生成工具和处理文档的字处理系统。
目标机器是软件所服务的对象,程序必须在该机器上进行最后测试。辅助机器是那些在开发过程中提供服务的机器。如果在为原有的机型开发新操作系统,该机器不仅充当目标机器的角色,同时也作为辅助机器。
目标机器类型有哪些?团队开发的监督程序或其他系统核心软件当然需要他们自己的机器。目标机器系统需要若干操作员和一两个系统编程人员,以保证机器上的标准支持是及时更新和实时可用的。其它速度不快、存储有要求、大容量内存,以及调试机器或软件-在调试过程中,所有类型的程序参数可以被自动计数和测量。进度安排,仿真器,一开始机器时间比较匮乏。有限的机器分配成连续的块,团队自己决定如何使用,持续的精力集中能减少思考时间。冲刺后完成文档,卓有成效地安排和共享时间块。
辅助机器和数据服务。仿真装置(间歇性硬件失败)、编译器和汇编平台、程序库和管理(首先是受控,即程序的拷贝属于经理,他可以独立地授权程序的变更;其次是使发布的进展变得正式,以及开发库与集成、发布的正式分离和进展)、编程工具、实用程序、文档系统(阅读计划+维护)、性能仿真装置。
高级语言(生产率和调试速度)和交互式编程(漫长的调试周转时间是调试周转时间)
第十三章 整体部分
如何开发一个可以运行的系统?如何测试系统?如何将经过测试的一系列构件集成到已测试过、可以依赖的系统?需要系统地考虑:
剔除BUG的设计。系统各个组成部分的开发者都会做出一些假设,而这些假设之间的不匹配是大多数致命和难以察觉的Bug的主要来源。简言之,产品的概念完整性是使它易于使用的同时,也使开发更容易进行,而且BUG更不容易产生。细致的功能定义、仔细的规格说明、规范化的功能描述说明以及这些方法的实施,大大减少了系统中必须查找的BUG数量。
测试规格说明。编写代码前,规格说明必须提交给外部测试小组,以详细地检查说明的完整性和明确性。
自上而下的设计,将系统开发划分为体系结构设计、设计实现和物理编码实现。Wirth的流程将设计看成一系列精细化步骤。比较粗的任务定义和大概的解决方案,开始是勾画能得到主要结果的模块。然后,对还定义和方案进行细致的检查,以判断结果和期望之间的差距。同时,将上述步骤的解决方案在更细的步骤中进行分解,每一项任务定义的精化变成了解决方案中算法的精化,还可能伴随着数据表达式的精化。过程中识别出解决方案或数据模块时,对这些模块的进一步细化可以独立其他工作,而模块大小决定了程序的适用性和可变化的程度。Wirth主张每个步骤中,尽可能使用级别较高的表达方法来表现概念和隐藏细节,直到有必要进行进一步的细化。
好的自上而下的设计可以避免几个BUG。首先,清晰的结构和表达方式更容易对需求和模块功能进行准确的描述;其次,模块分割和模块独立性避免了系统级BUG;第三,细节的抑制使结构上的缺陷更加容易识别;第四,设计在每个精化步骤上都是可以测试的,所以测试可以尽早开始,并且每个步骤的重点可以放在合适的级别上。当遇到意想不到的问题时,可能推翻顶层设计,重新开始整个过程。这种情况经常发生,它让我们更加清楚在什么时候和为什么抛弃了整个设计并重新开始。结构化编程。语言块,花括号。注意:关键的地方和构建无BUG程序的核心,是把系统的结构作为控制结构来考虑,而不是独立的分支语句。
构件单元测试。本机调试(程序员仔细设计调试过程-计划停止的地点,检验内存的位置,需要检查的东西以及如果没有预期结果的对策等。重大罪过是没有对程序分成测试段,重新开始)-内存转储(尽可能减少机器使用时间以满足更多程序员的要求)-快照(快照插入程序,无需重新汇编和编译)-交互式调试(本机调试实时性和批处理调试高效使用率,多个程序载入内存,被调试程序和一个只能由程序控制的终端相关联,由监督调度程序控制调试过程,但需要在调试过程中要预先进行计划。需要清理[更新调试日志,把更新后的程序列表加入到项目文件夹中,解释调试中出现的奇怪现象;剩余一半时间用于准备:为下一次操作设计详细的测试,进行计划的变更和改进],更新程序列表,准备数据,在每次调试会话中,第一次交互取得的工作进展是后续交互的3倍)-测试用例(实际调试过程和测试用例的设计)。
系统集成调试:系统调试花费的时间会比预期的长,它的困难证明了需要一种完备系统化和可计划的方法。包括:使用经过调试的构件单元(通常的看法是系统集成调试要求只能在每个部分都能正常运行之后开始?经验表明,集成越早越好-在系统测试中使用完好的、经过调试的构件,能比搭建测试平台和进行全面构件单元测试节省更多的时间)、搭建充分的测试平台(供调试使用的所有程序和数据,不会整合到最终产品中:伪构件,微缩文件,伪文件,辅助程序-测试数据的发生器等)、控制变更(必须有人负责-控制和负责各个构件单元的变更或版本之间的替换:受控拷贝/测试版本的拷贝/开发库,对变更和差异进行记载)、一次添加一个构件(完整的测试用例,测试子系统)、阶段化&定期变更(替换构建回归,定期发布,稳定周期。要么阶段大间隔宽,要么小而频繁—直到下次系统构件定期发布前都一直使用快速补丁,在当前发布中,已经通过测试并进行了文档化的修补措施整合到系统平台中)。
第十四章 祸起萧墙
重大灾害(重大压力、彻底重组、新技术)比较容易处理,但一天天的进度落后难以识别、不容易防范和难以弥补的。应急任务、紧急任务、管理人员检查。
里程碑很大程度上依赖于以往的经验,必须是具体的、特定的、可度量的事件,能够清晰定义,具体的里程碑是百分百事件。这些切实的里程碑澄清了那些划分比较模糊的阶段—计划、编码和调试。好的里程碑对团队来说实际上是一项服务,可以用来向项目经理提出合理要求的一项服务,而模糊的里程碑是难以处理的负担(不能误导,慢性进度偏离同样是士气杀手)。进取提供缓冲和储备,必须关注每一天的落后,PREP关键路径技术,上面的活动滞后会影响的最终完成日期。PREP准备工作是工具使用过程中最有价值的部分,包括整个网状结构展开、任务之间依赖关系的识别和各个任务链的估计等。人们愿意让自己的工作远离关键路径。
一线经理发现自己队伍出现计划偏离时,肯定不会马上赶到老板汇报,团队先想办法或重新安排进度。但每个老板都需要两种信息:需要采取行动计划方面的问题,用来进行分析的状态数据。只要项目经理觉得自己可以解决问题,他就不会告诉老板。有两种掀开毯子把污垢展现在老板面前的方法,必须被采用。一种是减少角色冲突和鼓励状态共享,另一种是猛地拉开地毯。
减少角色冲突。首先老板必须区别行动信息和状态信息。他必须规范自己,不对项目经理可以解决的问题做出反应,并且绝不在检查状态报告的时候做安排。老板把会见、评审、会议明显标记为状态检查和问题-行动会议,并且相应控制自己的行为,这对整个过程会很有帮助。当然,事态发展到无法控制时,状态检查会议会演变成问题-行动会议。
不论协作与否,拥有能了解状态真相的评审机制是必要的。PREP图以及频繁、明确的里程碑是这种评审的基础。大型项目,可能需要每周对某些部分进行评审,大约一个月左右进行整体评审。报告展示里程碑和实际完成情况—每个人都知道问题的所在,而产品构件经理应准备解释延迟的原因,什么时候结束,采取的步骤和需要的任何帮助-老板或其它小组提供的。
计划日期(项目经理的工作产物,代表了经协调后的项目整体工作计划,代表协调后的项目整体工作计划)+ 估计日期(基层经理的工作产物,在现有资源和已得到作为先决条件的必要输入的情况,基层经理的最佳判断)。项目经理必须停止对这些日期的怀疑,将重点放在使其更加精确上,以便得到没有偏见的估计,而不是那些合乎心意的乐观估计或者自我保护的保守估计。一旦它们在每个人的脑海中形成了清晰的印象,项目经理就可以预见到将来如果他在哪些地方不采取任何措施,就会出现问题。
PREP图的准备工作是老板和要向他进行汇报的经理们的职责。需要一个小组(1-3)来关注它的更新、修订和报告,可以将这个小组看作是老板的延伸。大型项目计划和控制小组的价值非常可贵—小组的职权权限于产品线经理询问他们什么时候设定或更改里程碑,以及是否达到了里程碑。计划和控制小组处理所有的文字工作,因此产品线经理的负担将会减到最少—仅仅需要做出决策。富有热情的、老练的、熟练的计划和控制小组。计划和控制小组作为监督人员,明白地指出了不易察觉的延迟,并强调关键的因素。
第十五章 另外一面
演示如何完成这些工作,将重点放在“如何做”。不同用户需要不同级别的文档。某些用户仅仅偶尔使用程序,有些用户必须依赖程序,有些必须根据环境和目的的变动对程序进行修改。三四页纸常常可以容纳以上所有的信息,需要表达的简洁和精确。
使用程序。每个用户都需要一段对程序进行描述的文字,此文档描述基本决策,绝大部分需要在程序编制之前书写。为了得到一份有用的文字描述,就必须放慢脚步,稳妥地进行。目的(主要的功能是什么?开发程序的原因是什么?)、环境(程序运行在什么样的机器、硬件配置和操作系统上)、范围(输入的有效范围是什么?允许显示的合法输入范围是什么?)、实现的功能和使用的算法(精确地阐述它做什么)、输入-输出格式(必须是确切和完整的)、操作指令(包括控制台及输出内容中正常和异常结束的行为)、选项(用户的功能选项有哪些?如何在选项之间进行挑选?)、运行时间(在指定的配置下,解决特定规模问题所需要的时间)、精度和校验(期望结果的精确程度?如何进行精度的检测?)。
验证程序,测试用例。针对大多数常规数据对程序主要功能进行测试的用例,它们是测试用例的主要组成部分;数量相对较少的合法数据测试用例,边界和有效特殊数据;数量相对较少的非法数据测试用例,无效数据有正确的诊断提示。
修改程序。调整程序或修复程序需要更多的信息,这要求了解全部的细节,记录在注释良好的列表中。修改者迫切需要一份清晰明了的概述,不过这一次是关于系统的内部结构。概述组成部分:流程图或子系统的结构图、对所有算法的完整描述,或者是类似算法的参考资料、对所有文件和规划的解释、数据流处理的概要描述-从磁盘或磁带中获取数据或程序处理的序列-以及在每个处理过程完成的操作、初始设计中,对已预见修改的讨论;特性、功能回调以及出口位置;原作者对可能会修改的地方以及可能处理方案的一些意见。另外,对隐藏缺陷的观察也同样很有价值。
流程图:很多程序不需要流程图,很少程序需要一页纸以上的流程图。一页纸的流程图刘成为表达程序结构、阶段或步骤的一种非常基本图示。它通常是被吹捧得最过分的程序。
自文档化的程序:试图努力维持不同文件之间的同步关系,是一件非常费力不太好的事情。更合理的方法是:每个数据项包含两个文件都需要的所有信息,采用指定的键值来区别,并把它们组合到一个文件中。程序变动总是不能及时精确地反映在文档中。文档来自程序,自文档化-必须试图把文档负担降得最小:借助语言要求附加尽可能多的文档信息(标签/声明语句/符号名称等)+ 使用空格和一致的格式提高可读性+段落注释。如果仅仅使用最高级别的结构图,另外使用一份文档的方法可能更安全一些,因为节后不会经常变化。一些技巧:为每次运行使用单独的任务名称。维护一份日志,记录程序运行的目的、时间和结果;使用包含版本号和能帮助记忆的程序名称;过程注释中包含记述性的描述文字;尽可能为基本算法提供参考引用,通常它会指向更完备的处理方法;显示和算法书籍中传统算法的关系:更改、定制细化、重新表达等;声明所有的变量,声明已经包含名称和结构性描述,需要增加的仅仅是对目的的解释;用标签标记出初始化的位置;对程序语句进行分组和标记,以显示与算法描述文档中语句单元的一致性;利用缩进表现结构和分组;程序列表中,手动加逻辑箭头;使用行注释或标记任何不很清楚的事情;把多条语句放置成一行,或者把一条语句拆放在若干行,以吻合逻辑思维,体现和其他算法描述一致。

你可能感兴趣的:(读书:《人月神话》摘录版11-15章)