Skip to content

人月神话

一. 焦油坑——重新认识职业

故事

  • 过去几十年的大型系统开发就犹如一个焦油坑,很多大型和强壮的动物在其中剧烈地挣扎。
  • 他们中大多数开发出了可运行的系统——不过只有极少数的项目满足了目标、进度和预算的要求。各种团队,大型的或小型的,庞杂的或精干的,一个接一个地淹没在了焦油坑中。
  • 表面上看起来 好像没有任何一个单独的问题会导致困难,每个问题都能获得解决,但是当它们相互纠缠和累积在一起的时候,团队的行动就会变得越来越慢。

职业的乐趣

  • 首先,一种创建事物的纯粹快乐。
  • 其次,来自于开发对他人有用的东西。劳动成果能够被他人使用,并能对他们有所帮助。
  • 第三,将相互啮合的零部件组装在一起,让以精妙的方式运行着,并收到了预期的效果。
  • 第四,持续学习的快乐,来自于这项工作的 非重复特性
  • 最后,来自于在 易于驾驭的介质 上工作。很少有这样的介质——创造的方式如此得灵活,如此得易于精炼和重建,如此得容易实现概念上的设想。

职业的苦恼

  • 首先,苦恼来自追求完美。
  • 其次,由其他人来设定目标,并且必须依靠自己无法控制的事物(特别是程序);权威不等同于责任。
  • 第三,概念设计是有趣的,但 寻找琐碎的bug 却是一项 重复性 的活动。
  • 最后,产品在即将完成时总面临着陈旧过时的威胁。因为产品开发所基于的技术在不断的进步。
  • 此外,人们通常期望项目在接近结束时,能收敛得快一些,然而软件项目的情况却是 越接近完成,收敛得越慢

二. 人月神话——不合理的进度安排

乐观主义

  • 进度安排背后第一个错误的假设是:一切都运作良好,每一项任务仅花费他所「应该」花费的时间。
  • 编程人员的介质比较容易掌握,所以期待在实现过程中不会碰到困难。

人月的关系是复杂的

  • 第二个谬误的思考方式是:在估计和进度安排中使用的工作量单位:人月。暗示着:人员数量和时间是可以相互替换的
  • 人月 作为衡量一项工作的规模是一个 危险 和带有 欺骗性的神话
  • 用人月来衡量工作是非常危险的,因为它建立在 他们之间不需要相互交流的前提下。比如,收割小麦或收获棉花。
  • 因为软件开发本质上是一项系统工作 --- 错综复杂关系下的一种实践,沟通、交流的工作量非常大,它很快会消耗任务分解所节省下来的个人时间。
  • 在错综复杂的任务中,沟通和交流的工作量非常大;从而,添加更多的人手,实际上是延长了而不是缩短了时间进度。

忽略测试的重要性

  • 由于乐观主义,软件出现bug的数量比我们预料的多得多。
  • 推荐的任务安排比例:⅓ 计划 、⅙ 编码 、¼ 持续单元/集成测试 、¼ 最后完整系统测试。
  • 开发进度的失控:前期不仔细思考方案和确定需求,后期频繁变化导致时间不够,为了赶进度又压缩测试空间,最后质量不高又要加班修改。

进度落后的错误处理

  • 不要进度一落后,就想着加人;
  • 项目经理应该仔细调整项目,重新安排任务,或者剪除造成落后的任务。
  • Brooks法则:“向进度落后的项目中增加人手,只会使进度更加落后。”

三. 外科手术队伍——如何构建项目团队

背景

  • 对一组有经验的程序人员进行测量:在该小组中,最好的和最差的表现在生产率上平均为 10:1;在运行速度和空间上具有 5:1 的惊人差异!

外科手术团队组成

  • 面对大型项目开发,如果组建少数精干团队,沟通成本低,但是开发周期长;如果组建大型团队,组织沟通难。
  • 技术

    • 架构师,即外科医生。定义功能,设计程序,书写文档,需要天赋、经验和系统知识。
    • 评估员。来评估设计,相比于架构师来说经验会少一点。
    • 专家。对某些领域有很深的研究,协助解决棘手问题
    • 文档维护者。统一维护项目的文档和工具
    • 程序员。负责功能的具体实现
    • 测试。负责测试用例、搭建测试平台、日常测试
  • 管理

    • Boss。在管理上有决定权
    • 文秘。负责协助Boss的事务落实

