2

“人月神话” 这个词,你知道是什么意思吗?我的第一反应是当面阿姆斯特朗在月球上留下的人类的一大步。然而实质上,这是一本软件工程的经典书籍,它最大的影响是让 “人月” 这个概念传遍整个软件工程行业。

然而,如此经典书籍,完全阅读过的人不多,前段时间笔者陷入了软件项目如何管理好的思考中,于是拿起此书,略读一番,留下本读书笔记,以及自己的感想。

《人月神话》的背景

版本和年代

我看的这本是清华大学出版社的40周年中文纪念版,2022年10月第21次印刷。但事实上需要注意的是,《人月神话》英文原版成书于 1975 年,而清华大学的这一中文版实际上基于 1995 年的 20 周年纪念版英文原版,所以书中的背景、资料、观点,我们应该基于 1995 年的时代大背景之下去考虑。

关于作者

本书的作者是小弗雷德雷克·菲利普斯·“弗雷德”·布鲁克斯(Frederick Phillips "Fred" Brooks, Jr,1931年4月19日—2022年11月17日)。他是一名软件工程师,任职 IBM 时,负责 System/360 的部份设计。《人月神话》一书大量篇幅即是基于他在这个项目中的经验所著。

System/360 和那个时代的计算机

请记住,《人月神话》一书出版于 1975 年,而其20周年纪念版则发布于 1995 年。我们看看这段时间发生了什么事情。

时代背景 1 - 计算机的诞生

国内绝大多数计算机教材中,基本一致认为建造于 1946 年的 ENIAC 是世界上第一台通用电子计算机。从此,电子计算机以其庞大的体积开始为人类服务,这个时候的计算机离 21 世纪人们眼中的个人电脑(PC)还相差甚远,只不过是军队、科研机构才能用得起的庞然大物。

System/360 是 IBM 发表于 1964 年的大型机。如果读者对大型机没有概念,我们可以看看 System/360 的 CPU:

CPU

它的主要成就是,开始创建偏通用的操作系统,它与之后的系列,开始共享 OS/360 这个操作系统,而不是每一个型号专门开发一款操作系统。

1969 年,AT&T 内部开始开发 UNIX。这可以算是第一款跨 CPU 通用操作系统。而 System/360 没赶上这个好时代。

时代背景 2 - 个人电脑出现

按照维基百科的说法,世界公认的第一台个人电脑是 1968 年由惠普发布的 Hewlett-Packard 9011A,然而在这段时间内,PC 的通用化程度远远没有现在高,且不说 PC 高昂的价格,实际上每一台 PC 所能承担的工作能力,基本上也是他们的生产厂家说了算,第三方软件开发者基本为零。

在这段时间内,UNIX 仅仅应用于大型机、服务器等领域,尚未应用于个人电脑。因此这个时候的 PC,从软硬件架构上,还处在上一个世代的水平,只是体积缩小了。

时代背景 3 - PC 操作系统市场的发展

1980 年,以 IBM 推出基于 x86 架构的 PC,并且搭载了微软的 MS-DOS 操作系统为标志,从 1980 年代开始,通用 PC 操作系统开始涌现。在这一阶段中,PC 操作系统依然与其运行的硬件载体相绑定,并且以商业公司在背后作为推手,市场份额开始变得越来越清晰。直到 1995 年,划时代的 Windows 95 推出之前,最引人注目的 PC 系统基本只剩下面两种:

  • x86 搭配微软 Windows 3.x
  • PowerPC 搭配苹果麦金塔系统

1995 年之后

1995 年之后发生的事情太多了,摩尔定律让计算机和互联网以指数速度一路狂飙。从我的从业角度,我就说两点吧:

  • 1991 年,Linux 之父 Linus Torvalds 发布了 Linux 的第一个版本;1994 年,Linux 1.0 正式发布,Red Hat 公司成立。在那个时候,或许没有人能够想到 Linux 以后在云服务领域几乎一统天下,更无法想到 Linux 对计算机系统软硬件设计抽象分层方面作出了多大的贡献。
  • 2006 年,AWS 首次推出弹性计算云服务,云计算逐步深入人心,以至于在现代称为互联网服务的基石。

软硬件的分层,为现代软件工程带来了革命性的变化;云计算的出现,让硬件虚拟化从理论走向工业化的大规模应用。互联网的发展,则让世界各地信息交换变得更加复杂。在这些背景之下,软件工程已经不再是30年前的样子。这些,或许是 1995 年的人们所完全没有意料到的。所以,我们需要以发展的眼光了解成书的理论。


以下请允许我按照书的目录列举一下本人读书过程中觉得重要的内容,以及一些个人笔记吧。下文 粗斜体字 代表书中的原文,剩下的则是我个人的理解和看法。

20 周年纪念版序言

“没有银弹” 被证明是富有煽动性的,它语言 10 年内没有任何编程技巧能够给软件的生产率带来数量级上的提高。10年只剩下一年了,我的预言看来是安全的。

《没有银弹》是作者 弗雷德雷克 在 1986 年发表的一个报告,也被附在了《人月神话》20 周年纪念版中。这个报告对软件工程的未来非常悲观。上面说的 “只剩一年” 指的是 1986 到 1996,距离出版时间 1995 年只剩一年。

现在,“没有银弹” 现在基本上成为一个共识了,准确地说是没有任何解决方法能够确保在软件工程的各个领域完美地解决所有的问题。但是在每一个特定的领域中,各种理论依然层出不穷。

我们要一直牢记心中的是:所有的解决方案都不是万能的,总有各种前置约束、限制条件——或许这也就是中台战略的失败原因吧……


第 1 章 - 焦油坑

本章节中,作者首先从程序员的角度,提出在编程工作中会有什么问题。作者提出了一个 “编程系统产品” 的概念。单个程序员写出来的一个完整的、可运行的产品称为 程序,但是它的用处不大。要将它转换成更有用的东西,有两种途径:

  1. 成为 编程产品(Programming Product):首先,程序要按照一个 普遍认可的风格 编写、有广泛适用性的输入;其次,需要进行广泛的测试,确保它的可靠性;第三,文档

    • 从这个角度来看,我们在 GitHub 上看到的许多受到一定认可的开源库,都可以归类为这一类别。开源库的代码起码要写得让别人能够看得懂、有单测、有文档,这样才能会有足够的认受性
  2. 成为 编程系统(Programming System):准确地说,是成为某一个较大规模的软件项目的一个组成部份,重点在于与系统中的各部分相互协作,输入输出也需要规划,也需要经过可靠的测试

    • 这个主要是偏重程序在整个系统中的构件
    • 书中提到 测试工作将会非常耗时,因此相同功能的编程系统的构建成本至少是独立程序的 3 倍。只能说在现代互联网浪潮下,这个数字或许变得连 1/3 都不到了,这个内容我暂且按下不表吧
  3. 进一步升级,就可以变成 编程系统产品(Programming System Product) 的一部份

    • 比如说记事本之于 Windows

