重读《人月神话》:第九章“削足适履”

“他应该瞪大眼睛盯着诺亚,好好学习,看他们是怎样把那么多东西装到一个小小的方舟上的。”

——西德尼·史密斯,《爱丁堡评论》


今天的程序员写代码,通常以千行为单位,大型项目以万行甚至百万行为单位。我们很少会停下来想:这么多代码,能不能塞进那枚小小的CPU里?能不能在有限的内存中跑起来?答案通常是"当然能"——因为我们的设备内存早已以GB计,存储空间以TB计,空间似乎是最不需要担心的问题。

但在布鲁克斯所处的年代,情况完全不同。内存以KB计,每一千字节都有明确的租金价格。程序占用的空间不是抽象的数字,而是用户每月账单上实实在在的支出。当空间本身就是成本时,"削足适履"不是锦上添花的技术优化,而是项目能否存活的根本约束。

正是在这样的背景下,布鲁克斯借用了诺亚方舟的比喻——在有限的空间里装载整个世界,需要的不是更大的方舟,而是更聪明的排列。


一、规模成本的真实面目:OS/360的惨痛教训

1.1 内存租金与整体预算

布鲁克斯用1970年代的一个案例揭示了空间成本的残酷:

IBM APL交互式软件系统,月租金400美元,运行时至少占用160K字节内存。在Model 165上,内存租金约12美元/每月每千字节。如果程序全天候运行,用户每月需支付400美元软件租金和1920美元内存租金——内存成本是软件本身的近5倍

当时常有人批评"2M内存的机器上,操作系统就占了400K"。但布鲁克斯指出,这种批评就像批评波音747耗资两千七百万美元一样无知——关键问题不是"它花了多少",而是"它能干什么"。

“当系统设计者认为对用户而言,常驻程序内存的形式比加法器、磁盘等更加有用时,他会将硬件实现中的一部分移到内存上。相反的做法是非常不负责任的。所以,应该从整体上来进行评价。”

这与第一章"焦油坑"的呼应: 从简单程序到编程系统产品,成本膨胀9倍。这9倍成本中,空间成本占据了不可忽视的份额。规模本身不是坏事,但不必要的规模是不可取的

OS/360的设计者非常仔细地为核心程序设定了规模目标。每个人都汇报了自己的核心大小,都在目标范围之内。但问题出在了视野之外

“在为每个单元设立核心规模的同时,我们没有同时设置访问的目标。当程序员发现自己的单元核心未能达到要求时,他会把它分解成链接库。这个过程本身增加了程序整体的规模,并降低了运行速度。最重要的是,我们的管理控制系统既没有度量,也没有捕获这些问题。”

结果: 第一次性能仿真运行时,Fortran H在带磁鼓的Model 65上,每分钟只能模拟编译5条语句。控制程序模块进行了大量不必要的磁盘访问。

“和制订驻留空间预算一样,应该制订总体规模的预算;和制订规模预算一样,应该制订后台存储访问的预算。”

预算类型OS/360的做法后果
核心内存预算✅ 有核心大小达标
整体规模预算❌ 无链接库膨胀,总空间失控
后台访问预算❌ 无磁盘访问爆炸,性能崩溃

1.2 功能边界与全局视角

OS/360的另外两个教训更为隐蔽,且相互关联。

教训二: 在每个模块分配功能之前,空间预算已经编制完成。结果是:

“任何在规模上碰到问题的程序员,会检查自己的代码,看是否能将其中一部分扔给其他人。因此,控制程序所管理的缓冲区成为了用户空间的一部分。更严重的是,所有的控制模块都有相同的问题,彻底影响了系统的稳定和安全性。”

核心问题: 当模块的"大小"被限定但"功能"未被精确定义时,程序员会本能地把功能"踢"给其他模块,以保住自己的空间指标。这就像让五个室友合租一间房,每人限定占用2平方米——结果不是大家精简行李,而是把东西塞进别人的区域。

“在指明模块有多大的同时,确切定义模块的功能。”