小结

  • 对于真正意义上的大型系统,小型精干的队伍太慢了。
  • 一拥而上的开发方法是高成本、速度缓慢、不充分的, 开发出的产品无法进行概念上的集成
  • 一位首席程序员、类似于外科手术队伍的团队架构提供了一种方法——既能获得由少数头脑产生的产品完整性,又能得到多位协助人员的总体生产率,还彻底地减少了沟通的工作量。
  • 推崇由少数人思考确定系统的方向,多数人来解决实际实现问题。并且需要对开发人员进行专业化分工,来减少成员的交流成本,提高工作的效率。
  • 当我们需要扩建团队规模时,需要调整人数比例,减少决定设计的人员,增多开发实现的人员,保持整个系统设计概念的完整性。并且清晰划分体系结构设计实现的界限,让工作易于管理,提高效率。

四. 贵族专制、民主政治——保证系统概念的完整性

概念完整

  • 在系统设计中,概念完整性(Conceptual Integrity)应该是最重要的考虑因素。
  • 不提倡独立和无法整合的系统, 哪怕它们其实包含着许多很好的设计。

获得概念的完整性

  • 由于目标是 易用性功能概念复杂度比(功能与理解上复杂程度的比值)才是系统设计的最终测试标准。功能多,不见得是好事。
  • 每个部分必须反映相同的原理、原则和一致的折衷机制。在语法上, 每个部分应使用相同的技巧;在语义上,应具有同样的相似性。
  • 因此,易用性实际上需要设计的一致性概念上的完整性

贵族专制统治和民主政治

  • 概念的完整性要求设计必须由一个人,或者非常少数互有默契的人员来实现。
  • 解决多人开发系统矛盾:

    • 第一种是仔细地区分设计方法具体实现。对于非常大型的项目,将设计方法、体系结构方面的工作与具体实现相分离是获得概念完整性的强有力方法。
    • 第二种是组建编程开发团队:外科手术队伍。
  • 如果系统必须保有概念上的整体性,那么就必须有人来控制这些概念,这就是 需要专制的原因,无庸置疑,无需致歉。

五. 画蛇添足——约束设计

架构师的交互准则和机制

  • 想要成功,架构师必须:
  • 1、记是开发人员承担创造性和发明性的实现责任,所以结构师只能建议,而不能支配。
  • 2、时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目 标的方法。
  • 3、对上述的建议保持低调和平静。
  • 4、准备放弃坚持所作的改进建议。

自律——第二系统效应

  • 在开发第一个系统时,架构师倾向于精炼和简洁,同时面对不断产生的装饰和润色功能。
  • 第一个项目迟早会结束,而此时的架构师,对这类系统充满了十足的信心,熟练掌握了相应的知识,并且时刻准备开发第二个系统。 第二个系统是设计师们所设计的最危险的系统。
  • 一种普遍倾向是,过分地设计第二个系统。 向系统添加很多修饰功能和想法,它们曾在第一个系统中被小心谨慎地推迟了。

结构师如何避免画蛇添足

  • 根据系统基本理念及目的变更,舍弃一些功能。
  • 一个可以开阔结构师眼界的准则是为每个小功能分配一个值:每次改进,功能 x 不超 过 m 字节的内存和 n 微秒。
  • 尊重有两个以上系统经验的架构师的决定,并警惕特殊诱惑。

六. 贯彻执行

问题

  • 对于一个由 1000 人开发的系统,一个 10 个结构师的小组如何保持系统概念上的完整性?

文档化的规格说明——手册

  • 手册、或者书面规格说明,是一个非常必要的工具,尽管光有文档是不够的。手册是产品的外部规格说明,它描述和规定了用户所见的每一个细节;同样的,它也是结构师主要的工作产物。
  • 规格说明的风格必须清晰、完整和准确。
  • 手册读起来枯燥乏味, 但是精确比生动更加重要

会议和大会

  • 会议分成两个级别:周例会年度大会
  • 周例会每周半天,由架构师主持,实施和市场人员参与。 重点是创新,而不仅仅是结论。
  • 年度会每半年一次,用于解决周例会遗留堆积的问题。

产品测试

  • 该小组根据规格说明检查机器和程序,充当麻烦的代言人,查明每一个可能的缺陷和相互矛盾的地方。
  • 每个开发机构都需要这样一个独立的技术监督部门,来保证其公正性。

