<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>没有银弹 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Tue, 08 Aug 2023 10:40:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>《人月神话》笔记：Brooks 用 OS/360 的学费换来的软件工程第一性原理</title>
      <link>https://ftmao.com/blog/bookstore/mythical-man-month-book-notes/</link>
      <pubDate>Tue, 08 Aug 2023 10:40:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/bookstore/mythical-man-month-book-notes/</guid>
      <description>&lt;h1 id=&#34;人月神话笔记brooks-用-os360-的学费换来的软件工程第一性原理&#34;&gt;《人月神话》笔记：Brooks 用 OS/360 的学费换来的软件工程第一性原理&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;目标读者：带过项目、估过排期、经历过&amp;quot;老板说加人就能赶上&amp;quot;的工程师和工程管理者。
参考书籍：Frederick P. Brooks Jr.《人月神话》（The Mythical Man-Month，1975 年初版，1995 年 20 周年纪念版），含 1986 年论文《没有银弹》（No Silver Bullet）。
阅读目标：不是复述一本 50 年前的书，而是把 Brooks 用 IBM OS/360 项目的巨额学费换来的几条&amp;quot;软件工程第一性原理&amp;quot;蒸馏成今天还能直接用的判断准则。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一焦油坑这本书从哪里长出来的&#34;&gt;一、焦油坑：这本书从哪里长出来的&lt;/h2&gt;
&lt;p&gt;书的第一章叫「焦油坑」（The Tar Pit），Brooks 用了一个古生物学意象：拉布雷亚沥青坑里，猛犸、剑齿虎、恐龙——越是强壮的野兽，挣扎得越猛烈，陷得越深。&lt;strong&gt;大型系统编程就是这样一个焦油坑：没有哪支队伍特别笨，但大家都在里面挣扎，而且越挣扎陷得越深。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这句话不是文学修辞，是作者的身份声明。Brooks 是 IBM System/360 大型机项目的经理，随后又是其操作系统 &lt;strong&gt;OS/360&lt;/strong&gt; 的项目经理——这是 1960 年代人类历史上最大的软件项目之一，几千人年、超支数倍、进度失控、bug 成山。1964 年 IBM 老板小沃森问他项目为什么管成这样，他答不上来；几个月后他离开 IBM 去北卡大学建计算机系，把这次失败翻来覆去想了十年，1975 年写出这本书。&lt;/p&gt;
&lt;p&gt;所以读这本书的正确姿势是：&lt;strong&gt;这不是一个管理学教授在总结别人的案例，是一个搞砸过史上最大软件项目的人在写尸检报告。&lt;/strong&gt; 书里每一条论断背后，都是 OS/360 真金白银的教训。这也是为什么这本书快 50 年了还不过时——硬件换了五代，语言换了几轮，但&amp;quot;人怎么组织起来写大软件&amp;quot;这个问题的底层结构，几乎没变。&lt;/p&gt;
&lt;p&gt;全书论点可以用一句话串起来：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;软件项目的失败，绝大多数不是技术失败，而是对&amp;quot;编程这项活动的本质&amp;quot;估计错误的失败——错估了沟通成本、错估了复杂度的来源、错估了设计与实现的相对价值。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二人月神话人月是不可互换的&#34;&gt;二、人月神话：人月是不可互换的&lt;/h2&gt;
&lt;p&gt;书名即论点。&lt;strong&gt;人月（man-month）——用人乘以月来度量工作量——是一个神话，因为它暗含一个错误前提：人和月可以互换。&lt;/strong&gt; 10 个人干 1 个月，和 1 个人干 10 个月，不是一回事。&lt;/p&gt;
&lt;p&gt;Brooks 的论证是一个漂亮的分类学，按任务的&lt;strong&gt;可分解性&lt;/strong&gt;拆开：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;完全可分解、无需沟通的任务&lt;/strong&gt;：比如收麦子、筛数据。这类任务人月确实可互换，人加倍时间减半。可惜软件里几乎没有这种任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可分解但需要沟通的任务&lt;/strong&gt;：大部分编码工作属于此类。增加人手，沟通成本随之而来，收益开始打折。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可分解但需要复杂沟通与再培训的任务&lt;/strong&gt;：沟通成本开始吞噬新增人手带来的产能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;完全不可分解、有严格次序依赖的任务&lt;/strong&gt;：比如调试（本质上是顺序的），比如生孩子——九个月，几个母亲也压缩不了。软件里的系统设计和集成调试大量属于此类。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    T[&amp;#34;软件任务&amp;#34;] --&amp;gt; Q{&amp;#34;能否分解为&amp;lt;br/&amp;gt;无需沟通的子任务?&amp;#34;}
    Q --&amp;gt;|&amp;#34;能(极少: 收麦子型)&amp;#34;| A[&amp;#34;人月近似可互换&amp;lt;br/&amp;gt;人加倍, 工期减半&amp;#34;]
    Q --&amp;gt;|&amp;#34;不能(绝大多数)&amp;#34;| Q2{&amp;#34;主要成本是什么?&amp;#34;}
    Q2 --&amp;gt;|&amp;#34;沟通与协调&amp;#34;| B[&amp;#34;加人收益递减&amp;lt;br/&amp;gt;沟通路径数 = n乘n减1再除2&amp;#34;]
    Q2 --&amp;gt;|&amp;#34;严格次序依赖&amp;lt;br/&amp;gt;设计、调试、集成&amp;#34;| C[&amp;#34;加人完全无效&amp;lt;br/&amp;gt;九个月生不出孩子&amp;#34;]
    style C fill:#ffcccc
    style A fill:#e8f5e9&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;沟通成本那条值得算一笔小账：n 个人两两沟通，路径数是 n(n-1)/2。3 个人是 3 条，7 个人是 21 条，10 个人是 45 条。&lt;strong&gt;人数翻倍，沟通路径数大约翻两番。&lt;/strong&gt; 如果每次协作都要开会、对齐、等回复，人越多，每个人写代码的时间占比越低。这就是为什么 Brooks 说&amp;quot;用人月作为度量，等于默认了一个只在收麦子时成立的假设&amp;quot;。&lt;/p&gt;
&lt;p&gt;这条原理的一个直接推论，常常被忽略：&lt;strong&gt;进度落后的项目，往往不是人太少，而是人太多&lt;/strong&gt;——沟通结构已经把产能吃掉了，这时候减人反而可能提速。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三brooks-定律向延期的项目加人只会让它更晚&#34;&gt;三、Brooks 定律：向延期的项目加人，只会让它更晚&lt;/h2&gt;
&lt;p&gt;这是全书最出名的一句话，1975 年提出，后来被叫成 Brooks 定律（Brooks&amp;rsquo;s Law）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Adding manpower to a late software project makes it later.（向一个已经延期的软件项目增加人手，只会让它更晚。）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为什么&amp;quot;加人赶工&amp;quot;这个管理者最直觉的动作是错的？Brooks 拆了三层成本：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;培训成本&lt;/strong&gt;：新人不能立刻干活。他们要先学项目的目标、架构、既有代码、开发流程——而教他们的人，正是团队里本来在干活的老手。老手的时间被培训占用，团队短期产能不升反降。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;沟通成本&lt;/strong&gt;：就是上一节的 n(n-1)/2。加人后，任务要重新划分、接口要重新对齐，原本两个人口头约定的事，现在要写文档、开会。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;任务重划分成本&lt;/strong&gt;：很多任务被打断重拆时，边界上的工作要重做；有些任务根本拆不动（次序依赖的部分），能拆出去的部分往往是最不需要人的部分。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    subgraph 加人前
        A1[&amp;#34;团队产能 100%&amp;lt;br/&amp;gt;全部用于推进项目&amp;#34;]
    end
    subgraph 加人后短期
        B1[&amp;#34;老手产能下降&amp;lt;br/&amp;gt;抽时间培训新人&amp;#34;] --&amp;gt; B3[&amp;#34;净产能低于加人前&amp;#34;]
        B2[&amp;#34;新人产能为负&amp;lt;br/&amp;gt;提问、犯错、需要返工&amp;#34;] --&amp;gt; B3
        B4[&amp;#34;沟通路径数平方增长&amp;lt;br/&amp;gt;对齐成本吞噬产出&amp;#34;] --&amp;gt; B3
    end
    subgraph 加人后长期
        C1[&amp;#34;若项目不取消&amp;lt;br/&amp;gt;数月后产能才可能恢复&amp;lt;br/&amp;gt;但死线已过&amp;#34;]
    end
    A1 -.-&amp;gt;|&amp;#34;管理者直觉: 产能应线性上升&amp;#34;| B1
    B3 --&amp;gt; C1
    style B3 fill:#ffcccc&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;书里还有一个配套观察，杀伤力同样大：&lt;strong&gt;项目是怎样延期一年的？一天一天延的。&lt;/strong&gt;（How does a project get to be a year late? One day at a time.）大灾难不是突然降临的，是每天落后一点点、每次例会都&amp;quot;下周能追上&amp;quot;累积出来的。所以 Brooks 主张里程碑必须&lt;strong&gt;具体、锋利、公开&lt;/strong&gt;——&amp;ldquo;编码完成 90%&amp;ldquo;不是里程碑，是遮羞布；&amp;ldquo;模块通过全部单元测试并合入主库&amp;quot;才是。&lt;/p&gt;
&lt;p&gt;对今天的映射几乎不用翻译：每个 deadline 前两周&amp;quot;借调支援&amp;quot;的场景，都是 Brooks 定律的现场重演。正确的动作恰恰相反——&lt;strong&gt;砍掉 20% 的范围，比增加 20% 的人有效得多。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四概念完整性与外科手术队伍&#34;&gt;四、概念完整性与外科手术队伍&lt;/h2&gt;
&lt;h3 id=&#34;41-最重要的系统属性不是功能是概念完整性&#34;&gt;4.1 最重要的系统属性不是功能，是概念完整性&lt;/h3&gt;
&lt;p&gt;Brooks 认为，一个系统给用户呈现的东西里，&lt;strong&gt;概念完整性（conceptual integrity）是最重要的品质&lt;/strong&gt;——系统各处必须体现同一套设计哲学，一致、连贯、正交。用户学透三个概念就能推测出三十个行为的系统，远好过每个功能都自说自话的系统。&lt;/p&gt;
&lt;p&gt;但概念完整性有一个组织上的代价：&lt;strong&gt;它无法由委员会设计出来。&lt;/strong&gt; 民主设计出来的系统，是每个聪明人都塞进了自己最爱的特性的系统——功能很多，灵魂没有。所以 Brooks 给了一个政治不正确但极其诚实的结论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;概念完整性要求设计出自一个人，或极少数同心同德的人。为了完整性，必须接受贵族专制（aristocracy），放弃民主。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这不等于独裁者包揽一切。Brooks 的关键区分是：&lt;strong&gt;体系结构（architecture）与实现（implementation）分离&lt;/strong&gt;。架构师定义&amp;quot;系统对用户是什么样&amp;rdquo;——接口、语义、概念模型；大量实现者在架构约束下尽情发挥创造力。OS/360 的教训是：架构师也必须克制，架构文档里不该规定任何&amp;quot;实现细节&amp;rdquo;，否则就是把实现者的创造力抢走、把架构变成瓶颈。&lt;/p&gt;
&lt;p&gt;Unix 是这条原则最著名的正面样本（Brooks 自己也拿它举例）：一切皆文件、程序是过滤器、文本流为接口——概念少到极致，组合力大到极致。&lt;/p&gt;
&lt;h3 id=&#34;42-外科手术队伍小团队怎么做大事&#34;&gt;4.2 外科手术队伍：小团队怎么做大事&lt;/h3&gt;
&lt;p&gt;如果人少才有一致性，人少又怎么完成大项目？Brooks 的回答是全书我最喜欢的组织设计：&lt;strong&gt;外科手术队伍（surgical team）&lt;/strong&gt;——不是&amp;quot;人人都是全才&amp;quot;的平等团队，而是像一台外科手术那样，一个主刀，其余所有人都是为了让主刀的每一分钟都高效而存在。&lt;/p&gt;
&lt;p&gt;10 人编制大致是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;外科医生（首席程序员）&lt;/strong&gt;：亲手定义功能与性能规格，亲手写核心代码，对系统负全责。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;副手（copilot）&lt;/strong&gt;：能替代外科医生做任何事，是他的讨论对象、保险丝和备份，但不抢方向盘。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;管理员&lt;/strong&gt;：处理钱、人、场地、设备这些非技术事务——外科医生不该为报销分心。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编辑/秘书&lt;/strong&gt;：外科医生口述或手写，编辑负责把文档变成清晰、统一、可发布的正式文档。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;程序职员&lt;/strong&gt;：维护所有代码版本、运行记录、测试数据——机器时间时代的&amp;quot;版本与构建管家&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具师&lt;/strong&gt;：为团队打造专用工具、脚本、测试设施。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;测试员&lt;/strong&gt;：根据规格写测试用例，并且&lt;strong&gt;从规格里找矛盾&lt;/strong&gt;——他是架构师的第一批批评者。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语言专家&lt;/strong&gt;：精通语言犄角旮旯的顾问，帮团队写出既优雅又高效的代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    S[&amp;#34;外科医生 首席程序员&amp;lt;br/&amp;gt;设计 + 核心代码 + 负全责&amp;#34;]
    C[&amp;#34;副手&amp;lt;br/&amp;gt;讨论对象与备份&amp;#34;]
    AD[&amp;#34;管理员&amp;lt;br/&amp;gt;钱、人、设备&amp;#34;]
    ED[&amp;#34;编辑&amp;lt;br/&amp;gt;文档产出与统一&amp;#34;]
    CL[&amp;#34;程序职员&amp;lt;br/&amp;gt;版本与运行记录&amp;#34;]
    TL[&amp;#34;工具师&amp;lt;br/&amp;gt;内部工具与设施&amp;#34;]
    TE[&amp;#34;测试员&amp;lt;br/&amp;gt;用例设计与规格挑刺&amp;#34;]
    LX[&amp;#34;语言专家&amp;lt;br/&amp;gt;语言技艺顾问&amp;#34;]
    C --&amp;gt; S
    AD --&amp;gt; S
    ED --&amp;gt; S
    CL --&amp;gt; S
    TL --&amp;gt; S
    TE --&amp;gt; S
    LX --&amp;gt; S
    style S fill:#fff3cd&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;注意这个结构的颠覆点：&lt;strong&gt;其他人不是外科医生的下属执行者，而是他的支撑系统。&lt;/strong&gt; 今天回头看，这是&amp;quot;10x 工程师团队&amp;quot;最早的严肃版本——结论不是&amp;quot;找 10 个 10x&amp;quot;，而是&amp;quot;&lt;strong&gt;让那个 10x 的人 100% 的时间都在做只有他能做的事&lt;/strong&gt;&amp;quot;。大项目怎么办？分成若干段，每段一个外科手术队伍，段与段之间用架构对齐——又回到概念完整性。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五第二系统效应你最危险的作品是第二个&#34;&gt;五、第二系统效应：你最危险的作品是第二个&lt;/h2&gt;
&lt;p&gt;全书最精妙的心理学洞察之一：&lt;strong&gt;第二系统效应（second-system effect）&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一个人在设计他的第二个系统时，会把它做成最危险的系统——因为他会把第一个系统里没用上的所有想法，全都塞进去。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;机制是这样的：设计第一个系统时，人是谨慎的、不自信的，处处收敛；那些&amp;quot;如果再来一次我一定要加&amp;quot;的念头，被一条条记在心里的清单上。设计第二个系统时，自信来了，约束松了，那张清单被整体倒出来——加上第一版遗留功能的修饰欲，结果是&lt;strong&gt;功能膨胀、概念混杂、复杂度失控&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Brooks 的自白是：OS/360 就是大量设计者的&amp;quot;第二系统&amp;quot;（多数人的第一系统是 1410、7090 系列），所以它的链接器、它的各种设施，都堆满了&amp;quot;这次终于可以做了&amp;quot;的东西。而他给架构师的建议只有一句：&lt;strong&gt;为每个功能问一句&amp;quot;它值它占用的那份复杂度预算吗&amp;quot;&lt;/strong&gt;；并且始终意识到自己在设计第几个系统——第三个系统的设计师，往往才第一次有真正的克制能力。&lt;/p&gt;
&lt;p&gt;工程映射：每个&amp;quot;重写 2.0&amp;quot;项目都是第二系统效应的高危现场。旧系统的痛点清单天然会被翻译成新系统的功能清单，而旧系统&amp;quot;为什么不支持 X&amp;quot;的答案（往往是成本，不是疏忽）在重写时被遗忘。&lt;strong&gt;重写立项评审时，把&amp;quot;砍掉的功能清单&amp;quot;和&amp;quot;新增的功能清单&amp;quot;摆在一起看，能救命。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六计划抛弃原型第一个版本注定要扔&#34;&gt;六、计划抛弃原型：第一个版本注定要扔&lt;/h2&gt;
&lt;p&gt;原话极不客气：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Plan to throw one away; you will, anyhow.（计划抛弃一个吧；反正你一定会抛弃的。）&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;意思是：你做的第一个版本，无论多用心，都是&amp;quot;试验品&amp;quot;——只有做完它，你才真正理解需求、理解约束、理解用户真正要什么。管理层如果不&amp;quot;计划&amp;quot;抛弃它，它就会被当作产品硬撑下去，背着一个为学习而生的架构进入维护地狱。&lt;/p&gt;
&lt;p&gt;这句话常被误读为&amp;quot;随便写一版就行&amp;quot;。Brooks 的本意严格得多：&lt;strong&gt;抛弃是计划内的，所以要为&amp;quot;抛弃&amp;quot;设计&lt;/strong&gt;——原型和生产系统用不同的人力配比、不同的质量预期、不同的心态；原型的使命是最大化学习，不是最大化寿命。后来的演进还有一条：&lt;strong&gt;唯一比&amp;quot;计划抛弃&amp;quot;更贵的，是假装不用抛弃。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这条思想后来开枝散叶：快速原型、MVP、以及 Brooks 自己在《没有银弹》里提出的&lt;strong&gt;增量式构建（grow, not build）&lt;/strong&gt;——软件不该是&amp;quot;建造&amp;quot;出来的，该是&amp;quot;生长&amp;quot;出来的：先让一个能跑的最小骨架活着，然后每加一个功能都保持系统可运行。1995 年纪念版里他承认，当年&amp;quot;抛弃一个&amp;quot;的说法被他自己修正为更平滑的增量演化，但内核没变：&lt;strong&gt;不要指望第一枪就命中，把迭代当成常态写进计划。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七文档与工作手册被遗忘的主角&#34;&gt;七、文档与工作手册：被遗忘的主角&lt;/h2&gt;
&lt;p&gt;这本书有个今天读来格外超前的观点：&lt;strong&gt;项目经理最重要的日常工作是文档，不是代码。&lt;/strong&gt; Brooks 花了整整一章讲「项目工作手册」（project workbook）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;它是什么&lt;/strong&gt;：项目所有正式文档的集合——目标、规格、进度、接口定义、会议纪要、变更记录。它不是档案柜，是项目的&lt;strong&gt;活的中枢&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么必须有&lt;/strong&gt;：第一，写作强制清晰——&amp;ldquo;写在纸上的决策，模糊性会自己暴露&amp;rdquo;，很多争吵在落成文字那一刻就解决了；第二，文档是沟通结构的载体，几百人的项目里，工作手册是唯一能让&amp;quot;每个人看到同一本事实&amp;quot;的装置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;怎么维护&lt;/strong&gt;：所有变更都要进手册，手册必须人人可得、持续更新（OS/360 时代用缩微胶片分发，他特意讨论了每日更新机制——放今天就是 wiki/文档站）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配套还有一条 OS/360 的组织创新：&lt;strong&gt;让文档成为规格的唯一权威形态&lt;/strong&gt;。架构师写正式的外部规格说明，实现中出现歧义时，由架构师裁决并&lt;strong&gt;把裁决写回规格&lt;/strong&gt;——规格永远是最新事实，不是&amp;quot;最初的美好愿望&amp;quot;。&lt;/p&gt;
&lt;p&gt;今天的映射一目了然：ADR（架构决策记录）、design doc 评审、&amp;ldquo;接口以文档为准而非以聊天为准&amp;rdquo;，全是工作手册的现代转世。Brooks 在 1975 年就说清楚了我们 2020 年代还在学的事：&lt;strong&gt;异步的、成文的沟通，是大团队唯一可扩展的沟通。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八没有银弹本质复杂度与偶然复杂度&#34;&gt;八、没有银弹：本质复杂度与偶然复杂度&lt;/h2&gt;
&lt;p&gt;1986 年，Brooks 发表了那篇比书本身更著名的论文：「没有银弹——软件工程中本质与偶然的问题」（No Silver Bullet: Essence and Accidents of Software Engineering），1995 年纪念版收入书中。&lt;/p&gt;
&lt;p&gt;核心论断：&lt;strong&gt;没有任何一项技术或管理进步，能在十年内让软件生产率提高一个数量级。&lt;/strong&gt; 因为软件的困难要分两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质复杂度（essential）&lt;/strong&gt;：问题域本身固有的复杂度——概念结构必须精确、一致、完整；软件是&amp;quot;纯粹的思想制品&amp;quot;，它的复杂度不会因为换工具而消失。就像银弹能杀狼人，但软件工程里没有狼人——没有一个叫&amp;quot;技术&amp;quot;的妖怪一枪打死就天下太平。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;偶然复杂度（accidental）&lt;/strong&gt;：我们制造过程附带的复杂度——机器慢、语言啰嗦、工具难用、环境配置地狱。&lt;strong&gt;这部分是可以消灭的&lt;/strong&gt;，而且历史上已经消灭了大部分：高级语言干掉了汇编的偶然复杂度，分时系统干掉了批处理的排队等待，统一硬件平台干掉了移植地狱。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Brooks 的关键预测逻辑是：到 1986 年，偶然复杂度已经被压缩到不是主要矛盾了——剩下的硬骨头几乎全是本质复杂度，而&lt;strong&gt;本质复杂度不响应任何&amp;quot;银弹&amp;quot;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;那怎么办？论文给出了四条&amp;quot;有希望的铜弹&amp;quot;，条条在后来兑现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;买，别造&lt;/strong&gt;（buy vs. build）：能买现成软件就别自己写——自己写的那部分才承载本质复杂度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需求精炼与快速原型&lt;/strong&gt;：最难的本质问题是&amp;quot;搞清楚到底要造什么&amp;quot;，用原型和用户一起把需求逼出来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增量式生长&lt;/strong&gt;（grow, not build）：系统永远保持可运行，小步叠加。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;培养伟大的设计师&lt;/strong&gt;：软件生产率的最大方差来自人——顶尖设计师和普通设计师的差距是数量级的，把培养设计师当成组织的核心投资。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1986 年之后的四十年基本在给这篇论文做注脚：面向对象、组件化、开源生态、云、低代码，每一波都消灭了新的偶然复杂度，每一波之后项目照样的难——因为难的那部分从来不在工具里，在&amp;quot;我们要造的东西本身&amp;quot;里。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九20-周年纪念版brooks-的自我检讨&#34;&gt;九、20 周年纪念版：Brooks 的自我检讨&lt;/h2&gt;
&lt;p&gt;1995 年纪念版最珍贵的部分，是 Brooks 回头看自己二十年前的论断，一条条打分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;仍然坚信的&lt;/strong&gt;：概念完整性是系统最重要的品质；人月不可互换；加人让延期项目更晚；工作手册必不可少；第二系统效应真实存在。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;修正的&lt;/strong&gt;：「计划抛弃一个」太粗暴，更准确的表述是增量演化（grow）；结构化编程、面向对象属于消灭偶然复杂度，不是银弹——这点他赌对了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;认错的&lt;/strong&gt;：他当年推崇&amp;quot;信息隐藏到团队之间也互相保密&amp;quot;的做法，后来承认过度了——Parnas 的信息隐藏原则适用于模块接口，不该用来隔离团队之间的知识。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;被时代证明最对的&lt;/strong&gt;：对&amp;quot;伟大设计师&amp;quot;的押注。20 年后他更确信：软件质量的天花板由少数顶尖设计者决定，组织的头等大事是发现他们、培养他们、别用流程磨平他们。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种&amp;quot;作者亲自给旧书做 code review&amp;quot;的结构，本身就是对全书精神的践行：&lt;strong&gt;把二十年前的决策放到今天的光下重新评审，而不是假装当年的自己永远正确。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十落地实践我自己在用的四条&#34;&gt;十、落地实践：我自己在用的四条&lt;/h2&gt;
&lt;p&gt;这本书不是读完就完的，我把其中几条固化成了自己带项目时的检查动作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;报排期时先分类任务&lt;/strong&gt;。任何估算之前，先问&amp;quot;这块工作能不能无沟通地并行拆开&amp;quot;。拆不动的部分（联调、设计、疑难 bug），单独列出来按顺序排，并且明确告诉需求方：这部分加人不解决问题，加人只会更慢。把 Brooks 定律提前说出来，比延期之后再解释有效得多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;里程碑只写&amp;quot;可验证的事&amp;quot;&lt;/strong&gt;。排期表里禁止出现&amp;quot;开发完成 80%&amp;ldquo;这类状态词，全部换成&amp;quot;接口联调通过&amp;quot;&amp;ldquo;性能压测达标&amp;quot;这种第三方可验证的硬节点。项目是一天一天延期的，锋利的里程碑是让&amp;quot;每天的小落后&amp;quot;无处藏身。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重写项目先审&amp;quot;砍掉清单&amp;rdquo;&lt;/strong&gt;。任何重构、2.0 立项，评审材料里必须有两栏：新系统不做什么、为什么不做。没有砍掉清单的重写方案，默认是第二系统效应发作，打回。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;护住团队里的&amp;quot;外科医生&amp;rdquo;&lt;/strong&gt;。识别出那个承担核心设计的人，然后系统性地替他挡事：杂会替他推掉、文档有人帮他整理、工具不顺有人帮他修。他的每一分钟专注时间，就是整个团队的产能上限。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;四条背后其实是同一个原则，也是这本书教我的最重要的一件事：&lt;strong&gt;软件工程里大多数&amp;quot;管理动作&amp;quot;的反面才是对的——加人不如减人，催进度不如砍范围，民主设计不如贵族专制，憋大招不如小步生长。&lt;/strong&gt; Brooks 在五十年前就把这些&amp;quot;反直觉&amp;quot;写成了定理，我们要做的只是别再交一遍学费。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十一带走的清单&#34;&gt;十一、带走的清单&lt;/h2&gt;
&lt;p&gt;如果只能记住几件事，记这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;人月不可互换&lt;/strong&gt;。报工期前先问：这个任务属于&amp;quot;收麦子型&amp;quot;还是&amp;quot;生孩子型&amp;quot;？后者加人无用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brooks 定律&lt;/strong&gt;：延期的项目加人只会更晚。赶工的正确动作是砍范围、保核心，不是借调支援。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;里程碑要锋利&lt;/strong&gt;：&amp;ldquo;完成 90%&amp;ldquo;不是进度，是幻觉；只有&amp;quot;可验证、不可含糊&amp;quot;的节点才是进度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;概念完整性 ＞ 功能数量&lt;/strong&gt;。架构出自一人或极少数人；架构师管&amp;quot;系统是什么样&amp;rdquo;，实现者管&amp;quot;怎么造出来&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;警惕第二系统效应&lt;/strong&gt;：重写立项时，先审&amp;quot;砍掉清单&amp;quot;，再审&amp;quot;新增清单&amp;quot;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计划抛弃原型&lt;/strong&gt;：第一版的使命是学习；要么计划抛弃它，要么被它拖死。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文档是项目的中枢&lt;/strong&gt;：写下来，模糊会自己暴露；规格是唯一权威，裁决要写回规格。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有银弹&lt;/strong&gt;：工具的进步只消灭偶然复杂度；本质复杂度只能靠更好的需求（原型）、更好的生长方式（增量）、更好的人（设计师）来对付。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;投资顶尖设计师&lt;/strong&gt;：人员方差是软件生产率里最大的方差，这件事 1975 年成立，今天更成立。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Frederick P. Brooks Jr., &lt;em&gt;The Mythical Man-Month: Essays on Software Engineering&lt;/em&gt;, Anniversary Edition, Addison-Wesley, 1995（含《没有银弹》全文及作者 20 年回顾）。&lt;/li&gt;
&lt;li&gt;Frederick P. Brooks Jr., &amp;ldquo;No Silver Bullet: Essence and Accidents of Software Engineering&amp;rdquo;, &lt;em&gt;Computer&lt;/em&gt;, 1987（1986 年原始论文）。&lt;/li&gt;
&lt;li&gt;Frederick P. Brooks Jr., &lt;em&gt;The Design of Design&lt;/em&gt;, Addison-Wesley, 2010（Brooks 晚年对&amp;quot;设计&amp;quot;本身的系统思考，可视作本书续篇）。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
