<?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%8C%81%E7%BB%AD%E4%BA%A4%E4%BB%98/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Fri, 08 Sep 2023 10:40:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/%E6%8C%81%E7%BB%AD%E4%BA%A4%E4%BB%98/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>《持续交付》笔记：每步可退，把集成风险日常化</title>
      <link>https://ftmao.com/blog/bookstore/continuous-delivery-book-notes/</link>
      <pubDate>Fri, 08 Sep 2023 10:40:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/bookstore/continuous-delivery-book-notes/</guid>
      <description>&lt;h1 id=&#34;持续交付笔记每步可退把集成风险日常化&#34;&gt;《持续交付》笔记：每步可退，把集成风险日常化&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;《持续交付》（Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation）是 Jez Humble 和 David Farley 2010 年的作品，拿过 2011 年的 Jolt 大奖。这本书可以说是 DevOps 运动的奠基文献之一——后来《DevOps Handbook》《Accelerate》这些书，根子上都能追溯到这里。&lt;/p&gt;
&lt;p&gt;全书 500 多页，核心其实就一个问题：&lt;strong&gt;怎么让&amp;quot;把软件放到生产环境&amp;quot;这件事，从一年几次的高风险仪式，变成随时可以按一下按钮的平常操作？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我读完最大的感受是：这本书表面讲工具和流程，骨子里讲的是一种风险管理哲学——&lt;strong&gt;不消除风险，而是把风险切碎、摊平到每一天&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;/p&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 TB
    subgraph P[&amp;#34;核心哲学：把风险日常化&amp;#34;]
        PHIL[&amp;#34;&amp;#39;If it hurts,&amp;lt;br/&amp;gt;do it more often&amp;#39;&amp;#34;]
    end
    subgraph PL[&amp;#34;部署流水线 Deployment Pipeline&amp;#34;]
        S1[&amp;#34;① 提交阶段&amp;lt;br/&amp;gt;编译 + 单元测试&amp;lt;br/&amp;gt;分钟级反馈&amp;#34;]
        S2[&amp;#34;② 自动化验收&amp;lt;br/&amp;gt;验收测试 + 容量/安全测试&amp;lt;br/&amp;gt;小时级反馈&amp;#34;]
        S3[&amp;#34;③ 手工验证&amp;lt;br/&amp;gt;UAT / 探索性测试 / 演示&amp;#34;]
        S4[&amp;#34;④ 发布&amp;lt;br/&amp;gt;点按钮，随时可发&amp;#34;]
        S1 --&amp;gt; S2 --&amp;gt; S3 --&amp;gt; S4
    end
    subgraph F[&amp;#34;支撑地基&amp;#34;]
        F1[&amp;#34;配置管理&amp;lt;br/&amp;gt;一切皆版本控制&amp;#34;]
        F2[&amp;#34;自动化测试金字塔&amp;#34;]
        F3[&amp;#34;主干开发 + 特性开关&amp;#34;]
    end
    PHIL --&amp;gt; PL
    F --&amp;gt; PL&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这本书的立论链条是这样的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;软件发布之所以痛苦，是因为它&lt;strong&gt;罕见&lt;/strong&gt;——几个月才发一次，每次集成了几百个变更，出问题没法定位；&lt;/li&gt;
&lt;li&gt;解决思路不是&amp;quot;更小心地发布&amp;quot;，而是&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;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：这个逻辑其实和健身一个道理——很久不运动，偶尔跑一次十公里肯定受伤；每天跑两公里反而没事。发布也一样，&amp;ldquo;少做&amp;quot;不是降低风险的办法，&amp;ldquo;把每次做小&amp;quot;才是。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二if-it-hurts-do-it-more-often全书最反直觉的一句话&#34;&gt;二、&amp;ldquo;If it hurts, do it more often&amp;rdquo;：全书最反直觉的一句话&lt;/h2&gt;
&lt;p&gt;书里有一句被广泛引用的话：&lt;strong&gt;&amp;ldquo;如果某件事让你痛苦，那就更频繁地去做它&amp;rdquo;&lt;/strong&gt;（If it hurts, do it more often, and bring the pain forward）。&lt;/p&gt;
&lt;p&gt;直觉上，痛苦的事应该少做。但作者的论证是：痛苦的根源是&lt;strong&gt;批量太大、间隔太久&lt;/strong&gt;。以集成为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个程序员各写两周代码再合并，冲突一大堆，合并花两天——于是大家说&amp;quot;少合并&amp;rdquo;；&lt;/li&gt;
&lt;li&gt;正确的解法恰恰相反：&lt;strong&gt;每天合并多次&lt;/strong&gt;，每次冲突只有几行，顺手就解了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样的道理适用于：数据库迁移、发布上线、甚至和客户的沟通。频率提高会逼着你把流程自动化、把每一步做小，而&amp;quot;小&amp;quot;本身就是最好的风险对冲。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;踩坑记录（书外）&lt;/strong&gt;：我待过的一个团队，发布周期是一个月一次，每次发布日都要通宵，发布完还要留人值班一周&amp;quot;灭火&amp;rdquo;。所有人的共识是&amp;quot;发布太危险，得再慎重些&amp;quot;——于是变更冻结期越来越长，每次积压的变更越来越多，发布越来越危险。这是典型的&lt;strong&gt;用制造问题的方式解决问题&lt;/strong&gt;。后来换了 CTO 强推两周一次、再到一周一次，逼着团队把部署脚本自动化、把回滚预案做出来，半年后发布变成了一个普通下午就能做的事。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：&amp;ldquo;痛苦&amp;quot;是个信号，但它指示的方向经常和直觉相反。看到团队里某件事人人回避，正确的反应不是绕着走，而是问：能不能把它自动化、高频化、常态化？&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三部署流水线每个提交都是可发布候选&#34;&gt;三、部署流水线：每个提交都是可发布候选&lt;/h2&gt;
&lt;p&gt;这是全书最核心的工程概念。部署流水线（deployment pipeline）的正式定义是：&lt;strong&gt;从代码提交到生产发布之间，所有验证步骤的自动化呈现&lt;/strong&gt;。&lt;/p&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
    C[&amp;#34;提交 Commit&amp;lt;br/&amp;gt;触发流水线&amp;#34;] --&amp;gt; B[&amp;#34;① 构建 + 单元测试&amp;lt;br/&amp;gt;编译 / 静态检查&amp;lt;br/&amp;gt;几分钟内出结果&amp;#34;]
    B --&amp;gt; A[&amp;#34;② 自动化验收测试&amp;lt;br/&amp;gt;面向业务的端到端场景&amp;lt;br/&amp;gt;在类生产环境跑&amp;#34;]
    A --&amp;gt; U[&amp;#34;③ 手工验证&amp;lt;br/&amp;gt;UAT / 探索性测试&amp;lt;br/&amp;gt;非功能需求确认&amp;#34;]
    U --&amp;gt; R[&amp;#34;④ 发布&amp;lt;br/&amp;gt;同一构建产物&amp;lt;br/&amp;gt;一键部署到生产&amp;#34;]
    B -.-&amp;gt;|&amp;#34;失败即止&amp;#34;| X[&amp;#34;❌ 流水线终止&amp;lt;br/&amp;gt;修复优先于新功能&amp;#34;]
    A -.-&amp;gt;|&amp;#34;失败即止&amp;#34;| X&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;几个关键点，都是容易理解偏的：&lt;/p&gt;
&lt;h3 id=&#34;31-每个阶段都是质量关卡失败即止&#34;&gt;3.1 每个阶段都是质量关卡，失败即止&lt;/h3&gt;
&lt;p&gt;流水线的本质是&lt;strong&gt;递进式的信心建设&lt;/strong&gt;：便宜的、快的测试放前面（单元测试几秒出结果），贵的、慢的放后面（验收测试、性能测试）。任何一个阶段失败，这个构建版本就&amp;quot;死&amp;quot;了，不进入下一阶段。&lt;/p&gt;
&lt;p&gt;这带来一条重要的团队纪律：&lt;strong&gt;流水线红了，修复它就是最高优先级&lt;/strong&gt;——比写新功能优先。因为流水线红着的时候，后面所有人的提交都拿不到反馈，等于团队集体失明。书里管这个叫&amp;quot;不要带着broken的构建回家&amp;rdquo;。&lt;/p&gt;
&lt;h3 id=&#34;32-每次提交都产生一个可发布候选&#34;&gt;3.2 每次提交都产生一个可发布候选&lt;/h3&gt;
&lt;p&gt;这句话值得单独强调：&lt;strong&gt;流水线的每个成功产出都是 release candidate&lt;/strong&gt;。注意是&amp;quot;候选&amp;quot;不是&amp;quot;一定发&amp;quot;——它保证了技术上随时可以发，发不发是业务决策（这点在第六节展开）。&lt;/p&gt;
&lt;p&gt;做到这一点有个硬要求：&lt;strong&gt;部署到每个环境的必须是同一个构建产物&lt;/strong&gt;。测试环境用 A 包、生产环境重新打一个 B 包，等于你在生产环境跑了一个从没被验证过的东西——测试全白做了。正确的做法是：构建只发生一次，产出的二进制包（jar、镜像）在流水线里逐级晋升（promote），环境差异全部由外部配置注入。&lt;/p&gt;
&lt;h3 id=&#34;33-流水线的反馈速度是硬指标&#34;&gt;3.3 流水线的反馈速度是硬指标&lt;/h3&gt;
&lt;p&gt;提交阶段要在几分钟内给出结果——慢了就没人愿意等，大家开始绕过流程。验收测试可以慢一些，但也要控制在小时级。如果一个阶段慢到天天被跳过，那它不是&amp;quot;严格&amp;quot;，是&amp;quot;无效&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：流水线画出来都不难，难的是维护它的&amp;quot;纪律成本&amp;quot;。红了几天的流水线比没有流水线更糟——它教会团队的是&amp;quot;告警可以无视&amp;quot;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四自动化测试金字塔而不是冰淇淋筒&#34;&gt;四、自动化测试：金字塔而不是冰淇淋筒&lt;/h2&gt;
&lt;p&gt;书里的测试分层思想，后来被大家画成了著名的&amp;quot;测试金字塔&amp;quot;（Mike Cohn 提出，本书把它发扬光大了）：&lt;/p&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 TB
    subgraph 金字塔[&amp;#34;自动化测试金字塔（数量：下多上少；成本：下低上高）&amp;#34;]
        E2E[&amp;#34;少量：端到端 UI 测试&amp;lt;br/&amp;gt;慢、脆、维护贵&amp;#34;]
        ACC[&amp;#34;适量：验收/服务层测试&amp;lt;br/&amp;gt;面向业务行为&amp;lt;br/&amp;gt;不依赖 UI&amp;#34;]
        UNIT[&amp;#34;大量：单元测试&amp;lt;br/&amp;gt;毫秒级、定位精准&amp;#34;]
    end
    UNIT --&amp;gt; ACC --&amp;gt; E2E&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;书中几个至今仍然尖锐的观点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;验收测试要用业务语言写，由开发者、测试、业务三方共同拥有&lt;/strong&gt;。它不只是测试，更是&amp;quot;可执行的规格说明书&amp;quot;——需求变了，先改验收测试；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;别把测试挂在 UI 上&lt;/strong&gt;。UI 是系统里最不稳定的层，通过 UI 驱动的测试又慢又脆。验收测试应该打在 UI 之下的服务/API 层；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手工测试不会被消灭，但角色变了&lt;/strong&gt;：从&amp;quot;重复执行回归用例&amp;quot;变成&amp;quot;探索性测试、可用性评估&amp;quot;——机器做重复的，人做需要判断力的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;反面形态叫&amp;quot;冰淇淋筒&amp;quot;：大量手工测试 + 一堆脆弱的 UI 自动化 + 几乎没有单元测试。症状是测试跑一遍要一整天、失败了大半天定位不到问题、最后团队对测试结果失去信心开始无视红灯。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：测试金字塔真正的价值不在&amp;quot;比例&amp;quot;，在它背后的经济学：&lt;strong&gt;反馈越快、定位越准的测试越便宜，应该最多&lt;/strong&gt;。所有&amp;quot;冰淇淋筒&amp;quot;团队的问题，本质都是把测试成本结构搞反了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五增量式发布把风险一刀一刀切小&#34;&gt;五、增量式发布：把风险一刀一刀切小&lt;/h2&gt;
&lt;p&gt;这部分是全书我最服气的一章——它回答了一个实际问题：大功能开发要好几个月，总不能这几个月不发版吧？书里给的答案是&lt;strong&gt;把&amp;quot;部署&amp;quot;和&amp;quot;发布&amp;quot;解耦&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;51-主干开发--特性开关和长寿命分支说再见&#34;&gt;5.1 主干开发 + 特性开关：和长寿命分支说再见&lt;/h3&gt;
&lt;p&gt;业界常见的做法是&amp;quot;功能分支&amp;quot;：每个大功能拉一个分支，开发几个月再合并。书里的态度很明确：&lt;strong&gt;长寿命分支是持续交付的头号敌人&lt;/strong&gt;。分支活得越久，合并那天的集成爆炸越大——你只是把集成风险攒起来，并没有消除它。&lt;/p&gt;
&lt;p&gt;替代方案是&lt;strong&gt;主干开发（trunk-based development）&lt;/strong&gt;：所有人都频繁提交到主干（至少每天），没做完的大功能用**特性开关（feature toggle）**藏起来——代码已经在生产环境，但功能入口被开关挡住，用户看不见。&lt;/p&gt;
&lt;p&gt;这样做的好处是双重的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;集成每天都在发生，冲突永远是小的；&lt;/li&gt;
&lt;li&gt;&amp;ldquo;部署新代码&amp;quot;和&amp;quot;向用户开放功能&amp;quot;变成了两件独立的事。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代价也要认账：开关本身是技术债，上线后要记得清理；半成品代码要保证&amp;quot;编译得过、不破坏现有行为&amp;rdquo;，对代码组织（抽象分支、按业务边界拆分）有要求。&lt;/p&gt;
&lt;h3 id=&#34;52-蓝绿部署与金丝雀发布&#34;&gt;5.2 蓝绿部署与金丝雀发布&lt;/h3&gt;
&lt;p&gt;发布阶段的两个经典模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;蓝绿部署（blue-green deployment）&lt;/strong&gt;：维护两套生产环境。当前流量在&amp;quot;蓝&amp;quot;，新版本部署到&amp;quot;绿&amp;quot;，验证没问题就把流量切过去。出问题？切回来就是秒级回滚。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;金丝雀发布（canary release）&lt;/strong&gt;：先把新版本暴露给一小部分流量（比如 1% 的用户或一台服务器），盯着错误率和关键指标，没问题再逐步扩大范围。名字来自煤矿里的金丝雀——鸟先下井，出事人有时间撤。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两者的共同点：&lt;strong&gt;回滚能力内建在发布机制里&lt;/strong&gt;，而不是出事后临时想办法。书里有句话大意是：发布计划里最重要的一条是回滚计划，而回滚计划必须&lt;strong&gt;真的演练过&lt;/strong&gt;才算数——没演练过的回滚方案约等于没有。&lt;/p&gt;
&lt;h3 id=&#34;53-数据库变更expand-contract-模式&#34;&gt;5.3 数据库变更：expand-contract 模式&lt;/h3&gt;
&lt;p&gt;蓝绿部署最怕的拦路虎是数据库：两套环境共用一个库，schema 一变，新旧代码没法同时跑。书里的解法是&lt;strong&gt;expand-contract（扩张-收缩）模式&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Expand&lt;/strong&gt;：先做一次只做&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;Contract&lt;/strong&gt;：等所有在用版本都不依赖旧结构了，再单独做一次变更删掉旧列、旧表。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;核心思想一句话：&lt;strong&gt;每一次变更都向前向后兼容，让 schema 演进和应用部署可以分开走&lt;/strong&gt;。这也解释了为什么&amp;quot;上线一个大变更顺便重构一下表结构&amp;quot;是事故高发操作——你把两个本可以解耦的风险捆在了一起。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六配置与环境把环境也当代码管&#34;&gt;六、配置与环境：把环境也当代码管&lt;/h2&gt;
&lt;p&gt;这本书反复强调的一个纪律是：&lt;strong&gt;一切进版本控制&lt;/strong&gt;——不只是源代码，还包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构建脚本、部署脚本；&lt;/li&gt;
&lt;li&gt;应用配置（环境相关的那部分参数化）；&lt;/li&gt;
&lt;li&gt;数据库迁移脚本；&lt;/li&gt;
&lt;li&gt;环境本身的定义（后来演化成了 Infrastructure as Code，IaC）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;理由很朴素：如果环境的搭建靠&amp;quot;运维同学的记忆和一台手工调出来的服务器&amp;quot;，那你的测试环境和生产环境一定存在没人知道的差异，而每个差异都是一颗雷。书里对这种手工维护的服务器有个后来的流行叫法——&lt;strong&gt;宠物（pets） vs 牲畜（cattle）&lt;/strong&gt;：宠物有名字，病了要治；牲畜只有编号，病了换掉重来。环境应该朝&amp;quot;牲畜&amp;quot;方向走：不可变、可重建、随时销毁再拉起。&lt;/p&gt;
&lt;p&gt;配置管理上的一条实用原则：&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;p&gt;传统模式下，&amp;ldquo;什么时候发布&amp;quot;是技术团队说了算的——因为只有他们觉得&amp;quot;差不多了&amp;quot;才敢发，发布本身是高危操作，自然由承担风险的人拍板。&lt;/p&gt;
&lt;p&gt;持续交付把这件事倒过来：当流水线保证了&lt;strong&gt;每个提交技术上都可发布&lt;/strong&gt;之后，&amp;ldquo;何时发布、对谁发布&amp;quot;就纯粹变成了业务问题——市场时机、合规窗口、用户沟通节奏，都应该由产品和业务来定。技术团队的职责是保证这个按钮&lt;strong&gt;随时可以按、按了不出事、出了事能秒回&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这也是特性开关、金丝雀发布的深层价值：它们把&amp;quot;发布&amp;quot;从技术动作变成了业务杠杆——按客户群分批开放、给内部员工先试用、关键客户定制节奏，都是业务手段而不是工程手段。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：很多团队的技术债，根子其实是&amp;quot;发布权力错配&amp;rdquo;：业务想要的速度给不了，因为发布在技术上做不到随时可做。先把工程能力补到位，权责自然归位。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八案例正面与反面&#34;&gt;八、案例：正面与反面&lt;/h2&gt;
&lt;h3 id=&#34;正面高频部署的先行者&#34;&gt;正面：高频部署的先行者&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flickr&lt;/strong&gt;：2009 年 Velocity 大会上，Flickr 的 John Allspaw 和 Paul Hammond 做了那场著名演讲《10+ Deploys Per Day: Dev and Ops Cooperation at Flickr》——每天 10 次以上部署。这个演讲被公认为 DevOps 运动的引爆点之一。他们的经验核心正是本书的思想：小批量、特性开关、完善的监控和一键回滚，让高频发布不是冒险而是常态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Amazon&lt;/strong&gt;：以部署频率著称。后来 Amazon 高管在公开分享中提到过，2011 年前后 Amazon 平均每隔十几秒就有一处变更部署到生产（这个数字随年份增长，到 2014 年的分享里已经是秒级）。支撑它的是高度自动化的流水线和&amp;quot;谁构建谁运行&amp;quot;的服务负责制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些公司证明了一件事：&lt;strong&gt;部署频率和生产稳定性不是此消彼长，而是可以同向增长的&lt;/strong&gt;——前提是自动化、小批量、快速回滚三件套齐全。后来 DORA 的年度行业报告用数据反复验证了这一点：部署频率最高的那批组织，变更失败率反而最低、恢复最快。&lt;/p&gt;
&lt;h3 id=&#34;反面knight-capital45-分钟-44-亿美元&#34;&gt;反面：Knight Capital，45 分钟 4.4 亿美元&lt;/h3&gt;
&lt;p&gt;2012 年 8 月 1 日，美国做市商 Knight Capital 发生了一起教科书级的部署事故，大约 45 分钟内亏损约 4.4 亿美元，公司险些倒闭，最终被收购。&lt;/p&gt;
&lt;p&gt;事后的公开报道和美国 SEC 的调查文件还原了链条：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;他们为新的&amp;quot;零售流动性计划&amp;rdquo;（Retail Liquidity Program）功能做部署，生产环境共 &lt;strong&gt;8 台服务器，人工部署只更新了 7 台&lt;/strong&gt;，漏了一台；&lt;/li&gt;
&lt;li&gt;新代码&lt;strong&gt;复用了一个旧的标志位（flag）&lt;/strong&gt;，而这个标志位多年前曾用于一个早已弃用的功能&amp;quot;Power Peg&amp;quot;——沉睡的旧代码没有被删除，只是被开关挡着；&lt;/li&gt;
&lt;li&gt;那台漏更新的服务器上，旧标志位被请求触发，&lt;strong&gt;沉睡多年的 Power Peg 代码被唤醒&lt;/strong&gt;，开始以错误逻辑疯狂下单；&lt;/li&gt;
&lt;li&gt;现场&lt;strong&gt;没有一键回滚机制&lt;/strong&gt;，工程师手忙脚乱，花了 40 多分钟才止住。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用本书的概念框架看，这个事故几乎踩中了所有反面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;部署靠人工&lt;/strong&gt;——8 台漏 1 台是人工部署的必然概率问题，不是偶发失误；&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;p&gt;&lt;strong&gt;感悟&lt;/strong&gt;：这个案例我逢人就讲，因为它完美诠释了本书的中心论点：&lt;strong&gt;事故的根源不是&amp;quot;发布太多&amp;quot;，而是发布过程不可重复、不可回滚&lt;/strong&gt;。Knight Capital 一年也发不了几次版，&amp;ldquo;少发布&amp;quot;没有保护他们。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九思考与感悟&#34;&gt;九、思考与感悟&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;持续&amp;quot;是方法，&amp;ldquo;交付信心&amp;quot;才是目的。&lt;/strong&gt; 读完回头看，这本书所有技术手段——流水线、金字塔、特性开关、蓝绿——都服务于同一件事：让团队在任何时候都能有底气地说&amp;quot;现在的版本是可发布的&amp;rdquo;。这种底气本身会改变团队的开发方式：敢重构、敢提交、敢试验。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;纪律比工具难买。&lt;/strong&gt; 流水线的搭建一个 Sprint 就能做完，难的是&amp;quot;红了就停下手头一切去修&amp;quot;这条纪律。工具解决的是&amp;quot;能不能&amp;rdquo;，纪律解决的是&amp;quot;做不做&amp;rdquo;。后者只能靠团队共识和管理者背书。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;和客户开发方法论同构。&lt;/strong&gt; 这是我读完联想最多的一点：之前读的创业方法论里，客户开发（Customer Development）讲的是市场侧的小步试错——别闭门造车一年再赌一把大的，把假设拆小，快速放到真实客户面前验证。持续交付是&lt;strong&gt;工程侧的同一件事&lt;/strong&gt;：别把代码攒三个月再赌一次大发布，把变更拆小，快速推到真实环境里验证。一个在验证&amp;quot;需求假设&amp;quot;，一个在验证&amp;quot;代码正确性假设&amp;quot;，底层的认识论完全一致：&lt;strong&gt;小批量、快反馈、可回退，用高频试错替代单次豪赌&lt;/strong&gt;。精益创业（Lean Startup）把这两条线拧在了一起，不是巧合——Eric Ries 本人就是持续部署的早期实践者。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;每步可退，才能每步敢进。&lt;/strong&gt; &amp;ldquo;可回滚&amp;quot;听起来是防御性能力，实际上是进攻性能力——只有确信每一步都退得回去，团队才敢把步子迈快。这本书最深的洞察也许就这一句：&lt;strong&gt;速度和安全不是天平的两端，可回滚性把它们焊在了同一侧。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;本篇小结&#34;&gt;本篇小结&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;部署流水线是核心骨架：提交 → 构建+单元测试 → 自动化验收 → 手工验证/UAT → 发布，每个阶段是质量关卡，失败即止，修复红灯优先于新功能；&lt;/li&gt;
&lt;li&gt;哲学上是 &amp;ldquo;If it hurts, do it more often&amp;rdquo;：痛苦的事要做小、做勤，风险切碎摊平，而不是攒起来赌一次大的；&lt;/li&gt;
&lt;li&gt;每次提交产出可发布候选；同一构建产物逐级晋升，环境差异靠外部配置注入；&lt;/li&gt;
&lt;li&gt;测试要金字塔不要冰淇淋筒：单元测试打底，验收测试讲业务语言，UI 测试最少；&lt;/li&gt;
&lt;li&gt;主干开发 + 特性开关替代长寿命分支，把&amp;quot;部署&amp;quot;和&amp;quot;发布&amp;quot;解耦；&lt;/li&gt;
&lt;li&gt;蓝绿部署和金丝雀发布把回滚能力内建在发布机制里；数据库变更走 expand-contract，每步向前向后兼容；&lt;/li&gt;
&lt;li&gt;配置和环境定义全部进版本控制，环境朝&amp;quot;可重建的牲畜&amp;quot;方向走；&lt;/li&gt;
&lt;li&gt;发布是业务决策，技术团队的职责是让那个按钮随时可按、按了能回；&lt;/li&gt;
&lt;li&gt;收尾的同构关系：客户开发是市场侧的小步试错，持续交付是工程侧的小步试错，精益创业把两者拧成一股。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