七. 为什么巴比伦塔会失败——交流和组织

问题

  • 巴比伦塔是人类第二大工程壮举,同时也是记载的第一个彻底失败的工程。(当上帝消除了统一的语言)它拥有清晰的目标、充足的人力、丰富的材料、足够的时间和技术,为什么会失败呢?

原因

  • 两个方面:交流,以及交流的结果—— 组织
  • 交流方面:交流的缺乏导致了争辩、沮丧和群体猜忌。
  • 组织方面:很快,部落开始分裂——大家选择了孤立,而不是互相争吵。

如何进行交流沟通

  • 非正式途径。电话、面基,快速解决问题
  • 会议。定期常规性会议,按时同步进度和问题
  • 工作手册。用于共享的大型项目

大型项目的组织架构

  • 如果项目有 n 个工作人员,则有(n^2 - n)/ 2 个相互交流的接口,有将近 2 n 个必须合作的潜在团队。
  • 团队组织的目标:是为了 减少必要的交流和协作量。从组织结构上可以从人力划分限定职责范围来实现。
  • 事实上,树状组织架构是作为权力和责任的结构出现。其基本原理——管理角色的非重复性——导致了管理结构是树状的。
  • 组织交流是网形,而不是树形。
  • 领导角色可以是产品负责人技术负责人的灵活组合,具体看是资源进度为主还是技术设计为主。
  • 产品负责人的角色是什么? 他组建团队,划分工作及制订进度表。他要求,并一直要 求必要的资源。这意味着他主要的工作是与团队外部,向上和水平地沟通。他建立团队内部 的沟通和报告方式。最后,他确保进度目标的实现,根据环境的变化调整资源和团队的构架。
  • 那么技术主管的角色是什么? 他对设计进行构思,识别系统的子部分,指明从外部看 上去的样子,勾画它的内部结构。他提供整个设计的一致性和概念完整性;他控制系统的复 杂程度。当某个技术问题出现时,他提供问题的解决方案,或者根据需要调整系统设计。
  • 1、产品负责人和技术主管是同一个人

    • 第一,同时具有 管理技能和技术技能的人很难找到。
    • 第二,大型项目中,每个角色都必须全职工作。对负责人来说,很难在承担全部管理责任的同时,还能抽出时间进行技术工作。对技术主管来说,很难在保证设 计的概念完整性,没有任何妥协的前提下,担任管理工作。
  • 2、产品负责人作为总指挥,技术主管充当其左右手

    • 很难在技术主管不参与任何管理工作的同时,建立在技术决策上的权威。
    • 显然,产品负责人必须预先声明技术主管的技术权威,在即将出现的绝大部分测试用 例中,他必须支持后者的技术决定。要达到这一点,产品责任人和技术主管必须在基本的技 术理论上具有相似观点;他们必须在主要的技术问题出现之前,私下讨论它们;产品责任人必须对技术主管的技术才能表现出尊重。
  • 3、技术主管作为总指挥,产品负责人充当其左右手

八. 胸有成竹——工作效率

前言

  • 「实践是最好的老师。」
  • 「实践是最好的老师,但智者还能从其他的地方有所收获」—— 《穷查理年鉴》

正文

  • 由于外部因素影响,实际工作时间会比预期多。
  • 程序开发工作随着程序的规模增长而增长。
  • 使用适当的高级语言,会提高5倍编程生产率。

九. 削足适履——规模控制

前言

  • 他应该瞪大眼睛紧盯着诺亚,然后……好好学习一下,看他们当时是怎样把那么多东西塞进一个小小的方舟上的。————西德尼-史密斯《爱丁堡评论》

规模控制

  • 规模预算:软件开发人员必须要设置规模目标,控制规模,发明一些减少规模的方法。
  • 团队对各个模块进行局部优化的时候,架构师需要警惕系统完整性是否遭到破坏。

数据的表现形式是编程的根本

  • 精湛的技艺出自创造,精炼、充分和快速的程序也是如此。技艺改进的结果往往是 战略性 的突破,而不仅仅是技巧上的提高。
  • 更普遍的,战略上突破常常来自数据或表的重新表达————这是程序的核心所在。
  • 实际上,数据的表现形式(数据结构)是编程的根本。

十. 提纲挈领——文档