职业的乐趣

编程为什么有趣?作为回报,它的从业者期望得到什么样的快乐?

首先,这种快乐是一种创建事物的纯粹快乐。如同小孩在玩泥巴时感到快乐一样,成年人喜欢创建食物,特别是自己进行设计。……

其次,这种快乐来自于开发对他人有用的东西。内心深处,我们期望我们的劳动成果能够被他人使用,并能对他们有所帮助。……

第三,快乐来自于整个过程体现出的一股强大的魅力——将相互啮合的零部件组装在一起,看到它们以绝妙的方式运行着,并收到了预期的效果。……

第四,这种快乐是持续学习的快乐,……

最后,这种快乐还来自于在易于驾驭的介质上工作。……

本章节首先列出作为一个程序员的快乐在哪里,简单地说,就是基于创造、学习、环境的舒适以及成果的正向反馈。设想一下,如果一个程序员所参与的项目全部失败了,那么 ta 从职业中获得的,或许就没有快乐,只有钱了吧(逃。。

职业的苦恼

首先,苦恼来自追求完美。…… 实际上,我认为,学习编程最困难的部份,是将做事的方式想追求完美的方向调整

其次,苦恼来自由他人设定目标、供给资源和提供信息。……

个人觉得,上面这两条在我们团队的 Code Review 中是很常见的。每个人对于什么样是 “好” 的,看法并不统一。自己认为的完美,在别人眼中是不足或画蛇添足。

对于系统编程人员而言,对其他人的是一件非常痛苦的事情。他依赖他人的程序,而这些程序往往设计得并不合理、实现拙劣、发布不完整(没有源代码或测试用例)或者文档记录得很糟。……

个人觉得这句话更多指的是程序员主观对别人的看法吧,自己想法的永远是最合理的,别人的做法总有问题。如果从这个角度看,这就是一个普遍的情况了。

书中还提到了一些其他的苦恼,包括写代码很有趣,但是 debug 很枯燥;测试出 bug 后要定位修复,导致时间一拖再拖;技术迭代太快,设计方案很快陈旧过时之类的。


第 2 章 - 人月神话

第二章作者则从团队的角度,提出在编程工作中的问题。首先,项目延期都有哪些原因呢?本章节在最前面首先就列举了导致项目延期的多个问题。我下面将每个问题和具体表现放在一块儿讲:

首先,我们对估算技术缺乏有效的研究,更加严肃地说,它反映了一种悄无声息但并不真实的假设——一切都将运行良好。

第二,我们……假设人和月可以互换,错误地将进度与工作量相互混淆。

第三,……通常不会有耐心持续的估算这项工作。

第四,对进度缺少跟踪和监督。……

第五,当意识到进度的偏移时,下意识(以及传统)的反应是增加人力。这就像使用汽油灭火一样,只会使问题更糟。……

乐观主义

程序员们都是 “乐观主义者”,觉得自己完成某项工作、写完某些代码需要花费这么多时间,于是就把这个时间上报,然后项目经理就拿着这个乐观的时间去排期了。这个问题在年轻人中更甚,因为经验不足,而年轻人总是些乐观主义者

我们在编程中,要考虑各种困难,因为 我们构思是有缺陷的,因此总会发现 bug。Bug 的修复以及为此导致的可能更大规模的代码架构的变更,需要时间。此外,多个任务时间的衔接处也可能不顺利,可能还会有预料之外的先后次序问题。从而一切正常的概率变得非常小,甚至接近于零。

人月

本书的主旨很快就引出来了。人月,准确的数学表示应该是 “人·月”,也就是一个人花费一个月的工作量。作者说:用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的

然而极为可悲的是,50年后的今天,我们依然还在迷信这个半个世纪之前就被警告为不靠谱的概念,甚至我们开始使用人日、人时这样更细粒度的单位,给管理者们进一步洗脑。

为什么人月不能简单替换?尽管程序员们有时候经常抱怨这一点,但如果被反问为什么加一个人工期不能减半的时候,却支支吾吾不能回答出来。下一次,请大家直接拿原书的文本来回答就行了,这个回答包含两部份:

  1. 人数和时间的互换仅仅适用于以下情况:……参与人员……他们之间不需要相互的交流……而在系统编程中近乎不可能。 个人觉得这是最重要的一点:多一个人就多一份沟通成本,而成本就是时间,就是工期的增加。
  2. 当任务由于次序上的限制不能分解时,忍受的添加对进度没有帮助。 简单的说就是有些工作是串行的、前后依赖的,对于这种情况,增加人力完全没有任何帮助。

第二个问题无需多言,我们将重点关注在第一点上。这一点本章节从很多方面去阐述问题所在。首先,如果一个任务确实是可以分解的(对于大型工程确实如此),但是我们在分解之后,如果这些任务是由多个人合作参与完成,那么 子任务之间需要相互沟通和交流的任务,必须在计划工作中考虑沟通的工作量。……沟通所增加的负担由两个部份组成:培训和相互的交流。

如果一个项目是个人设计和开发,那么技术方案的沟通成本可以简单视为 0。如果中途加入新的开发者,那么必然需要增加时间成本。按照作者的看法,时间成本分为:

  1. 培训成本:如果加入的开发者,不是熟悉当前系统的代码、架构,那么需要一定的时间对其进行培训。并且需要注意的是,这个时间是原开发者和新加入的开发者两个人都需要付出的。带新员工的导师们应该深有体会
  2. 交流成本:即便新开发者了解当前系统,但是对于一个新需求而言,ta 依然是新人,依然需要与原开发者沟通。

    • 作者提到:如果任务的每个部份必须分别与其他部份单独协作,则工作量按照 n(n-1)/2 递增。在一对一交流的情况下,3 个人的工作量是 2 个人的 3 倍,4 个人的工作量则是 2 个人的 6 倍。 远程沟通的难度更高。
    • 因此,无休止地增加人力,最终会导致总工期比原工期更长。
    • 这也就是为什么,我们在分配任务的时候,尽可能将一个闭环的、内聚的构件分配给同一个开发者的原因,减少沟通的成本。
    • 这也同时是为什么,不同的模块之间推荐使用接口和明确的注释进行沟通,也不应该是你调用我,我也调用你。这也是为了减少模块之间的耦合,明确工作分工。
    • 当然了,最灾难的事情就是项目中途做到一半,完全换一个或者一批人来做。除非万不得已,我们不应该做这样的决策。

系统测试

作者在书中给出了他的经验,排期的时候,按照以下原则分配:

1/3 计划

1/6 编码

1/4 构件测试和早期系统测试

1/4 系统测试,所有的构件已完成

“这是什么神仙公司?”——尽管我很想这么吐槽,但说实话,我们不能以现在的眼光去看待这个经验法则。要知道,作者最主要的项目经验是 System 360,这是一台大型机、是一个需要软硬件强耦合的计算机系统,背后需要几百上千位工程师共同协作。如此复杂的系统,代码占了 1/6 显然是多了。

在我们的团队,当没有 deadline 的时候,大部份情况下测试的耗时是不严格列入排期之内的,只有设计、编码、联调/自测阶段需要进行排期。按照作者的经验,这两个比例为 2:1。

实际上我们参与的系统往往没那么复杂,一般 1:1,甚至是 1:2 也差不多了。我们排期时,有经验的工程师都会加上一个 “系统设计” 的任务卡片。

但是如果我们按照 1:1 甚至仅仅 1:2 来填工时,必然会被外行人质疑,产品 leader 和项目经理肯给你一天设计 + 排期都算老好人了。这就导致了开发开始之后,可能发现设计方案有缺陷、考虑不周等等异常,不得不重新修改方案,导致项目延期。然后,为了赶工期,再加了一个人进来开发。然而按照前面说过的,实际上沟通成本增加,对项目进度没有任何帮助。

空泛的估算

这一小节不长,作者举了一个例子:

……就像约好在两分钟内完成一个煎蛋,看上去可能进行得非常好,但当它无法在两分钟内完成时,顾客只能选择等待或者生吃煎蛋,……

厨师还有其他的选择:他可以把火开大,不过结果常常是无法 “挽救” 的简单——一面已经焦了,而另一面还是生的。

……为了满足顾客期望的日期而造成的不合理的进度安排……

这实际上就是研发排期的最大痛点所在了:当一个突发需求带有未经技术侧评估的 deadline 时,那么从软件工程的角度,从一开始就是失败的,除非这个 deadline 毫无争议地留下了足够的时间 buffer。

就像煎蛋一样,我们只能选择加班(把火开大),这样的后果很可能是放弃产品质量(一面已经焦了),要么就放弃某些功能(另一面还是生的)。

作者提到:在基于可靠的估算出现之前,项目经理需要挺直腰杆,坚持他们的估计。 但是,如果项目经理已经屈膝,程序员要靠什么撑起腰杆呢?如果因为赶工出了线上问题,谁愿意担起这个责任呢?

重复产生的进度灾难

本小节是前文的一个举例总结。在实际的项目进行中挺常见的,这里就不再赘述了。作者在书中简化总结了 Brooks 法则:向进度落后的项目中增加人手,只会使进度更加落后。同时也提到:人员的最大数量依赖于独立子任务的数量;分派大量人力、并且将任务颗粒度划分得非常详细,往往无法得到合理可行的进度安排。

作者认为,缺乏合理的进度安排是造成项目滞后的最主要原因,不过这一点,我个人联系上下文后觉得,这里的 “进度安排” 不仅仅开发进度,也可能是整个产品、策略规划的进度。

这也能解释为什么很多游戏频繁跳票:往往技术只是一方面,产品的设计方向频繁变化也是重要原因之一,这也可以算是广义上的 “进度安排”。


第 3 章 - 外科手术队伍

作者在这一章中,认为 系统应该由尽可能少的人原来开发。但是大型系统太大了,小型队伍的进度太慢。我们要调和这方面的矛盾。

笔者在文章中提出了一个方案,用外科手术的团队作为比喻,其中实际负责架构设计和编程的人只是极少数,其他人都是辅助人员,包括秘书、文档工程师、测试人员。

然而我个人认为,作者提出的这个团队中没有需求提出方(产品人员),实际上并不是一个非常完整的团队。这么冗余的人力分配,在降本增效的互联网大背景下,已无可推进价值。此外,作者也没有提出任何佐证这种团队组成方式的有效性,因此这一章节基本上价值不大。


第 4 章 - 贵族专制、民主政治和系统设计

本章节中,作者提到了 “体系结构” 和 “系统的结构师” 两个概念,但结合上下文以及译文的注释,这里更接近于我们现在所指的 “产品” 和 “需求” 侧的概念,因此 “体系结构” 用现在的概念,应该接近于 “产品框架”。

而 “系统的结构师“ 的概念,对于我司来说,似乎没有能对标的概念。尽管研发侧,有 “技术 owner” 或 “Tech Lead”,作为一个非行政管理、但略高于普通开发工程师的架构级设计师的概念,但是产品(P族)并没有。

笔者认为,针对每一个产品,产品团队应该明确地授权给某一位工程师来担负起这个职责。如果确实没有的话,个人认为产品团队的 leader 应该承担起来。我把承担这个职责的角色称为 “产品负责人” 吧。

贵族专制统治和民主政治

系统的体系结构(产品框架)指的是完整和详细的用户接口说明。其实类比我们的项目,就是详细的需求文档和交付清单。

必须仔细地将体系结构(产品框架)同实现区分开来。如同 Blaauw 所说的,“体系结构陈述的是发生了什么,而实现描述的是如何实现”。也就是说,提需求的时候,要明确产品工程师要什么、实现什么效果,但是具体的实现方案,可以有很多种,这不是需求文档所应该涉及的内容。

本小节的其他内容,由于与我们互联网现行的很多概念很难对上号,所以我作为读者并不太理解。我从中试图提取出来的一些理解(欢迎拍砖)是:

  1. 产品负责人要有自己的想法,而不是用户要什么,就直接做什么。
  2. 需求和创意可以雨后春笋层出不穷,但是作为产品负责人,需要对这些需求进行筛选、整合,对不同基本概念进行合并,在合并后的系统上重新开始
  3. 需求的提出鼓励 “民主”,什么创意都可以提出来。但是具体落地到产品需求中,应该 “专制”,也就是说由少数人掌握能够将电子转化为需求的权限。否则 在毫无限制的实现小组中,在进行结构上的决策时,会出现大量的想法和争议,对具体实现的关注反而会比较少,也就是说,你一句我一句,没有话事人进行收拢,那么产品的方向就定不下来,最终做成什么样子,也没人关心。

在等待时,实现人员应该做什么

本小节说得比较虚,简单而言就是,当需求开始的时候,到需求确认之前,开发团队似乎无所事事。作者提出开发团队在需求阶段,其实也可以开始工作,主要包括一些已经明确要做的需求,其实就可以开启开发和设计了,也可以在这个阶段保持与产品工程师的密切沟通,了解需求情况之类的。

不过我觉得在现代互联网软件工程管理中,基本上不再存在这种问题了,因为互联网的需求是做不完的,开发团队不可能无所事事,总会有待开发的需求、待优化的架构等着你。如果互联网的开发团队经常无所事事,那么这个项目可能快要黄了。


第 5 章 - 画蛇添足

结构师的交互准则和机制

面对估算过高的难题,结构师(产品负责人)有两个选择:削减设计或采用成本更低的实现方法。……此时,结构师是在向开发人员的做事方式提出挑战。

所谓的 “估算过高”,在我们的实践中,实际就是工时过高。面对这种情况,产品负责人除了前几章所提到的人月神话之外,“削减设计” 就是砍掉某些功能;“采用成本更低的实现方法”,就是我们最讨厌从产品嘴里听到的 “简单做就好”。

按照书中的意思,我理解这个时候,如果产品提出上面三种要求,那就是在就是挑战开发的方案和排期。

后半段话主要是在告诫产品:你可以这么提要求、可以建议、可以沟通,但是最终决定权在开发手中,产品不能过分坚持自己的观点。

当然了,《人月神话》成书于 50 年前,而现代社会中,还有一种方法是 “加个班”。

自律——开发第二个系统所带来的后果

这一小节中作者描述了产品规划的一个问题。不过感觉与我们现在正常的项目流程出入很大。我们先看看作者的看法吧:

在开发第一个系统时,结构师(产品负责人)倾向于精炼和简洁。他知道自己对正在进行的任务不够了解,所以会谨慎、仔细地工作。

第二个系统是设计师们所设计的最危险的系统。……一种普遍倾向是过分地设计第二个系统,向系统添加很多修饰功能和想法……

项目经理如何避免开发第二个系统所引起的后果,从而避免画蛇添足?他必须坚持至少拥有两个系统以上开发经验结构师(产品负责人)的决定。

我对作者这一小节的理解为:产品工程师新建一个项目时,会很谨慎;但是项目上线后,开始迭代时,产品工程师就会非常自信地觉得自己已经对项目很熟悉了,开始大刀阔斧地增加不必要的功能,这就是 “第二个系统带来的后果”,因此要由富有经验的产品负责人来做最终决定。

但是这个观点与笔者的项目经验相悖。笔者在项目中经常遇到下面两种有问题的产品需求:

  1. 一开始就把项目设计得五花八门眼花缭乱,但是这些规划到后期因为各种原因没有落地,或者是趋于平淡,又或者是项目做着做着就没了,产品工程师也不跟进和迭代。
  2. 一开始就 “简单来” 或者是 “怎么快怎么来”,并且一直以这样的风格持续迭代,不收敛一下已有的能力;代码里的权宜之计和 hardcode 处处可见,屎山越堆越高。

因此,资深产品负责人的把关和把控,是很重要的。在开发侧,我们有 owner 和 Tech Lead 等角色和制度试图去解决代码层面的问题,“重构” 也是开发者们的常用词汇。

但是产品侧?笔者个人是没听说过,还请专业的产品同学指教一下哈。


第 6 章 - 贯彻执行

He'll sit here and he'll say, "Do this! Do that!" And nothing will happen.

——哈里·杜鲁门,“论《总统的权力》”

这句话太形象了,所以我特别附上。这一章节还是对产品工程师提出的要求,要求产品工程师 保持系统概念上的完整性,也就是要如何明确需求和产品框架。

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

书中要求产品工程师应该输出 “手册”:手册是产品的外部规格说明,它描述和规定了用户所见的每一个细节;同样地,它也是结构师(产品工程师)主要的工作产物。不过我觉得现代互联网可能不能套用这个定义,否则照这个观点,很多产品工程师的产出为 0 了。

其实在做很多传统行业项目的时候,这个规则是贯彻得很好的,比如说做 toB 和 toG 项目的时候,甲方都会要求我们提供大量的测试用例、文档、说明、SOP、维护手册等等资料,并且这些资料会成为整个项目中最有价值的部份(没错,代码简直不值钱)。

本小节的主要观点,是为了避免许多产品工程师七嘴八舌地提出观点和主意,但是没有最终落地和统一。书中提出的方案是:

……思路是大约 10 个人的想法,但如果想要保持文字和产品之间的一致性,则必须有一个或两个人来完成将其结论转换成书面规格说明的工作。……保证这些看似所对的问题处理原则上的一致性,绝对不是一件无关紧要的事情。

简单而言,就是需要有极为少数的一两个,负责收集所有的需求,并转换为统一的文字输出。书中没有说这必须是产品负责人,也可以是一位秘书,或者是某一两个专职的产品工程师。总之,原则上并不是所有的人都能对接开发。

其实自从 CSIG 成立,对于腾讯没有 toB 基因的声音就不绝于耳。确实我们 toC 的做法,就是不重视文档的,甚至在某些场景下,还有些鄙视文档。

这些也不是简单的对和错,只能说适应场景的角度。其实我们可以换个看法,在本章节中,作者的重点是要保证概念的一致性,那么我们完全可以基于这个目的,用其他的方法来解决,比如说建立术语辞典、或者是推崇大火的 DDD。


第 7 章 - 为什么巴别塔会失败

项目工作手册

本章节作者进一步说明了沟通和组织的重要性,并且强调必须维护项目工作手册,这个手册包含以下内容:

  1. 项目目的
  2. 外部规格说明
  3. 接口说明
  4. 技术标准
  5. 内部说明
  6. 管理备忘录

本小节可以跳过,在 toC 的互联网行业中,我们无法推进这种工作的落地。如果是 toB 的话,甲方会教我们 “做人”。

大型编程项目的组织架构

在这里面,作者提出了在一个项目中两个重要的角色:

  • 产品负责人:这个概念跟我在上文提到的 “产品负责人” 的概念进一步不一致。在我们的语境中,产品负责人一般情况下是一位资深的、有权威性的产品工程师。但是在本小节中提到的产品负责人,在我们的语境中应该是项目领导,ta 拥有行政权力,可以调配人力,协调资源,他组建团队,划分工作及制定进度表,更多的接近于我们公司的项目工程师(PM)+ 各级管理层的角色。
  • 技术主管对设计进行构思,识别系统的子部份,指明从外部看上去的样子,勾画它的内部结构。他提供整个设计的一致性和概念完整性。很明显,这就是我们技术 owner 或 tech lead 的角色。

然后,作者提出这两种角色的三种协作关系:

  1. 项目领导 和技术主管是同一个人 :这很好理解,从团队而言,同一个人又是 CEO 又是 CTO,拥有绝对的权力
  2. 项目领导 作为总指挥,技术主管充当其左右手:这在大型团队中,特别是技术团队非常多的情况下中非常有用。但是这种方式执行起来比较困难,因为这样一来技术主管很容易缺乏行政权威,很难调用资源,对项目领导专业能力的要求很高
  3. 技术主管作为总指挥,项目领导 充当其左右手:这在小型团队,或者是产品工程师多于开发的情况下非常适合。

第 8 章 - 胸有成竹

本文详细地说明了一个系统编程所需要花费的时间、工作量和预估方法。但是就我个人感觉,本章节在现代计算机行业中,适用程度已经不高了,特别是文中列出的许多经验值和公式。但是定性的角度,我们还是可以汲取一些信息的:

  • 耦合功能越多,工作量越大,并且这是一个指数递增的关系。这让我们在排期中要特别注意,加一个功能并不是简单加相应功能的工作量就完了,还要加上与系统现有功能的联调和相应的测试成本。
  • 尽量保存开发过程中的工作日志,包括进度记录、各种琐碎文字记录、会议记录、甚至请假记录,便于收集经验、复盘和指导以后的项目排期

第 9 章 - 削足适履

这一章节很小,简单(但是缺乏例证地)列举了几个观点:

  1. 要注意机器租金带来的成本——这个我们都知道
  2. 要针对相应的规模,准备相应的预算——说白了就是要做好容量预期
  3. 开发人员要时刻从整体出发、面向用户去思考,不要只做一个个小模块的优化
  4. 削减不必要的功能,以节省设备成本——对我们来说,就是尽量不要浪费算力在一些没用、或者是 ROI 很低的功能中
  5. 以空间换时间——这在软件开发中其实经常用,比如各种缓存机制
  6. 积累公共库,这是一件重要的实现工作——其实放到现代软件工程中,开源共享的氛围也大大提高了编程效率

第 10 章 - 提纲挈领

本章节又双叒叕强调了文档的重要性,此外还强调了文档的跟踪维护的重要性。原文有一句话我觉得很有意思:

文档的跟踪维护是项目监督和预警的机制。文档本身可以作为检查列表、状态控制,也可以作为汇报的数据基础。

确实,比如说我在晋级答辩时候,资料中有不少数据来自于日常的文档,而不是临时抱佛脚。至于文档的跟踪是否能够体现出项目的异常情况,我觉得可能只能作为其中的一种参考手段吧。

计算机产品的文档

目标:定义待满足的目标和需要,定义迫切需要的资源、约束和优先级。

技术说明:计算机手册家性能规则说明。它是在计划新产品时第一个产生,并且最后完成的文档。

进度

预算:预算不仅仅是约束,对管理人员来说,他还是最有用的文档之一。预算的存在会迫使其指定技术决策,否则,技术决策很容易被忽略。更重要的是,它促使和澄清了策略上的一些决定。

组织结构图

工作空间的分配

报价、预测、价格:这三个因素互相牵制,决定了项目的成败。

谁能推动这些文档落地,我敬一杯。

软件项目的文档

作者说:不论项目的规模有多小,项目经理聪明的做法都是:首先立刻正式生成若干形式的小文档,一作为一个自己的数据基础,然后再要求提供和其他经理类似的文档。

在我们所处行业,这是绝对不可能做到的,我们几乎不可能把文档的地位抬到这么高。但是我自己个人针对这一点有另一个看法,我们看看下一小节:

为什么要有正式的文档

首先,书面记录决策是必要的。只有记录下来,分期才会明朗,矛盾才会突出

如果从项目经理的角度来看,ta 可以做好每一次项目问题的记录,这种记录,恐怕只有项目经理自己才能完成,不能要求别人给出,因为 ta 不是矛盾的当事人,能够尽量中立。

第二,文档能够作为同其他人的沟通渠道。……

这里提到的文档,指的是由项目经理发起,但主要有项目直接参与者(产品、开发)重点负责更新。然而,在现行架构下,这基本是一句空话,也是我个人觉得不切实际的一点。但是确实有很多团队在试图建立文档自动生成能力的建设,这一点非常值得考虑。

最后,项目经理的文档可以作为数据基础和检查列表。通过周期性的回顾,他能够清楚项目所处的状态。

这是我个人比较赞同的一点:作为项目或者产品经理,维护自己的一个简易文档是有必要的,这个文档可以是对各种资源的提纲、整理,也是管理者管理思维的外在体现。这也就决定了这个文档的形式并不统一,并且应该由项目经理自主维护和更新。

我在不得不专职项目管理时,就有许多给自己看的项目进度文档,并且进度有时候需要主动去了解,如果只依靠被动接收进度汇报,我会发现一直都是 “正常”,直到关键时间点接近的时候,各种风险和延期警告会突然间集中爆发出来。


第 11 章 - 未雨绸缪

看了前面 10 章,产品工程师们可能会不满意:怎么尽吐槽我们了?别急别急,从这一章开始,让我们把火力对准开发。

试验性工厂和增大规模

化学工程师很早就认识到,在实验室可以进行的反应过程,并不能在工厂中一步实现。……

软件系统的构件人员也面临类似的问题,但似乎并没有吸取教训。一个接一个的软件项目都是一开始设计算法,然后将算法应用到待发布的软件中,接着根据进度把第一次开发的产品发布给顾客。

对于大多数项目,第一个开发的系统并不合用。……要解决所有的问题,除了重新开始以外,没有其他的的办法……系统的丢弃和重新设计可以进一步完成,也可以一块块地实现。所有大型系统的经验都显示,这是必须完成的步骤。而且新的系统概念或新技术会不断出现,必须构件一个用来抛弃的系统。……

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

个人觉得这几段话非常完整,详细解释了为什么在软件中一步到位是不可能的,并且也明确说明了要设计一个可变化的系统。

另外一个方面,是逐步发布。对于一个大型的系统,可以先发布少量功能,然后参照线上反馈,逐步修改接下来新功能的功能、架构并进行开发、测试,一步步地将完整的功能发布上线。

为变更计划组织架构

这一小节重点强调了设计文档的作用,让文档表现开发者的思路,通过设计文档化,设计人员将自己暴露在每个人的批评之下,他必须能够为他书写的一切进行辩护。

接下来的一部份比较长,但是简单而言,就是建议参考 IBM 一样,给高级程序员后续的晋升涉及两个方向,一个是管理线,另一个是技术线,为两条线建立相互一致的薪水级别和威信——不过这在国内互联网公司中,真的能做到吗?

前进两步,后退一步

本小节主要说明系统上线后,随着用户使用的深入,bug 仍会持续产生;修复先前的 bug 也可能会导致新 bug 的产生。为此,回归测试是非常重要的。

改善(无法完全解决)这个问题的方法是:

  1. 使用更好的程序设计方法
  2. 详细的文档
  3. 设计实现的人员越少、接口越少越好

前进一步,后退一步

随着时间的推移,系统变得越来越无序,修复工作迟早会失去根基。每一步前进都伴随着一步后退。……崭新的、基于原有系统的重新设计是完全必要的。

我的理解,这里讲的其实就是对原有架构的持续重构,如果架构是一成不变的,那么很快就会无法适应新变化、新需求的要求,维护的成本越来越高,迭代、测试、debug 的成本也会越来越高。


第 12 章 - 干将莫邪

本小节主要说明统一的基础设置的必要性。

……每个骨干人员都仔细地保管自己工作生涯中搜集的一套工具集,这些工具成为个人技能的直观证明。……

这种方法对软件项目来说是愚蠢的。首先,项目的关键问题是沟通,个性化的工具会妨碍而非促进沟通。其次,……技术也会随之变化,所有工具的生命周期都是很短的。最后,毫无疑问,开发和维护公共的通用编程工具的效率会更高。

……我建议为每个团队配备一名工具管理人员。……

……为通用工具的开发分配资源。……可能有人会觉得,将所有分散的工具管理人员集中起来,形成一个公共的工具小组,会有更高的效率,实际上却不是这样。

这里的 “工具集” 概念,按照作者在下文中的分类,包括以下内容:

  • 计算机设施:这个我们至少已经收敛了,开发环境就是本地或 DevCloud 的 Linux 环境或者是 ioa 云开发;测试和部署,就是 idc 和 TKE
  • 操作系统:没得说的,Linux,统一了。开发环境随意,公司支持得很好,不需要统一
  • 实用程序:这个公司也提供了很多,都是可用的
  • 调试辅助程序:Go 编译工具,很统一
  • 测试用例生成工具:没有,实际上这个也很难统一,可以理解
  • 字处理系统:以 Go 开发为例,基本就是 VSCode 或 GoLand,也统一了。Vim 也有完善的工具链。

可以看到,作者提的 “工具集”,其实就是开发的基础设施。统一提供,问题不大。但是原书中反对建立公共工具小组,这是让我极度费解的,笔者认为适度的工具链维护团队是有益的。


第 13 章 - 整体部份

剔除 bug 的设计

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

又要求写文档了。

此外,作者建议在设计中使用自上而下的方式进行设计,好处在于:

  1. 清晰的结构和表达方式更容易对需求和模块功能进行精确地描述。成书时,主要开发语言还是汇编。现代高级语言的可读性已经今非昔比。
  2. 模块分割和模块独立性避免了系统级的 bug。我们开发的时候要尽量将独立的功能模块化,而模块的大小决定了程序的适用性和可变化的程度。
  3. 细节的抑制使结构上的缺陷更容易识别。这句话怎么理解我不太确定,是推崇高内聚吗?
  4. 设计在每个精话步骤上是可以测试的。意思就是模块级别的测试,个人觉得对于底层模块,单测可以很好地解决这个场景。

此外作者还提了一个场景,跟上一章节有一点相互印证:

一些糟糕的系统往往就是试图挽救一个基础很差的设计,而对它添加了各种表面装饰般的补丁。

该重构就重构。

构件单元测试

这一小节作者提了一些概念,但是它所提的场景更适合老式软硬件相结合的大型计算机项目,对现代互联网相互参考不大。

系统集成测试

系统集成调试要求只能字每个部份都能正常运行之后开始

也就是说,每个人要对自己开发的模块,能测试则测试,OK 了之后再联调。当然了,我觉得这也只能是尽量而言,因为有些逻辑确实是需要集成之后才能调试的。

另外,作者还强调了搭建测试平台的重要性,这对我们来说包含两部份:

  1. 搭建测试环境和构件测试数据
  2. 自动化测试平台

此外,作者还提出了 伪构件 的概念,用于辅助测试,类比到我们的开发场景中,其实更加接近于 mock 技术。

还有一个概念是 “阶段(量子)化、定期变更”,这个对我们来说,可以用持续测试来优化。


第 14 章 - 祸起萧墙

本章主要说明如何应对项目进度落后。

里程碑还是沉重的负担

要管控大型项目的时间表,第一件事是制定进度表上的里程碑。里程碑的选择只有一个原则,那就是里程碑必须是具体的、特定的、可度量的时间,能够进行清晰定义。。反面例子是诸如 “90%完成”“99%完成” 之类的话术。具体的里程碑是百分之百的事件

如果里程碑定义得非常明确,无法自欺欺人时,很少人会就里程碑的进展弄虚作假。但是如果里程碑很模糊,老板常常会得到一份与实际情况不符的报告。

此外,作者还建议经常回顾进度,每两周进行一次仔细的修订。从我们的角度看来,两周时间足够完成一次需求了,但是这两周却是一个很有趣的时间单位,再敏捷开发 Scrum 中,对 sprint 的最小单位也建议为 2 周。这值得我们好好研究,避免以更小的维度安排项目。

“其他的部份反正会落后”

作者在这里建议用波特图来观察项目进度——原来波特图的历史这么早啊。

地毯的下面

当项目落后时,项目经理会倾向于向老板掩盖问题,只在团队内部寻找有没有解决的办法。久而久之,就导致 所有的污垢都被隐藏在地毯之下。但是老板是希望知道项目进度异常的,但是一线又担心汇报问题后,老板会直接插手,降低项目经理的威信、打乱其他计划。

作者建议了两种解决方法:

  1. 汇报问题后,老板不应急于插手,而是先观察和询问团队自己是否可以解决问题,时间一长,一线就不会害怕汇报问题;如果老板收到报告之后马上发号施令,久而久之他就会逐渐无法收到真实的信息。
  2. 借用波特图和明确的里程碑,向老板展示项目的全貌并给出报告,应该准备解释延迟的原因,什么时候结束,采取的步骤和需要的任何帮助——老板提供的,或者是其他小组间接提供的。也就是说,把现状和解决方案一并奉上。

第 15 章 - 另外一面

这一章节主要是再次说明文档为什么重要,以及如何撰写文档。

文档,是沟通的一种。即使是完全开发给自己使用的程序,这种沟通仍然是必要的。因为记忆衰退的规律会使用户——作者失去对程序的了解,于是他不得不重拾自己劳动的各个细节。

面对那些文档“简约”的程序,我们中的大多数人都不免暗骂那些远在他方的匿名作者。

需要什么样的文档

作者在这里介绍了文档需要包含的部分,我觉得作为注释,也可以参考。此外,作者是以一整个程序作为文档的单位,如果是小到一个模块、一个函数也可以借鉴。

1、使用程序,也就是被说明的对象的使用方法

(1) 目的。主要的功能是什么?开发程序的原因是什么?我们可以理解为 “背景”

(2) 环境。程序运行在什么样的机器、硬件配置和操作系统上?对后台开发来说,这个问题不大

(3) 范围。输入的有效范围是什么?允许现实的合法输出范围是什么。其实就是值域。比如说,sleep() 函数,如果输入小于零的值会发生什么事情,这里得说明

(4) 实现功能和使用的算法。精确阐述它做了什么。

(5) “输入-输出” 格式。必须是确切和完整的。比如说有个变量,int 类型,叫做 timestamp,你得解释一下单位是秒还是毫秒

(6) 操作指令。适用于控制台命令,比如说各种参数之类,程序如何正常执行,有哪些异常情况

(7) 选项。额外的选项配置

(8) 运行时间。执行一个功能,程序要运行多久

(9) 精度和校验。程序执行的精度如何以及如何验证。

说实话,我觉得一份文档,还不太有必要上面9项面面俱到的程度,根据情况,选取就行了。个人觉得 1、5 是特别必要的。

不过说句题外话,如果大家要写论文或者是晋级资料,这9项倒是具有极高的参考价值。

2、验证程序,这里讲的是程序的 测试用例

测试用例就是根据程序的输入,它会得出什么样的输出。用例根据 输入数据的范围划分为三个部分

  1. 基于基本功能、常规数据的测试用例,用来表示程序正常执行的情况。他们是测试用例的主要组成部分
  2. 合法性测试用例,主要是用来覆盖 输入数据范围边界,比如最大值、最小值之类的情况。
  3. 数量相对较少的非法数据测试用例

不过笔者想要吐槽一下,如果追求 100% 覆盖率的话,其实 3 才是单元测试用例的大头……

3、修改程序。这一部分更像是程序的设计文档了,是写给开发着看的。这里作者简单列举了一下几项,并且在本小节的后文进一步说明:

(1) 流程图或子系统的结构图

(2) 对所用算法的完整描述,或者是类似算法的参考资料。参考资料确实是挺好的东西,我也经常鼓励大家在注释里面写

(3) 对所有文件规划的解释。这个没仔细解释,我根据我的实际经验,我猜可能是解释文件为什么要这么拆分、各个文件分别是实现什么逻辑之类的吧。

(4) 数据流处理的概要描述。就是数据的流向,以及在每一步中的数据处理过程

(5) 初始设计中,对已预见修改的讨论;特性、功能回调以及出口的位置……前面一部分我个人觉得非常有预见性,我们在做架构设计时,有时候是会为一项未来即将引入或者可能引入的功能预留接口,着也就是架构设计的扩展性和预见性。那么在文档中,我们可以把这些扩展和预期列出来,不论做不做,这都可以为未来的设计提供参考,也可以佐证架构设计的完备以及当前一些逻辑设计的合理性。

流程图

流程图我们都会画,但是作者的观点是:很多程序甚至不需要流程图,很少有程序需要一页纸以上的流程图。对这句话的后半句我非常赞同,超过一页纸的流程图,根本看不明白。前者我觉得作者想要表达的意思,应该是认为一个严谨的、拘泥于 ANSI 标准的流程图并不是必要的,在绝大多数情况下,我们可以自由选择示意图的格式,尽可能地使用简明扼要的形式表达逻辑或结构。

但是说实话,作者写了很大一段话,列出了几个并没有什么普适性的例子,我感觉他并不能很好的自圆其说。但是对于观点我个人是赞同的,只是如何画图,这是另外一个大课题了,一个章节甚至是一本书也是说不明白的。

自文档化的程序

作者表达了一个意思:如果将代码写在一处地方,而文档写在另一处地方,那么因为代码是频繁变更的,我们几乎不可能在每次修改代码的时候,都会记得(或者是愿意)去修改对应的文档记述。作者说:相应的解决方案是“合并文件”,即吧文档整合到源程序。这种程序被称为 自文档化(Self-Documenting)

这就是我们当前常见的几种模式了:

  1. 在源文件中写文档:我们如果看 Linux 设备驱动程序文件就非常常见,在每一个 .C 文件的开头,总有长篇大论的一段文字,或是 GNU 声明,也包含对这个文件的文档注释
  2. 在代码符号(变量、常量、函数、方法)上写关于该符号的文档
  3. 函数/方法的行内注释,这也算是作者所说的文档的一部分

具体到 Go 来说,严格使用 GoDoc 规范就可以非常好地实现自文档化。

作者在该小节给出了一个让人叹为观止的自文档例子,在例子中,代码只占据不到 10%,剩下的 90% 都是各种各样复杂的注释,甚至作者还用 ASCII 技术写出了复杂的 JUMP 流程图。这是因为,作者在文中使用的是汇编语言,而汇编语言的可读性大家都懂。在现代高级语言的加持下,程序的可读性大大提高,足够简洁的逻辑,也不需要像50年前那样过多的注释了(不是不需要注释!)。

作者也说了:高级语言的使用激发了自文档化方法


第 16 章 - 没有银弹

《没有银弹》是作者在 1986 年在读比邻 IFIP 研讨会的一篇受邀论文,1987 年《Computer》杂志也登载了。本小节主要就是当年的那篇论文。需要注意的是,这些内容,距今已有超过35年。

银弹可以用来是用来射杀吸血鬼、狼人和怪兽,作者引申出表示能够解决一切软件工程问题的工具或者技术。作者认为,看看近十年来的情况(指的是 1995 年过去的 10 年),没有发现银弹的踪迹。没有任何技术或管理上的进展,能够独立的许诺在生产率、可靠性或简洁性上去的数量级的提高。同时作者也总结道,对银弹的追求,诞生了现在的软件工程。

在未来的十年内(指的是 1986 年之后的 10 年),无论是在技术还是管理方法上,都看不出有任何突破性的进步,能够保证在十年内大幅度地提高软件的生产率、可靠性和简洁性。

这篇论文非常有趣。我们可以从今天的角度(2024年)往回看这篇文章,去回看作者的观点,看看他的评论和预言是否成真了。

根本困难

作者认为,软件系统的 复杂度、一致性、可变性和不可见性 导致了 软件开发总是非常困难的,天生就没有银弹。

对比硬件领域有摩尔定律,作者认为,软件的特性本身也导致不大可能有任何的发明创新,能够大规模地 提高软件的生产率、可靠性和简洁程度。 因此软件工程没有摩尔定律,或者说没有通用领域下的摩尔定律,有能力让我们 期望每两年有两倍的增长。

作者认为:软件开发中困难的部分是规格说明、设计和测试这些概念上的结构,额不是对概念进行表达和对实现逼真程度进行验证。换句话说,难的是如何精准地表达产品需求。

软件系统的 复杂度,也导致 团队之间的沟通非常困难,导致了产品瑕疵、成本超支和进度延迟;由于复杂度,使列举(还远远不是理解)所有可能的状态变得十分困难……这也促成了模糊测试的出现,但也依然不能完全解决我们的痛点。

由于结构性复杂度,程序难以在不产生副作用的情况下用新函数扩充。按我们流行的说法,就是引入新 feature 的同时,大概率引入新 bug 或新漏洞。这也就是为什么 Windows 的漏洞年年有,因为它太复杂了。

回想这两年的 AIGC 热,我们会发现 AI 确实提高了生产力,但是它还没有替代程序员的工作,也是因为类似的原因——并不完全是因为 AI 做不到,而一定程度上是因为我们没办法精确描述我们要什么。因此需求的设计到开发再到上线,依然需要拉扯、需要测试、需要验证。这些场景,依然没有银弹能够解决。

一致性 讲的是我们无法开发一个绝对通用的软件,来解决所有的问题。作者列举了物理学的统一场论,因为在物理学中,很多不同领域的公式都存在着极为相似的性质,最典型的就是各种力场的形式都非常相似,因此物理学家试图通过这一表象,找到所有力学现象的本质,这也爱因斯坦毕生的追求,甚至为了统一场论,爱因斯坦与哥本哈根学派还有过论战,其中最为著名的就是爱因斯坦的 “上帝不会掷骰子”。然而历史证明,爱因斯坦失败了。而之后量子力学的发展,才直接造就了计算机技术革命。

可变性不可见性 也很好理解,需求经常是变化的,而软件时不可兼得和无法可视化的,因此软件非常抽象,不直观。

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

作者这里提了几个软件技术在 1995 年之前的三次进步,我们可以当历史书来看:

  1. 高级语言:高级语言的发明,对软件开发的贡献有目共睹,它极大地降低了软件代码的复杂度。但是,随着软件设计能力的提高,软件需求的复杂度也与时俱进了。高级语言让我们提高了生产力,但是并没有释放我们的生产力。
  2. 分时:以前的操作系统都只是批处理系统,无法做到分时多任务
  3. 统一编程环境:这个比较虚,不过我觉得这里应该用 “标准化” 一词,比如操作系统层面,各种协议和规范,我们耳熟能详的 OSI、Posix、IEEE、ANSI、JPEG、MPEG 等等,统一了运行环境、交换协议、文件格式等等,概念性的统一,让程序能够得到极高的复用,也可以降低软件系统的开发成本。已经熟悉云原生的 00 后们,恐怕很难体会到 Pony 当年架设起一个 QQ 服务器的困难。

银弹的希望

从 1995 年的角度,作者也提了几个技术点或范畴,觉得有可能会出现银弹。由于我们距离 1995 年已经太久了,这一部分依然可以作为历史书来看:

Ada 和其他高级编程语言:首先,Ada 已经凉了。而各种高级语言确实在各个领域都在茂盛地生长,但是我们也发现,并没有任何一种语言在这过去的接近30年间,一统天下成为银弹。

面向对象编程:面向对象提出了大量深刻影响后人的设计理念,在 2024 年的今天,我们依然可以从中获益良多。然而我们作为 Go 工程师可以看到,Go 作为后起之秀,在设计之初就抛弃了 OOP 的一部分理念,这也从侧面印证了,即便 OOP 非常先进,但它也不全是银弹。

人工智能:1995 年的人工智能,基本上还没什么概念和解决方案。当年可能看起来比较有潜力的也就只是神经网络了。然而神经网络的可应用性,也沉寂了20多年,直到今年的深度学习神经网络才有所起色。

专家系统:这个目前算是以大模型为主的 AI 应用场景中正在发力的方向,前景未明。现在的我们看专家系统,就像 30 年前的人们看人工智能一样,面前还是一片迷雾,只有不确定的方向,那就是大模型。

“自动” 编程:这个概念就正如字面意思一样,我查阅不到相关的资料,更像是当时人们的一种愿景吧

图形化编程:图形化编程发展了这么多年,基本上已经被证明并不是一种高效的开发手段了,它只适合用来实现一些傻瓜式的、极为简单的 CURD 逻辑。要不然前端开发同学早就把图形化玩出花了。

程序验证:其实就是测试手段。为了测试,程序员们已经发明出了很多种测试方案,接口测试、单元测试等等。但是也没有哪一种测试手段能够覆盖所有的场景。

环境和工具:对我们来说,就是 IDE 了。功能越来越多的 IDE 确实极高地提高了我们的开发效率,然而,也依然没有哪一个 IDE 能够产生革命性的影响。

工作站:作者应该是像表达,集中式的工作站,使得程序员们可以使用性能更强的进行开发、编译和调试。我只能说,作者低估了现代个人电脑的性能了。不过,机器跑得快,也并没有对我们的开发效率带来根本性的变化。

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

作者这里再次提及了一些理念,可以提高软件设计、开发效率:

购买和自行开发。这里作者偏向于能买到的现成软件,就买,不要自己再开发一次。其实我觉得可以引申出去,就是已有的能力、特别是现成的开源软件或代码,我们都可以调研,尽量避免浪费时间造轮子,而把主要精力放在业务开发中

需求警联合快速原型。这就是产品同学需要学习的了,比如说我很少看到有产品同学使用 Figma 以及类似的专业的原型设计软件,而非常依赖设计同学输出的静态图片。

增量开发——增长,而非搭建系统。这个之前就提过了,软件开发是搭积木,砌砖,而不是垒墙。我们要模块化编程、面向接口编程,而不是面向过程开发。

卓越的设计人员。作者化了一些篇幅表达核心软件设计师的重要性,优秀的管理人员同等重要。


第 17 章 - 再论 “没有银弹”

作者发表《没有银弹》之后,引起了很大争议,很多作者声称他们找到了银弹,或者是他们手头的技术手段能够成为银弹。作者在这一小节里逐一进行辩论。我们已经知道结果了,确实没有银弹。因此这一小节并不重要。


第 18 章 - 《人月神话》的观点:是与非

这一小节是对前文的提纲式总结。


第 19 章 - 20 年后的 《人月神话》

这一部分更像是一个长长的后记,大部分内容还是对前文的重新强调,也顺便赞赏了软件系统工程师们对提高用户体验过程中的努力。

这一小节有小部分新内容,其中很重要的一部分是:瀑布模型是错误的,都已经退休了的作者在这一小节中抨击了瀑布模型的错误性,他认为一个软件开发模型应该存在逆向移动,也就是返工过程,而瀑布模型没有考虑这种问题。

作者进一步提及:增量开发模型更佳——渐进地精化,其中提到的很多理念,与敏捷迭代(Agile)非常类似。增量地开发(growing)也与 Scrum 开发非常类似。

此外,作者还提到了 Microsoft 的 “每晚重建” 方法,其实就是我们常说的持续集成。

作者也提到了个人计算机带来的革命,哈哈,前面我也说了,作者之前低估了这一点。


结束语:令人向往、激动人心和充满乐趣的 50 年

……而我现在只能对层出不穷的学科分支遗憾地说 “再见”,对我所关注的东西也越来越难以全部掌握。……

毕竟 1995 年,弗雷德里克老爷子 64 岁,已经退休。以后的软件工程就要靠后浪们顶上了。


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原作者: amc,原文发布于腾讯云开发者社区,也是本人的博客。欢迎转载,但请注明出处。

原文标题:《为什么软件行业仍在重蹈 50 年前的覆辙?——《人月神话》读书笔记》

发布日期:2024-09-02

原文链接:https://cloud.tencent.com/developer/article/2448955

CC BY-NC-SA 4.0 DEED.png


amc
924 声望223 粉丝

电子和互联网深耕多年,拥有丰富的嵌入式和服务器开发经验。现负责腾讯心悦俱乐部后台开发