教训三: 项目规模本身很大,缺乏管理和沟通,以至于每个团队成员认为自己是争取小红花的学生,而不是构建系统软件产品的人员。为了满足目标,每个人都在局部优化自己的程序,很少会有人停下来,考虑一下对客户的整体影响。

这与第七章"巴别塔"的呼应: 第七章说"沟通是大型项目失败的首要原因",第九章说**“缺乏沟通导致每个人都在局部优化,没人考虑整体影响”**。巴别塔的工程师因为语言不通而无法协作,OS/360的工程师因为缺乏全局视野而各自为战——两种病症,同一种病根。

“在整个实现的过程期间,系统结构师必须保持持续的警觉,确保连贯的系统完整性。培养开发人员从系统整体出发、面向用户的态度是软件编程管理人员最重要的职能。”


二、装进方舟的艺术:空间、时间与数据

规模预算的制定只是第一步。真正让系统"装进方舟"的,是空间技能——在约束条件下进行创造性取舍的能力。

2.1 空间-时间折衷:从系统预算到算法课本

布鲁克斯指出了一个在很大范围内都成立的基本规律:

“对于给定的功能,空间越多,速度越快。”

这句话听起来熟悉吗?在数据结构与算法的课程里,我们学过几乎相同的道理——只是换了一套术语:用哈希表做查找,是以空间复杂度的上升换取时间复杂度的下降;用链表代替连续数组,是以访问时间的增加换取插入删除空间的节省。空间复杂度和时间复杂度从来不是独立的坐标轴,而是一条可以来回滑动的权衡曲线。

布鲁克斯在第九章说的正是这条曲线的系统级版本。OS/360的程序员为了保住自己的"核心内存预算"(降低空间占用),把代码拆成链接库、踢给其他模块(增加磁盘访问时间)——这本质上是一次用时间换空间的决策,只是没有人去计算这次交换是否划算。

策略数据结构中的例子OS/360中的对应代价
空间换时间哈希表、缓存、索引常驻内存、预加载消耗更多内存
时间换空间链表、压缩存储、惰性计算链接库、覆盖加载增加访问延迟

关键洞察: 数据结构的复杂度分析教我们如何在单个算法里做这道选择题;布鲁克斯教我们如何在整个系统里做同样的选择题——而且必须有人为这道题的全局后果负责。

在此基础上,布鲁克斯提出了另一个影响深远的策略问题:为用户保留多少选择?

“程序可以有很多的选择功能,每个功能仅占用少量的空间。也可以设计成拥有若干选项分组,根据选项组来剪裁程序。任何一系列特殊选项被合并在一起进行分组时,程序需要的空间较少。这很像小汽车。如果把照明灯、点烟器和时钟作为整个配件来标明价格,则成本会比单独提供这些选择所需要的成本低。所以,设计人员必须决定用户可选项目的粗细程度。”

策略特点空间效率灵活性
细粒度选项每个功能独立开关低(重复代码多)高(用户自由组合)
粗粒度分组功能打包成组高(共享代码多)低(用户只能选组)

项目经理的两件事: 一是确保团队得到培训,而不是只依赖个人经验;二是建立公共构件库,对于每项功能至少准备两个实现——一个运行速度较快,一个短小精炼。

这与第八章"胸有成竹"的呼应: 第八章说高级语言可以将生产率提高5倍。第九章说,公共构件库是另一种形式的生产率提升——不是通过语言抽象,而是通过消除重复劳动。

2.2 数据的表现形式:从数据结构到系统架构

第九章的最后一部分,是整本书中最富诗意、也最具洞察力的段落之一。布鲁克斯在这里超越了"空间管理"的技术层面,触及了编程的本质

“如果提供了程序流程图,而没有表数据,我仍然会很迷惑。而给我看表数据,往往就不再需要流程图,程序结构是非常清晰的。”

这个论断的颠覆性在于: 传统教学告诉我们"先画流程图,再写代码"。但布鲁克斯说,真正揭示程序本质的不是流程图,而是数据。流程图展示的是"程序怎么做",数据表展示的是"程序处理什么"。当你理解了数据的结构和关系,程序的行为自然浮现。

