admin管理员组

文章数量:819698

人月神话(五)未雨绸缪、干将莫邪、整体部分

第11章 未雨绸缪

Part 1 实验性工厂和增大规模

对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。要解决所有的问题,除了重新开始以外,没有其他的办法—即开发一个更灵巧或者更好的系统。系统的丢弃和重新设计可以一步完成,也可以一块块地实现。所有大型系统的经验都显示,这是必须完成的步骤。而且,新的系统概念或新技术会不断出现,所以开发的系统必须被抛弃,但即使是最优秀的项目经理,也不能无所不知地在最开始解决这些问题。

Part 2 唯一不变的就是变化本身

一旦认识到试验性的系统必须被构建和丢弃,具有变更思想的重新设计不可避免,从而直面整个变化现象是非常有用的开发人员交付的是用户满意程度,而不仅仅是实际的产品。用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。

软件产品易于掌握的特性和不可见性,导致它的构建人员面临永恒的需求变更。

不但目标上的变化不可避免,而且设计策略和技术上的变化也不可避免。抛弃原型概念本身就是对事实的接受—随着学习的过程更改设计。

Part 3 为变更计划系统

如何为上述变化设计系统,是个非常著名的问题,在书本上被普遍讨论——可能讨论得比实践还要多得多。

① 包括细致的模块化、可扩展的函数、精确完整的模块间接口设计、完备的文档

② 可能会采用包括调用队列和表驱动的一些技术。

③ 最重要的措施是使用高级语言和自文档技术,以减少变更引起的错误。采用编译时的操作来整合标准声明,在很大程度上帮助了变化的调整。

④ 变更的阶段化是一种必要的技术。每个产品都应该有数字版本号每个版本都应该有自己的日程表和冻结日期,在此之后的变更属于下一个版本的范畴。

Part 4 为变更计划组织架构

当系统发生变化时,管理结构也需要进行调整。这意味着,只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性。

这其中的障碍是社会性的,人们必须同顽固的戒心做斗争。首先,管理人员自己常常认为高级人员太“有价值”,而舍不得让他们从事实际的编程工作;其次,管理人员拥有更高的威信。

① 管理人员需要参与技术课程,高级技术人才需要进行管理培训。项目目标、进展、 管理问题必须在高级人员整体中得到共享。

② 只要能力允许,高层人员必须时刻做好技术和情感上的准备,以管理团队或者亲自参与开发工作。

③ 组建外科手术队伍式的软件开发团队,这其结果是当高级人才编程和开发时,不会感到自降身份。

④ 上述组织架构的设计是为了最小化成员间的接口。同样的,它使系统在最大程度上易于修改。当组织构架必须变化时,为整个“外科手术队伍”重新安排不同的软件开发任务,会变得相对容易一些。这的确是一个长期有效的灵活组织构架解决方案。

Part 5 前进两步,后退一步

在程序发布给顾客使用之后,它不会停止变化。发布后的变更被称为“程序维护”。

计算机系统的硬件维护包括了三项活动—替换损坏的器件、清洁和润滑、修改设计上的缺陷。(大多数情况下—但不是全部—变更修复的是实现上、 而不是结构上的一些缺陷。对于用户而言,这常常是不可见的。)

软件维护主要包含对设计缺陷的修复。和硬件维护相比,这些软件变更包含了更多的新增功能,它通常是用户能察觉的。

对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多。令人吃惊的是,该成本受用户数目的严重影响。用户越多,所发现的错误也越多。

麻省理工学院核科学实验室的 Betty Campbell 指出特定版本的软件发布生命期中一个有趣的循环

起初,上一个版本中被发现和修复的 bug,在新的版本中仍会出现。新版本中的新功能会产生新的 bug。