前提

  • “在一片文件的汪洋中,少数文档成为了关键的枢纽,每个项目管理的工作围绕着他们运转。它们是经理们的主要个人工具。”
  • 文档本身可以作为:检查列表状态控制,也可以作为汇报的 数据基础

为什么要有正式的文档?

  • 第一、书面记录决策是必要的。只有记录下来,分歧才会明朗,矛盾才会突出。
  • 第二、文档能够作为同其他人的沟通渠道。
  • 第三、项目经理的文档可以作为数据基础和检查列表。

    • 对每个关键文档的维护提供了状态监督预警机制
    • 每个文档本身就可以作为检查列表(Checklist)或者数据库
    • 项目经理的基本职责是使每个人都向着相同的方向前进。
    • 项目经理的主要日常工作是沟通,而不是作出决定;文档使各项计划和决策在整个团队范围内得到交流

十一. 未雨绸缪——拥抱变化

前言

  • 不变只是愿望,变化才是永恒。—— swift

试验性工厂和增大规模

  • 1、对于大多数项目,第一个开发的系统并不合用。它可能太慢、太大,而且难以使用,或者三者兼而有之:
  • 2、系统的丢弃和重新设计可以一步完成,也可以一块块地实现。所有大型系统的经验都显示,这是必须完成的步骤:
  • 3、为舍弃而计划,无论如何,你一定要这样做:

唯一不变的就是变化本身

  • 1、变化是与生俱来的,不是不合时宜和令人生厌的异常情况:
  • 2、开发人员交付的是用户满意程度,而不仅仅是有形的产品
  • 3、用户的实际需要和用户感觉会随着程序的构建、测试和使用而变化
  • 4、软件产品易于掌握的特性和不可见性,导致它的构建人员面临永恒的需求变更
  • 5、目标上的一些变化无可避免,事先为它们做准备总比假设它们不会出现要好得多

为变更设计系统

  • 1、最重要的措施是使用高级语言自文档技术,以减少变更引起的错误:
  • 2、变更的阶段化是一种必要的技术。每个产品应该有数字版本号,每个版本都应该有自己的日程表和冻结日期。在此之后的变更,都属于一个版本的范畴。

为变更计划组织架构

  • 1、现在软件编程小组失败的主要原因是管理控制的太少,而不是太多:
  • 2.不愿意为设计书写文档的原因,不仅仅是由于惰性或时间压力。相反,设计人员通常不愿意提交尝试性的设计决策,再为它们进行辩解;
  • 3.为变更组建团队比为变更进行设计更加困难:
  • 4.只要管理人员和技术人才的天赋允许,老板必须对他们的能力培养给予极大的关注,使管理人员和技术人才具有互换性:
  • 5,项目目标、进展和管理问题必须在高级人员整体中得到共享

前进两步,后退一步(BugFix不可控)

  • 1.在程序发布给顾客使用之后,并不会停止变化。发布后的变更被称为“程序维护”
  • 2.软件维护主要包含对设计缺陷的修复,通常包含了更多的新增功能,它通常是用户能察觉的
  • 3.对于一个广泛使用的程序,其维护总成本通常是开发成本的40%或更多
  • 4,缺陷修复总会以固定(20%一50%)的几率引入新的BUG。所以,整个过程是前进两步,后退一步
  • 5、每次修复之后,必须重新运行先前所有的测试用例
  • 6、使用能消除或至少能指明副作用的程序设计方法,会在维护成本上有很大的回报:
  • 7、设计实现的人员越少、接口越少,产生的错误也就越少

前进一步,后退一步(迭代不可控)

  • 1、模块总数量随版本号的增加呈线性增长,但是受到影响的模块数量随版本号的增加呈指数增长
  • 2、系统开发是为了减少混乱度(减熵),所以它本身是亚稳态。软件维护和迭代是提高混乱度(增熵)的过程。
  • 3、在迭代是,需要明确目标和设计,减缓系统退化到非稳态的进程

十二. 干将莫邪——通用工具

通用工具

  • 开发和维护公共的通用编程工具,使得项目工作效率更高;通用工具需要专人开发和维护。
  • 项目经理需要重视通用工具的重要性
  • 项目的关键问题是 沟通,个性化的工具 妨碍沟通

高级语言

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

交互式编程

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

十三. 整体部分——整体系统思考