这与数据结构课程的核心思想完全呼应。 当你为一个问题选择了错误的数据结构——比如用数组做频繁插入删除,或者在需要快速查找时用了线性链表——你的程序就会像OS/360那样"膨胀"且低效:不是内存占用失控,就是运行时间爆炸。而当你重新表达数据——比如改用树形结构、哈希映射或者列式存储——你可能获得布鲁克斯所说的"战略上的突破",而非仅仅是技巧上的优化。

布鲁克斯进一步区分了两种技艺改进:

类型例子影响
技巧上的提高更快的循环、更优的寄存器分配线性改进,通常10%-50%
战略上的突破快速傅立叶变换、将比较算法从n²降到n log n数量级改进,通常10倍-100倍

“更普遍的是,战略上突破常来自数据或表的重新表达——这是程序的核心所在。缺乏空间而绞尽脑汁的编程人员,常常能通过从自己的代码中挣脱出来,回顾、分析实际情况,仔细思考程序的数据,最终获得非常好的结果。实际上,数据的表现形式是编程的根本。”

这与第四章"概念完整性"的呼应: 第四章说概念完整性是系统设计中最重要的因素。第九章说,概念完整性不仅体现在架构层面,更体现在数据层面——当数据的表达形式被重新设计时,整个程序的概念结构会随之清晰。


三、膨胀的隐秘逻辑:为什么系统总在变胖

3.1 温水煮青蛙:渐进式侵蚀的四个阶段

布鲁克斯揭示了一个可怕的模式:规模膨胀从来不是一次性的灾难,而是渐进式的侵蚀。

阶段表现心理机制
第一阶段:无害的添加“就加几行代码”低估累积效应
第二阶段:指标的转移“核心达标就行,其他不管”局部优化替代全局目标
第三阶段:性能的崩溃系统变慢、资源耗尽问题爆发时已经积重难返
第四阶段:重构的代价重写比修改更便宜技术债务到期

OS/360的教训告诉我们,第三阶段的问题在第一阶段就已经埋下。当管理控制系统"既没有度量,也没有捕获这些问题"时,膨胀就像暗流,直到仿真运行时才浮出水面。

3.2 "不必要的规模"的三种现代形态

布鲁克斯所说的"不必要的规模",在今天有三种更隐蔽的形态:

形态1970年代的表现现代的表现
功能膨胀每个选项独立存在,重复代码多微服务过度拆分,每个服务都自带全套基础设施
依赖膨胀链接库无节制增长引入一个工具库,连带引入几十个间接依赖
数据冗余缓冲区重复分配多副本缓存、重复日志、未清理的临时数据

3.3 局部优化的组织根源

第九章最深刻的问题不是技术性的,而是组织性的:为什么明知会损害全局,个人仍然选择局部优化?

答案在于激励机制的错位:

  • 如果绩效考核基于"我的模块是否达标",而不是"系统整体是否最优"
  • 如果晋升取决于"我完成了多少功能",而不是"我为系统精简了什么"
  • 如果沟通成本高于局部优化的收益,那么局部优化就是理性的选择

这与第二章"人月神话"的呼应: 第二章说增加人手不能线性缩短工期,因为沟通成本二次方增长。第九章说,当沟通成本过高时,个人会选择局部优化来规避沟通——不是因为他们不关心全局,而是因为关心全局的代价太高了。


四、从控制到预防:现代工程的回应

4.1 云时代的回归与微服务的粗细之争

布鲁克斯时代的内存成本是显性的——每月每千字节12美元,直接体现在账单上。云时代的空间成本一度变得"隐形"——存储便宜、内存充裕,"削足适履"似乎成了过时的焦虑。

但成本从未真正消失,只是换了形态:

1970年代现代对应
内存租金云服务器实例费用
磁盘访问次数数据库查询次数与延迟
程序驻留空间容器镜像大小、冷启动时间
后台存储访问网络带宽、跨可用区流量

容器镜像大小的回归: 当容器镜像从几十兆膨胀到几个G时,部署时间、冷启动时间、节点资源占用都随之恶化。现代团队重新发现了"削足适履"的价值——多阶段构建、精简基础镜像、移除无用依赖,这些实践正是布鲁克斯"规模控制"思想的现代回响。