解决了这些问题之后,程序会正常运行几个月。接着,错误率会重新攀升。Campbell 认为这是因为用户的使用到达了新的熟练水平,他们开始运用新的功能。这种高强度的考验查出了新功能中很多不易察觉的问题。

 

    程序维护中的一个基本问题是—缺陷修复总会以(20-50)%的几率引入新的bug。所以整个过程是前进两步,后退一步。

为什么缺陷不能更彻底地被修复?

首先,看上去很轻微的错误,似乎仅仅是局部操作上的失败,实际上却是系统级别的问题,通常这不是很明显。修复局部问题的工作量很清晰,并且往往不大。但是,更大范围的修复工作常常会被忽视,除非软件结构很简单,或者文档书写得非常详细。其次,维护人员常常不是编写代码的开发人员,而是一些初级程序员或者新手。

作为引入新 bug 的一个后果,程序每条语句的维护需要的系统测试比其他编程要多。理论上,在每次修复之后,必须重新运行先前所有的测试用例,从而确保系统不会以更隐蔽的方式被破坏。实际情况中,回归测试必须接近上述理想状况,所以它的成本非常高。

显然,使用能消除、至少是能指明副作用的程序设计方法,会在维护成本上有很大的回报。同样,设计实现的人员越少、接口越少,产生的错误也就越少。

Part 6 前进一步,后退一步

Lehman 和 Belady 研究了大型操作系统的一系列发布版本的历史。他们发现模块数量随版本号的增加呈线性增长,但是受到影响的模块以版本号指数的级别增长。所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。用在修复原有设计上瑕疵的工作量越来越少,而早期维护活动本身的漏洞所引起修复工作越来越多。随着时间的推移,系统变得越来越无序,修复工作迟早会失去根基。每一步前进都伴随着一步后退。尽管理论上系统一直可用,但实际上,整个系统已经面目全非,无法再成为下一步进展的基础。而且,机器在变化,配置在变化,用户的需求在变化,所以现实系统不可能永远可用。崭新的、基于原有系统的重新设计是完全必要的

    系统软件开发是减少混乱度(减少熵)的过程,所以它本身是处于亚稳态的。软件维护是提高混乱度(增加熵)的过程,即使是最熟练的软件维护工作,也只是放缓了系统退化到非稳态的进程。

作者总结

11.1 化学工程师已经认识到无法一步将实验室工作台上的反应过程移到工厂中,需要一个实验性工厂(pilot planet)来为提高产量和在缺乏保护的环境下运作提供宝贵经验。

11.2 对于编程产品而言,这样的中间步骤是同样必要的,但是软件工程师在着手发布产品之前,却并不会常规地进行试验性系统的现场测试。[现在,这已经成为了一项普遍的实践,beta 版本。它不同于有限功能的原型,alpha 版本,后者同样是我所倡导的实践。]

11.3 对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之。

11.4 系统的丢弃和重新设计可以一步完成,也可以一块块地实现。这是个必须完成的步骤。

11.5 将开发的第一个系统——丢弃原型——发布给用户,可以获得时间,但是它的代价高昂——对于用户,使用极度痛苦;对于重新开发的人员,分散了精力;对于产品,影响了声誉,即使最好的再设计也难以挽回名声。

11.6 因此,为舍弃而计划,无论如何,你一定要这样做。

11.7 开发人员交付的是用户满意程度,而不仅仅是实际的产品。

11.8 用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化。

11.9 软件产品易于掌握的特性和不可见性,导致了它的构建人员(特别容易)面临着永恒的需求变更。

11.10 目标上(和开发策略上)的一些正常变化无可避免,事先为它们做准备总比假设它们不会出现要好得多。

11.11 为变更计划软件产品的技术,特别是细致的模块接口文档——非常地广为人知,但并没有相同规模的实践。尽可能地使用表驱动技术同样是有所帮助的。[现在内存的成本和规模使这项技术越来越出众。]

11.12 高级语言的使用、编译时操作、通过引用的声明整合和自文档技术能减少变更引起的错误。