剔除bug的设计

  • 关键的工作是产品定义

    • Vyssotsky 提出∶"关键的工作是产品定义。许许多多的失败完全是因为那些产品未精确定义的地方而导致的。"
    • 细致的功能定义、仔细的规格说明、规范化的功能描述说明以及这些方法的实施,大大减少了系统中必须查找的 bug 数量。
  • 测试规格说明

    • 规格说明必须提交给测试小组,以详细地检查说明的完整性和明确性。
  • 自顶向下的设计

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

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

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

构件单元调试

系统集成调试

十四. 祸起萧墙——如何避免项目延期

前言

  • “项目是怎样被延迟了整整一年时间的......一次一天。”
  • 项目进度经常以一种难以察觉,但是残酷无情的方式慢慢落后。
  • 进度落后是难以识别、不容易防范和难以弥补的。

里程碑还是沉重的负担

  • 1、根据一个严格的进度表来控制大型项目的第一个步骤是制定进度表,进度表由里程碑和日期组成;
  • 2、里程碑的选择只有一个原则。必须是具体的、特定的、可度量的事件,能够进行清晰定义;
  • 3、里程碑边界明显和没有歧义。如果里程碑定义得非常明确,无法自欺欺人时,很少有人会就里程碑的进展弄虚作假;
  • 4、当里程碑没有正确反映损失的时间,并对人们形成误导,迟到事态无法挽回的时候,它会彻底打击小组的士气;
  • 5、慢性进度偏离同样也是士气杀手。

其他的部分反正会落后

  • 1、同优秀的棒球队伍一样,进取对于杰出的软件开发团队是不可缺少的必要品德;
  • 2、进取提供了缓冲和储备,使开发队伍能够处理常规的灾祸,可以预计和防止小的灾祸;
  • 3、必须关心每一天的滞后,它们是大灾祸的基本组成元素;
  • 4、PERT的准备工作是PERT图使用中最有价值的部分。它包括整个网关结构的展开、任务之间依赖关系的识别和各个任务链的估计,这些都要求在项目早期进行非常专业的计划;
  • 5、PERT图为“其他的部分反正会落后”提供了答案。它展示某人为了使自己的工作远离关键路径,需要超前多少,也建议了补偿其他部分失去的时间的方法。

地毯的下面

  • 1、每个老板都需要两种信息:需要采取行动计划方面的问题,用来进行分析的状态数据;
  • 2、一线经理的利益和老板的利益在这里是存在内在冲突的。一线经理担心如果汇报了问题,老板会采取行动.这降低了自己的威信,搞乱其他计划。所以,只要项目经理认为自己可以独立解决问题,他就不会告诉老板;
  • 3、老板必须区别行动信息和状态信息。他必须规范自己,不对项目经理可以解决的问题做出反应,并且决不在检查状态报告的时间做安排;
  • 4、当项目经理了解到老板收到状态报告之后不会惊榄,或者不会越俎代庖时,他就逐渐会提交真实的结果;
  • 5、必须有评审机制,使所有成员可以通过它了解真正的状态。出于这个目的,里程碑的进度和完成文档是关键;
  • 6.项目经理必须停止对团队成员估算日期的怀疑,将重点放在使其更加精确。以便得到没有偏见的估计,而不是那些合乎心意的乐观估计或者自我保护的保守估计。

十五. 另外一面——如何写出良好的文档

用户文档

  • 目的
  • 环境和范围
  • 实现功能和使用的算法
  • 输入/输出格式
  • 指令和选项
  • 运行时间(性能)

流程图

  • 一页纸的流程图,成为表达程序结构、阶段或步骤的一种非常基本的图示。
  • 流程图是被吹捧得最过分的一种程序文档;很少有程序需要一页纸以上的流程图。

自文档化(self-documenting)

  • 合并文件,即把文档整合到源码中。
  • 提高源码可读性
  • 注释
  • 规范项目结构和命名

最小化文档负担的 3 个关键思路

  • 借助那些必须存在的语句,如名称和声明等,来附加尽可能多的“文档”信息。
  • 使用空格和格式来表现从属和嵌套关系,提高程序的可读性。
  • 以段落注释,特别是模块标题的形式,向程序中插入必要的记叙性文字。

十六. 没有银弹——根本和次要任务