微服务架构本质上是对"功能换尺寸"策略的大规模应用:

细粒度选项(微服务过拆): 每个功能一个服务,独立部署、独立扩展。灵活性极高,但每个服务都自带通信框架、监控代理、配置管理——共享代码的缺失导致总空间(运维复杂度)爆炸。

粗粒度分组(适度聚合): 将相关功能聚合为领域服务,内部共享框架和库。灵活性降低,但每个服务的"自重"更轻,整体运维负担更小。

这与第九章原文的呼应: 布鲁克斯说"设计人员必须决定用户可选项目的粗细程度"。今天,架构师必须决定服务边界的粗细程度——同一个权衡,不同的战场。

4.2 数据重新表达的战略价值

布鲁克斯说"数据的表现形式是编程的根本"。在数据驱动的时代,这一洞察被放大到了极致:

传统数据库设计: 表结构反映业务实体,查询通过多表连接实现。

现代数据建模: 宽表、物化视图、列式存储——通过重新表达数据的物理结构,将运行时的连接计算转化为预计算,换取数量级的查询性能提升。

这不是索引优化或查询调优,而是布鲁克斯所说的"战略上的突破"——来自数据表现形式的重新表达。

4.3 给你的实践建议

个人层面:成为"有空间意识"的工程师

  • 在写代码前先问"有必要吗":这个功能真的需要吗?这个依赖真的不可替代吗?
  • 学会从代码中抽离,审视数据:当遇到复杂逻辑时,先问自己——如果重新设计数据结构,问题会不会变简单?
  • 掌握两种实现:对于常用功能,准备两个版本——一个追求速度,一个追求精简。

团队层面:建立"反膨胀"的规模文化

机制目的实施方式
整体规模预算防止局部达标、全局失控不仅限制核心模块,也限制总依赖数、总镜像大小
功能定义先行防止"踢皮球"式优化每个模块在限定大小的同时,必须有明确的功能边界文档
空间-时间评审在方案阶段就考虑取舍技术方案评审时,强制要求说明空间和时间的选择理由
公共构件库消除重复,共享优化成果团队内部维护常用功能的"快版"和"精简版"实现

组织层面:投资"全局最优"的基础设施

  • 调整绩效考核: 不仅考核"我的模块是否按时交付",也考核"我的模块对系统整体资源的影响"
  • 建立资源看板: 让团队实时看到系统的空间占用趋势,就像看测试覆盖率一样自然
  • 强制"瘦身迭代": 每个季度或半年,安排专门的迭代用于清理无用代码、移除冗余依赖、优化数据存储
  • 培训数据建模: 不仅培训编程语言和框架,更培训"如何重新表达数据以获得战略突破"

结语

布鲁克斯在第九章结尾没有给出豪言壮语,因为"削足适履"本身就是一场与膨胀本能的永恒对抗

但我想用布鲁克斯自己的一句话作为结尾——这句话可能是整本书中最被低估的洞察:

“给我看表数据,往往就不再需要流程图,程序结构是非常清晰的。实际上,数据的表现形式是编程的根本。”

在1975年,这是一个关于内存优化的技术建议。在今天,这是关于系统复杂性本质的哲学洞察。

无论是控制程序大小、设计微服务边界,还是构建数据平台——当我们被复杂性淹没时,答案往往不在"怎么做"的流程图里,而在"是什么"的数据结构中。 重新表达数据,就是重新理解问题。理解问题,才能找到真正优雅的解决方案。

诺亚方舟的教训从未过时:在有限的空间里装载整个世界,需要的不是更大的方舟,而是更聪明的排列。