11.13 采用定义良好的数字化版本将变更量子(阶段)化。[当今的标准实践。]

为变更计划组织架构

11.14 程序员不愿意为设计书写文档的原因,不仅仅是由于惰性。更多的是源于设计人员的踌躇——要为自己尝试性的设计决策进行辩解。

11.15 为变更组建团队比为变更进行设计更加困难。

11.16 只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性;特别是希望能在技术和管理角色之间自由地分配人手的时候。

11.17 具有两条晋升线的高效组织机构,存在着一些社会性的障碍,人们必须警惕和积极地同它做持续的斗争。

11.18 很容易为不同的晋升线建立相互一致的薪水级别,但要同等威信的建立需要一些强烈的心理措施:相同的办公室、一样的支持和技术调动的优先补偿。

11.19 组建外科手术队伍式的软件开发团队是对上述问题所有方面的彻底冲击。对于灵活组织架构问题,这的确是一个长期行之有效的解决方案。

前进两步,后退一步——程序维护

11.20 程序维护基本上不同于硬件的维护;它主要由各种变更组成,如修复设计缺陷、新增功能、或者是使用环境或者配置变换引起的调整。

11.21 对于一个广泛使用的程序,其维护总成本通常是开发成本的 40%或更多。

11.22 维护成本受用户数目的严重影响。用户越多,所发现的错误也越多。

11.23 Campbell 指出了一个显示产品生命期中每月 bug 数的有趣曲线,它先是下降,然后攀升。

11.24 缺陷修复总会以(20-50) %的机率引入新的 bug。

11.25 在每次修复之后,必须重新运行先前所有的测试用例,从而确保系统不会以更隐蔽的方式被破坏。

11.26 能消除、至少是能指明副作用的程序设计方法,对维护成本有很大的影响。

11.27 同样,设计实现的人员越少、接口越少,产生的错误也就越少。

前进一步,后退一步——系统熵随时间增加

11.28 Lehman 和 Belady 发现模块数量随大型操作系统(OS/360)版本号的增加呈线性增长,但是受到影响的模块以版本号指数的级别增长。

11.29 所有修改都倾向于破坏系统的架构,增加了系统的混乱程度。即使是最熟练的软件维护工作,也只是放缓了系统退化到不可修复混乱的进程,从中必须要重新进行设计。[许多程序升级的真正需要,如性能等,尤其会冲击它的内部结构边界。原有边界引发的不足常常在日后才会出现。]

第12章 干将莫邪

① 每个骨干人员都仔细地保管自己工作生涯中搜集的一套工具集,保留着编辑器、排序、内存信息转储、磁盘实用程序等工具。

② 这种方法对软件项目来说是愚蠢的。首先,项目的关键问题是沟通,个性化的工具妨碍沟通

(1)开发和维护公共的通用编程工具的效率更高。

(2)专业需要和个人偏好同样需要很多专业工具。建议为每个团队配备一名工具管理人员。这个角色管理所有通用工具,能指导他的客户、老板使用工具。还能编制老板需要的专业工具。

(3)项目经理应该制订一套策略,并为通用工具的开发分配资源,意识到专业工具的需求。

(4)项目经理必须考虑、计划、组织的工具到底有哪些。(首先是计算机设施。它需要硬件和使用安排策略;它需要操作系统,提供服务的方式必须明了;它需要语言,语言的使用方针必须明确;然后是实用程序、调试辅助程序、测试用例生成工具和处理文档的字处理系统。)

Part 1 目标机器

机器支持可以有效地划分成目标机器和辅助机器。目标机器是软件所服务的对象, 程序必须在该机器上进行最后测试辅助机器是那些在开发系统中提供服务的机器

(1) 目标机器的类型有哪些?

目标机器系统会需要若干操作员一两个系统编程人员,以保证机器上的标准支持是即时更新和实时可用的。

② 运行速度不必非常快,但大容量内存很重要,可以进行进程覆盖和功能测试之后的剪裁工作,从而极大地提高生产率。