介绍

  • 所有编程活动包括

    • 根本任务 —— 打造由抽象软件实体构成的复杂概念结构;
    • 次要任务 —— 使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。
  • 人狼:它们可以完全出乎意料的从熟悉的面孔变成可怕的怪物。为了对付人狼,我们需要银色子弹

  • 软件项目具有人狼特性,常常看 似简单明了的东西,却有可能变成一个落后进度、超出预算、存在大量缺陷的怪物。
  • 布鲁克斯认为,在软件工程中,「没有银弹」:没有任何技术或管理上的进展,能够独立地许诺十年内使生产率可靠性简洁性获得数量级上的进步。
  • 解决管理灾难的第一步是将大块的 「巨无霸理论」替换成 「微生物理论」。 它告诉工作者,进步是逐步取得的,要伴随辛勤的劳动,对规范化过程进行持续不懈的努力,而非一蹴而就的解决方案。

根本困难

  • 效仿亚里士多德把困难分成

    • 根本的 —— 软件特性中固有的困难;
    • 次要的 —— 出现在目前生产上的,但并非那些与生俱来的困难。
  • 一个相互牵制关联的概念结构中,要素是抽象的,体现在不同表现形式下的 概念结构是相同的

  • 软件开发中困难的部分是规格化、设计和测试这些概念上的结构,而不是对概念进行表达和对实现逼真程度进行验证。
  • 现代软件系统中这些无法规避的内在特性:复杂度、一致性、可变性和不可见性。
  • 复杂度

    • 需要强调的是, 软件的复杂度是根本属性,不是次要因素
    • 数学家和物理学家们为复杂的现象建立了简化的模型,从模型中抽取各种特性,并通过实验来验证这些特性。这些方法之所以可行,是因为模型中忽略的复杂度不是被研究现象的根本属性。当复杂度是本质属性时,这些方法就行不通了。
    • 复杂度不仅仅导致技术产生困难,还引发了很多管理上的问题。它使全面理解问题变得困难,从而`妨碍了概念上的完整性`;它使所有离散出口难以寻找和控制;它引起了大量`学习和理解上的负担`,使开发慢慢演变成了一场灾难。
  • 一致性

    • 物理学家坚信,必定存在着某种通用原理,或者在夸克中,或者在统一场论中。爱因斯坦曾不断地重申自然界一定存在着简化的解释,因为上帝不是专横武断或反复无常的。
    • 软件工程师却不具备这种信念,他必须掌握的很多复杂度是随心所欲、毫无规则可言的,来自若干必须遵循的人为惯例和系统;且随时间而变化。
    • 这些变化不是必需的,仅仅由于它们是不同的人—— 而非上帝 —— 设计的结果。
    • 许多情况下,因为是开发最新的软件,它必须遵循各种接口。 另一些情况下,软件的开发目标就是兼容性。 很多复杂性来自保持与其他接口的一致方面,对软件的任何再设计,都无法简化这些复杂特性。
  • 可变性

    • 软件实体之所以持续变更,是因为软件可以 很容易地 进行修改—— 它是纯粹思维活动的产物,可以无限扩展。
    • 建筑有可能发生变化,但众所周知,建筑修改的成本很高,从而打消了那些想提出修改的人的念头。
  • 不可见性

    • 软件是不可见的和无法可视化的。
    • 软件的客观存在不具有空间的形体特征。因此,没有已有的几何表达方式,就像陆地海洋有地图,硅片有膜片图,计算机有电路图一样。
    • 当我们试图用图形来描述软件结构时,发现它不仅仅包含一个,而是很多相互关联、重叠在一起的图形。

以往解决次要困难的一些突破

  • 高级语言
  • 分时
  • 统一编程环境

银弹的希望

  • 高级编程语言:抽象数据类型、层次结构的模块化理念
  • 面向对象编程
  • 人工智能
  • 专家系统
  • “自动”编程
  • 图形化编程

针对概念上根本问题的颇具前途的方法

  • 购买和自行开发

    • 构建软件最可能的彻底解决方案是不开发任何软件。
  • 需求精炼和快速原型

    • 在计划任何软件活动时,要让客户和设计人员之间进行多次广泛的交流沟通,并将其作为系统定义的一部分。
    • 原型的目的是明确实际的概念结构,从而客户可以测试一致性和可用性。
  • 增量开发——增长,而非搭建系统。

    • 首先系统应该能够运行,即使未完成任何有用功能,只能正确调用一系列伪子系统。接着,系统一点一点被充实
  • 卓越的设计人员

    • 卓越与一般之间的差异接近于一个数量级。