已经博主授权,源码转载自 https://pan.quark.cn/s/a4b39357ea24 ### TDS 2014示波器使用手册知识点总结 #### 一、TDS 1000B 和 TDS 2000B 系列数字存储示波器概述 - **产品系列**: TDS 1000B 和 TDS 2000B 是由 Tektronix 公司所研发并推出的数字存储示波器产品线。 - **功能定位**: 主要致力于为电子工程师以及研发人员提供具备高性能与高精度的信号测量设备。 - **应用领域**: 此类设备被普遍应用于教育机构、研发实验室以及工业生产过程中的测试环节。 #### 二、TDS 2014示波器基本操作与使用 - **开机与基本设置**: - 在启动设备时,必须确保仪器已经正确接地。 - 在使用之前,需要根据观察需求设定合适的屏幕亮度、对比度等显示参数。 - **通道选择与配置**: - 可以通过触摸显示屏或设备前面板上的按钮来选定需要进行的测量通道。 - 可依据实际需求来调整垂直灵敏度、水平时间基准等设置项。 - **触发设置**: - 触发模式包括自动、常态、单次等多种选择。 - 触发源与阈值设定涉及确定触发信号的具体来源及其电压阈值水平。 - **测量与分析功能**: - 提供多种自动测量功能选项,涵盖电压峰峰值、频率等参数的测量。 - 支持对波形进行数学运算,例如执行两个波形的相加或相减操作。 #### 三、TDS 2014示波器高级特性 - **波形捕获率**: - 波形捕获率越高,意味着在检测偶发事件方面的能力越强。 - **波形存储与回放**: - 支持将波形数据存储到内部存储单元或外部存储设备中。 - 用户能够随时调取先前保存的波形数据,以进行深入分析。 - *...
内容概要:本文聚焦2026年高教社杯全国大学生数学建模竞赛B题“无线电干扰源的快速自动定位与清除”,同时整合了多个数学建模与工程技术仿真研究资源,涵盖SEM广告投放策略优化、无人机协同路径规划、电力系统无功优化、微电网调度、负荷预测、电动汽车响应率建模等多个领域。其中重点详述了SEM广告投放策略的系统性建模,构建了从问题诊断、关键词分类、预算优化到不确定性环境下鲁棒决策的完整框架。提出基于成本—效益二维归一化的五类关键词划分方法(黄金词、重点词、潜力词、问题词、无效词),并建立了0-1整数规划与CVaR鲁棒优化模型,实现注册转化最大化与风险控制的平衡。文档还汇集了大量基于Matlab/Simulink的仿真资源,涉及智能优化算法、机器学习、信号处理、路径规划等方向,并配套提供代码与论文支持,形成跨学科的技术资源共享平台。; 适合人群:具备一定数据分析与建模基础,正在准备数学建模竞赛或从事科研工作的本科生、研究生及工程技术人员。; 使用场景及目标:①应用于数学建模竞赛备赛,学习多目标优化、分类模型、鲁棒决策等建模范式;②开展广告投放、电力调度、路径规划等领域的科研项目时借鉴模型构建与算法实现方法;③通过提供的Matlab/Python代码快速复现经典或前沿研究成果,提升科研效率与实践能力。; 阅读建议:此资源集合了多个独立研究主题,建议读者根据自身研究方向选择性阅读,重点关注模型构建逻辑与算法实现细节,并结合所提供的Matlab/Python代码进行实践验证,以加深理解与应用能力。
打开链接下载源码: https://pan.quark.cn/s/a89f7876a37d 将硅片上的电路管脚通过导线引至外部连接点,目的是为了与其他设备建立连接。封装类型指的是用于固定半导体集成电路芯片的外壳结构。这种外壳不仅承担着固定、密封、保护芯片以及改善电热特性等多重功能,同时通过芯片上的接触点利用导线连接至封装外壳的引脚,这些引脚再经由印刷电路板的线路与其他部件相连,从而完成芯片与外部电路的沟通。由于芯片必须与外界隔绝,以避免空气中杂质对电路造成腐蚀导致性能恶化,因此封装后的芯片也更为便于实施安装和运输。封装工艺的优劣直接关联到芯片自身特性和与之相接的PCB(衡量芯片封装技术水平的重要参照是芯片面积与封装面积的比例,这一比例越趋近于1则表示效果更佳。 【封装】在半导体产业中占据核心地位,其操作是将硅片上的电路端子借助导线连接至外部端口,以便与其他电子部件相接。封装的核心功能涵盖了固定、密封、保护芯片以及优化电热表现。封装外壳不仅作为芯片的物理防护层,更通过引脚将芯片与外部电路相连接,确保芯片功能的正常运作。封装的样式丰富多样,常见的有DIP(双列直插式封装)、SOP(小型封装)、SMD(表面贴装封装)、TO(晶体管封装)等。其中,TO-92是一种较为古老的晶体管封装方式,多用于小功率晶体管,其特征是在封装底部设有金属引脚,两侧各有两个引脚,外形类似字母“L”。 封装技术的革新直接影响芯片性能及其连接的PCB(印刷电路板)的工作效能。一个卓越的封装布局应尽可能减小芯片面积与封装面积的比率,从而提升封装的效率。除此之外,封装设计还需关注引脚的长度、间距、散热等要素,以减少信号传输的延迟,避免相互间的干扰,并确保良好的散热条件。封装技术的演进轨迹可从早期的TO封...
代码下载链接: https://pan.quark.cn/s/a4b39357ea24 依据所提供的文件资料,可以判断出这段代码与通过GPS数据计算电离层总电子含量(Total Electron Content, TEC)存在关联。尽管代码片段并不完整且包含了一些未完成的功能,但依然可以从现有资料中提取出一些关键性的知识点。 ### 1. 电离层总电子含量(TEC) **定义:** 电离层总电子含量(Total Electron Content, TEC)是指沿着信号传输路径单位面积上的电子总体数量,通常以TECU作为计量单位(1 TECU 等于 10^16 m^-2)。它作为研究电离层的重要指标之一,在卫星通信、导航系统以及遥感技术等领域具有关键性的应用意义。 **作用:** - **卫星通信与导航:** 掌握TEC数据有助于降低电离层对卫星信号的干扰,从而提升定位的精确度。 - **气象学与空间天气研究:** 通过监测TEC的动态变化,能够预测气象现象,特别是在太阳活动达到高峰的时期。 ### 2. GPS数据在TEC计算中的应用 **原理概述:** 电离层对GPS信号传播的主要影响表现为信号延迟现象。不同频率的GPS信号在穿过电离层时,由于受到不同电离层成分的作用会产生不同的延迟效果。因此,可以通过比较不同频率信号到达接收设备的时间差异来推算出电离层中的电子密度分布,进而得出TEC值。 **计算方法:** 一种常用的方法是通过双频观测数据来估算TEC。假设GPS接收设备接收到了两个不同频率的信号,比如L1和L2,它们分别位于1575.42 MHz和1227.6 MHz。通过分析这两个信号的相位差,可以消除大部分与接收设备相关的误差,从而精确地估算出电离层延...
内容概要:本文针对直流调速双闭环系统,深入研究了在考虑积分饱和退饱动态与负载扰动情况下的控制器参数鲁棒整定方法,并通过Simulink平台实现了完整的系统建模与仿真实验。文章系统阐述了电流环与转速环的控制结构设计,重点剖析了积分饱和现象对系统动态响应的不利影响,提出了有效的退饱和策略以抑制超调并加快恢复过程。在此基础上,构建了包含非线性环节和外部负载扰动的完整双闭环仿真模型,通过多工况对比仿真验证了所提出鲁棒参数整定方法的有效性,显著提升了系统在复杂工况下的稳定性、抗扰能力和动态品质。; 适合人群:具备自动控制原理、电机拖动及Simulink仿真基础的电气工程、自动化、机电一体化等领域的高校本科生、研究生、科研人员以及从事电机控制相关工作的工程技术人员。; 使用场景及目标:①应用于高校自动化类课程的教学实践与实验设计,深化学生对PID控制、双闭环调速系统工作机理及非线性问题处理方法的理解;②为工业领域直流驱动系统的控制器调试、参数优化与抗扰设计提供理论指导和技术验证手段;③支撑科研工作中对非线性补偿、鲁棒控制策略等先进控制理论的研究与应用拓展。; 阅读建议:建议读者结合提供的Simulink模型进行同步操作与参数调试,重点关注积分饱和的发生条件与退饱和模块的设计逻辑,通过设置不同的负载扰动场景开展对比仿真,深入理解参数变化对系统动态性能的影响规律,从而全面掌握高性能直流调速系统鲁棒设计的核心技术要点。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值