配备调试机器或者软件。在调试过程中,所有类型的程序参数可以被自动计数和测量。例如,内存使用模式是非常强大的诊断措施,能查出程序中不可思议的行为或者性能意外下降的原因。

(2) 进度安排

当目标机器刚刚被研制,或者当它的第一个操作系统被开发时,机器时间是非常匮乏的,时间的调度安排成了主要问题

解决方法:把机器时间分配成连续的块。(例如,整个从事排序工作的 15 人小组,会得到系统 4 至 6 小时的使用时间块,由他们自己决定如何使用。即使没有安排,其他人也不能使用机器资源。)

实际效果:尽管机器的利用程度可能会有些降低(常常不是这样),生产率却提高了。

实际安排:上述小组中的每个人,6 小时中连续 10 次操作的生产率,比间隔 3小时的 10次操作要高许多,因为持续的精力集中能减少思考时间。在这样的冲刺之后,提出下一个时间块要求之前,小组通常需要一到两天的时间来从事书面文档工作。并且,通常3人左右的小组能卓有成效地安排和共享时间块。在调试新操作系统时,这似乎是一种使用目标机器的最好方法。

Part 2 辅助机器和数据服务

仿真装置

    如果目标机器是新产品,则需要一个目标机器的逻辑仿真装置。这样,在生产出新机器之前,就有辅助的调试平台可供使用。同样重要的是—即使在新机器出现之后,仿真装置仍然可以提供可靠的调试平台

可靠并不等于精确。在某些方面,仿真机器肯定无法精确地达到与新型机器一致的实现。如果有新机器,还是尽早换用新机器。

编译器和汇编平台

    出于同样的原因,编译器和汇编软件需要运行在可靠的辅助平台上,为目标机器编译目标代码。接着,可以在仿真器上立刻开始后续的调试。高级语言的编程开发中,在目标机器上开始全面测试目标代码之前,编译器可以在辅助机器上完成很多目标代码的调试和测试工作。这为直接运行提供了支持,而不仅仅是稳定机器上的仿真结果。

程序库和管理

    在 OS/360 开发中,一个非常成功的重要辅助机器应用是维护程序库。该系统由 W. R. Crowley 带领开发,连接两台 7010 机器,共享一个很大的磁盘数据库。7010同时还提供 System/360 汇编程序。所有经过测试或者正在测试的代码都保存在该库中,包括源代码和汇编装载模块。这个库实际上划分成不同访问规则下的子库。

    首先,每个组或者编程人员分配了一个区域,用来存放他的程序拷贝、测试用例以及单元测试需要的测试辅助例程和数据。在这个开发库(playpen)中,不存在任何限制开发人员的规定。他可以自由处置自己的程序,他是它们的拥有者。

当开发人员准备将软件单元集成到更大的部分时,他向集成经理提交一份拷贝,后者将拷贝放置在系统集成子库中。此时,原作者不可以再改变代码,除非得到了集成经理的批准。当系统合并在一起时,集成经理开始进行所有的系统测试工作,识别和修补 bug。

    有时,系统的一个版本可能会被广泛应用,它被提升到当前版本子库。此时,这个拷贝是不可更改的, 除非有重大缺陷。该版本可以用于所有新模块的集成和测试。7010 上的一个程序目录对每个模块的每个版本进行跟踪,包括它的状态、用途和变更。

    这有两个重要的理念。首先是受控,即程序的拷贝属于经理,他可以独立地授权程序的变更。其次是使发布的进展变得正式,以及开发库(playpen)与集成、发布的正式分离。

    在我看来,这是 OS/360 工作中最优秀的成果之一。它实际上是管理技术的一部分,很多大型的项目都独立地发展了这些技术,包括 Bell 试验室、ICL、剑桥大学等。它同样适用于文档,是一种不可缺少的技术。