十七. 20年后「人月神话」

核心观点:概念完整性和结构师

  • 概念完整性

    • 一个整洁、优雅的编程产品必须向它的每个用户提供一个条理分明的概念模型,这个模型描述了应用、实现应用的方法以及用来指明操作和各种参数的用户界面使用策略。
    • 用户所感受到的产品概念完整性是易用性中最重要的因素。
    • 概念完整性是产品质量的核心。
  • 结构师

    • 负责产品所有方面的概念完整性。
    • 结构师开发用于向用户解释使用的产品概念模型,概念模型包括所有功能的详细说明以及调用和控制的方法。结构师是这些模型的所有者,同时也是用户的代理。
  • 将体系结构和设计实现、物理实现相分离

    • 为了使结构师的关键任务更加可行,有必要将用户所感知的产品定义—体系结构,与它的实现相分离。
  • 体系结构的递归

    • 个人无法完成所有的体系结构工作。有必要由一位主结构师把系统分解成子系统,系统边界应该划分在使子系统间接口最小化和最容易严格定义的地方。

第二个系统效应

开发第二个系统所引起的后果:盲目的功能和频率猜测

  • 盲目的功能

    • 以性能甚至是可用性的代价,过多地向产品添加边界实用功能。
  • 定义用户群

    • 用户群越大和越不确定,就越有必要明确地定义用户群,以获得概念完整性。
    • 他们是谁
    • 他们需要(need)什么
    • 他们认为自己需要(need)什么
    • 他们想要(want)的是什么

瀑布模型是错误的

没有构建舍弃原型——瀑布模型是错误的

  • 瀑布模型的基本谬误是 它假设项目只经历一次过程,而且体系结构出色并易于使用,设计是合理可靠的,随着测试的进行,编码实现是可以修改和调整的。
  • 瀑布模型的第二个谬误是 它假设整个系统一次性地被构建,在所有的设计,大部分编码,部分单元测试完成之后,才为闭环的系统测试合并各个部分。

增量开发模型

增量开发模型更佳——渐进地精化

  • 构建闭环的框架系统
  • 增量式开发和快速原型

人就是一切

或者说,几乎是一切

  • 人件

    • 管理人员的职责不是要人们去工作,而是是 创造工作的可能
  • 放弃权力的力量

    • 通过权力委派,中心的权威实际上是得到了加强;从整体而言,组织机构实际上更加融洽和繁荣
    • 将权力向下委派。这就像是魔术!改进的质量、提高的生产率、高涨的士气。
  • 元编程

再论困难

  • 借亚里斯多德之表达

    • Essence──此为概念上(conceptual)的根本困难。
    • Accidents──此为将概念转换为电脑表示法时﹐在表达(representation)上之困难。
  • 根本性困难

    • 复杂性(complexity)──「复杂」是软体的根本特性﹐可能来自于程式师之间的沟通不良﹐而产生结构错误或时间延误﹔也可能因为人们无法完全掌握程式的各种可能状态﹔也可能来自新增功能时而引发的副作用等等。
    • 一致性(conformity)──大型软体开发中﹐各小系统之介面常会不一致﹐而且易于因时间和环境的演变而更加不一致。
    • 易变性(changability)──软体的所处环境常是由人群、法律、硬体设备及应用领域等各因素融合而成的文化环境﹐这些因素皆会快速变化。
    • 不可见性(invisibility)──软体是看不见的﹐既使利用图示方法﹐也无法充分表现其结构﹐使得人们心智上的沟通面临极大的困难。
  • 可行方案

    • 买来装配(buy and build)──软体的建造尽量使用现有零组件﹐不要一切都从头做起。
    • 快速雏型(rapid prototyping)──使用重复式的开发方法(iterative development)来渐进地改善软体的雏型﹐裨逐步厘清使用者需求。
    • 有机成长(growing organically)──有生命的东西皆是由小慢慢长大的﹐建造大型软体的方法应该是逐渐成长﹐而不是一次建造完成。
    • 优秀设计者(great designer)──人是软体设计的核心﹐良好的方法可改善人的创造过程﹐但无法激励人的原本创造力﹐须藉重有创意的人。