编程工具

    随着调试技术的出现,旧方法的使用减少了,但并没有消失。因此,还是需要内存转储、源文件编辑、快照转储、甚至跟踪等工具。

    与之类似,一整套实用程序同样是必要的,用来实现磁带走带、拷贝磁盘、打印文件、更改目录等工作。如果一开始就任命了项目的工具操作和维护人员,那么这些工作可以一次完成,并且随时处在待命状态。

文档系统

    通过两种途径作出了反应。首先,OS/360 的文档规模是不可避免的,需要制订仔细的阅读计划。如果选择性地阅读,则可以忽略大部分内容和省下大量时间。人们必须把 OS/360 的文档看成是图书馆或者百科全书,而不是一系列强制阅读的文章。

    第二,它比那些刻画了大多数编程系统特性的短篇文档更加可取。不过,我也承认,手册仍有某些需要大量改进的地方, 经改进后文档篇幅会大大减少。

性能仿真装置

最好有一个。正如我们将在下章讨论到的,彻底地开发一个。使用相同的自顶向下设计方法,来实现性能仿真器、逻辑仿真装置和产品。尽可能早地开始这项工作,仔细地听取“它们表达的意见”。

Part 3 高级语言和交互式编程

    ① 高级语言

(1)主要原因:生产率和调试速度。编译器的诊断机制可以帮助找出这些类似的错误。

(2)工具的传统反对意见:它无法完成我想做的事情;目标代码过于庞大;目标代码运行速度过慢。

功能而言,需要花费时间和精力找出如何做。

空间而言,新的优化编译器已非常令人满意,并且将持续地改进。

速度而言,经优化编译器生成的代码,比绝大多数程序员手写代码的效率要高。而且,在前者被全面测试之后,可以将其中的百分之一至五替换成手写的代码,这往往能解决速度方面的问题。

    ② 交互式编程

(1)多个级别上数据和程序的共享和保护,可延伸的库管理,以及协助终端用户共同开发的设施。

(2)调试是系统编程中很慢和较困难的部分,而漫长的调试周转时间是调试的祸根。

作者总结

12.1 项目经理应该制订一套策略,以及为通用工具的开发分配资源,与此同时,他还必须意识到专业工具的需求。

12.2 开发操作系统的队伍需要自己的目标机器,进行调试开发工作。相对于最快的速度而言,它更需要最大限度的内存,还需要安排一名系统程序员,以保证机器上的标准软件是即时更新和实时可用的。

12.3 同时还需要配备调试机器或者软件,以便在调试过程中,所有类型的程序参数可以被自动计数和测量。

12.4 目标机器的使用需求量是一种特殊曲线:刚开始使用率非常低,突然出现爆发性的增长,接着趋于平缓。

12.5 同天文工作者一样,系统调试总是大部分在夜间完成。

12.6 抛开理论不谈,一次分配给某个小组连续的目标时间块被证明是最好的安排方法,比不同小组的穿插使用更为有效。

12.7 尽管技术不断变化,这种采用时间块来安排匮乏计算机资源的方式仍得以延续20 年[在 1975 年],是因为它的生产率最高。[在 1995 年依然如此]

12.8 如果目标机器是新产品,则需要一个目标机器的逻辑仿真装置。这样,可以更快地得到辅助调试平台。即使在真正机器出现之后,仿真装置仍可提供可靠的调试平台。

12.9 主程序库应该被划分成(1)一系列独立的私有开发库;(2)正处在系统测试下的系统集成子库;(3)发布版本。正式的分离和进度提供了控制。

12.10 在编制程序的项目中,节省最大工作量的工具可能是文本编辑系统。

12.11 系统文档中的巨大容量带来了新的不理解问题,但是它比大多数未能详细描述编程系统特性的短小文章更加可取。

12.12 自顶向下、彻底地开发一个性能仿真装置。尽可能早地开始这项工作,仔细地听取 “它们表达的意见”。

高级语言

12.13 只有懒散和惰性会妨碍高级语言和交互式编程的广泛应用。[如今它们已经在全世界使用。]

12.14 高级语言不仅仅提升了生产率,而且还改进了调试:bug 更少,以及更容易寻找。

12.15 传统的反对意见——功能、目标代码的尺寸、目标代码的速度,随着语言和编译器技术的进步已不再成为问题。

12.16 现在可供合理选择的语言是 PL/I。 [不再正确]

交互式编程

12.17 某些应用上,批处理系统决不会被交互式系统所替代。 [依然成立]

12.18 调试是系统编程中很慢和较困难的部分,而漫长的调试周转时间是调试的祸根。

12.19 有限的数据表明了系统软件开发中,交互式编程的生产率至少是原来的两倍。

第13章 整体部分

① 如何开发一个可以运行的系统?如何测试系统?

② 如何将经过测试的一系列构件集成到已测试过、 可以依赖的系统?

Part 1 剔除bug的设计

① 产品的概念完整性在使它易于使用的同时, 也使开发更容易进行以及 bug 更不容易产生。

② 细致的功能定义、详细的规格说明、 规范化的功能描述说明以及这些方法的实施,大大减少了系统中必须查找的 bug 数量。

测试规格说明:规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。

自顶向下的设计:将程序开发划分成体系结构设计、 设计实现和物理编码实现, 每个步骤可以使用自顶向下的方法很好地实现。

精化步骤:开始是勾画出能得到主要结果的,但比较粗略的任务定义和大概的解决方案。然后,对该定义和方案进行细致的检查, 以判断结果与期望之间的差距。同时,将上述步骤的解决方案,在更细的步骤中进行分解,每一项任务定义的精化变成了解决方案中算法的精化,后者还可能伴随着数据表达方式的精化。

⑥ 当识别出解决方案或者数据的模块时,对这些模块的进一步细化可以和其他的工作独立,而模块的大小程度决定了程序的适用性和可变化的程度。

⑦ 在每个步骤中,尽可能使用级别较高的表达方法来表现概念和隐藏细节,除非有必要进行进一步的细化。

⑧ 好的自顶向下设计从几个方面避免了bug。

  1. 清晰的结构和表达方式更容易对需求和模块功能进行精确的描述。
  2. 模块分割和模块独立性避免了系统级的bug。
  3. 细节的隐藏使结构上的缺陷更加容易识别。
  4. 设计在每个精化步骤的层次上是可以测试的,所以测试可以尽早开始,并且每个步骤的重点可以放在合适的级别上。

⑨ 结构化编程:该方法所设计程序的控制结构,仅包含语句形式的循环结构,例如 DO WHILE,以及 IF...THEN...ELSE 的条件判断结构,而具体的条件部分在 IF...THEN...ELSE 后的花括号中描述。

Part 2 构件单元调试

整个调试过程有四个步骤,跟随这个过程来检验每个步骤各自的动机是一件很有趣的事情。

① 本机调试 :把程序划分成测试段,并对执行终止位置进行计划。

② 内存转储 :某人持续地运行程序,直到某个检测失败,这时所有的内存都被转储。整个过程的设计是为了减少计算机的使用时间,从而尽可能满足更多的编程用户。

③ 快照 :随着内存的规模不断增长,对整个内存都进行转储变得不大可能。因此,人们开发了有选择的转储、选择性跟踪和将快照插入程序的技术。

④ 交互式调试 :提出了一种兼有本机调试方式实时性和批处理调试高效使用率的方法。

⑤ 测试用例 :关于实际调试过程和测试用例的设计。

Part 3 系统集成调试

完备系统化和可计划的方法。

 ① 使用经过调试的构件单元

 ② 搭建充分的测试平台

a.伪构件(dummy component),它仅仅由接口和可能的伪数据或者一些小的测试用例组成。例如,系统包含某种排序程序,但该程序还未完成,这时其他部分的测试可以通过伪构件来实现,该构件读入输入数据,对数据格式进行校验,输出格式良好、但没有实际意义的有序数据以供使用。

b.微缩文件,创建一个仅包含典型记录,但涵盖全部描述的小型文件是非常值得的。

c.伪文件

d.辅助程序

③ 控制变更

a.存在系统的受控拷贝:一个是供构件单元测试使用的最终锁定版本;一个是测试版本的拷贝,用来进行缺陷的修复; 以及一个安全版本,其他人员可以在该拷贝上工作,进行各自的程序开发工作,例如修复和扩展自己的模块和子系统等。

b.技巧的关键因素是对变更和差异的记载,即在一个日志中记录所有的变更,而在源代码中显著标记快速补丁和正式修改之间的区别,正式修改是完备并经过测试的,而且需要文档化。

④ 一次添加一个构件

注意必须拥有完整的测试用例,在添加了新构件之后,用它们来测试子系统。

⑤ 阶段(量子)化、定期变更

将使用中的构件替换成新版本,仍然需要进行和构件添加一样的系统化测试流程。

量子(阶段)化变更方法非常优美地容纳了紫色线束技术:直到下一次系统构件的定期发布之前,都一直使用快速补丁;而在当前的发布中,把已经通过测试并进行了文档化的修补措施整合到系统平台。

作者总结

13.1 第 4、 5、 6 章所意味的煞费苦心、 详尽体系结构工作不但使产品更加易于使用,而且使开发更容易进行以及 bug 更不容易产生。

13.2 V.A.Vyssotsky 提出,许许多多的失败完全源于那些产品未精确定义的地方。

13.3 在编写任何代码之前,规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。开发人员自己不会完成这项工作。(Vyssotsky)

13.4 十年内[1965~1975], Wirth 的自顶向下进行设计[逐步细化]将会是最重要的新型形式化软件开发方法。

13.5 Wirth 主张在每个步骤中,尽可能使用级别较高的表达方法。

13.6 好的自顶向下设计从四个方面避免了 bug。

13.7 有时必须回退,推翻顶层设计,重新开始。

13.8 结构化编程中,程序的控制结构仅由支配代码块(相对于任意的跳转)的给定集合所组成。这种方法出色地避免了 bug,是一种正确的思考方式。

13.9 Gold 结果显示了,在交互式调试过程中,第一次交互取得的工作进展是后续交互的三倍。这实际上获益于在调试开始之前仔细地调试计划。[我认为在 1995 年依然如此]

13.10 我发现对良好终端系统的正确使用, 往往要求每两小时的终端会话对应于两小时的桌面工作: 1 小时会话后的清理和文档工作; 1 小时为下一次计划变更和测试。

13.11 系统调试(相对于单元测试)花费的时间会比预料的更长。

13.12 系统调试的困难程度证明了需要一种完备系统化和可计划的方法。

13.13 系统调试仅仅应该在所有部件能够运作之后开始。(这既不同于为了查出接口bug 所采取 “合在一起尝试” 的方法;也不同于在所有构件单元的 bug 已知,但未修复的情况下,即开始系统调试的做法。)[对于多个团队尤其如此]

13.14 开发大量的辅助调试平台(scaffolding 脚手架)和测试代码是很值得的,代码量甚至可能会有测试对象的一半。

13.15 必须有人对变更进行控制和文档化,团队成员应使用开发库的各种受控拷贝来工作。

13.16 系统测试期间,一次只添加一个构件。

13.17 Lehman 和 Belady 出示了证据,变更的阶段(量子)要么很大,间隔很宽;要么小和频繁。后者很容易变得不稳定。[Microsoft 的一个团队使用了非常小的阶段(量子)。结果是每天晚上需要重新编译生成增长中的系统。]

本文标签: 人月神话(五)未雨绸缪干将莫邪整体部分