跳到主要内容

the-missing-readme 通读笔记(2026-08-29,一次通读完成)

原书:The Missing README(Riccomini & Ryaboy,No Starch 2021),中译《程序员的 README》(人邮 2023-07,付裕译)。 14 章正文 + 前后附材料全部读完。行号 = library/the-missing-readme/text/*.txt:N。 导航章(09-fm 目录)未读未引;01/02/03/08/24-fm 仅取出版信息(2021 英文原版 / 2023-07 中译)。

定位与差异化

  • 本书回答:从「会写代码」到「能在团队里交付生产软件」之间那段没人教的路;背后是一条职业成长路线图(新手营→胜任之湾)。
  • 与已拆书差异化:principles-of-programming=代码原则清单;the-programmers-brain=认知机制;本书=职业流程与成长路线(怎么入职/怎么改代码/怎么测试评审交付值班/怎么做设计/怎么跟管理者合作/怎么晋升)。
  • product-engineering 判据:读完对「下一步该怎么走」有判断(第 14 章给出职级/晋升/换工作的判断框架)。
  • 前言自曝立场:经验来自「快速成长的、风投资助的或准上市的硅谷公司」(06-fm.txt:30-33),读时要注意口径。

各章要点(机制/数字/可引段落)

ch01 前面的旅程(10-ch01)

  • 四个核心领域能力:技术知识/执行力/沟通能力/领导力(:18,:25,:30,:37)。
  • 旅程地图五站:新手营→试炼之河→贡献者之角→运维之海→胜任之湾(:58-49)。
  • 坎宁安定律:「发布错误的答案」(:95);自行车棚效应:发电厂方案几分钟批准,自行车棚材料讨论 45 分钟(:103-104)。
  • 新手任务可小到「只更新一行注释」(:114)。

ch02 步入自觉阶段(11-ch02)

  • 布罗德威尔四阶段:无意识的无能力/有意识的无能力/有意识的有能力/无意识的有能力(:3-14);「你的目标是尽快到达第三个阶段」(:18)。
  • 学习方法 7 种:前置学习(Facebook 6 周 boot camp,:50)/实践(克里斯删库故事:分支标记合并后毁掉整个 VCS,:74)/运行实例(入口处打印特殊语句识别新旧版本,:109-114)/阅读(杰弗里斯「代码从不说谎,注释有时却会」,:125;德米特里读反编译代码故事,:173)/讲座(1.5-2 倍速+做笔记,:185-187)/会议(3 类:学术/草根/供应商,信噪比低,:196-206)/跟班结对/副业。
  • 提问 3 步:调查→时限→写全过程(:283);坏/好提问对照(潘卡邮件:每 3 次失败 1 次、拍打测试花 20-30 分钟,:334-345);非打扰式=组播+异步(:378-388);批量同步(办公室答疑时间,:397)。
  • 冒充者综合征(自我强化循环:错误=能力证明,成功=冒充证据,:439-440;对策:觉知/重塑/交谈);邓宁-克鲁格(「完全自信标志着盲点」,:469)。

ch03 玩转代码(12-ch03)

  • 软件的熵:混乱是变化的自然副作用(:22)。
  • 技术债=本金+利息(:36);福勒 2×2 矩阵(鲁莽/谨慎 × 有意/无意,:53-57);「技术债总是不可避免的……项目只有存活了足够长的时间,才会变得无序」(:80-82);滥用「技术债」会稀释它(:44-45)。
  • 债务提案模板 5 条(:97-101);约翰娜拆登录服务邮件:不稳定占 On-Call 问题 30% 以上(:111-112)。
  • 费瑟斯五步:定义变更点/找测试点/打破依赖/写测试/修改重构(:156-160);栅栏比喻(:162);打破依赖 3 法(:188-193);不要为测试改访问声明(破坏封装,:194-195)。
  • 童子军原则「过手的代码要比之前更干净」(:209-214);清理与行为提交分开(:216-220)。
  • 代码异味:Java 缺大括号例(清单 3-1/3-2,:229-251)。
  • 提交信息 7 条(比姆斯:标题≤50 字符、命令式语气等,:324-330)。
  • 避坑:霍洛维茨「至少比流行方式好十倍」(:347);创新代币(:377-380,新语言≈3 枚 :394-395);「价值数十亿美元的公司都是建立在成熟但有些无聊的编程语言之上」(:402-405);Scala/SBT 故事(:409-439);分叉不回馈(:464-479);第二系统综合征(:497);DDG 迁移:预计 6 个月→18 个月、超 100 万美元(:526-527)。

ch04 编写可维护的代码(13-ch04)

  • 防御式编程=安全(编译时校验/不可变/静态类型)+弹性(异常)(:22-26)。
  • 空值:空对象模式(返回空列表,:40-43)、可选类型;不可变(final/val/let,:49-55);类型提示+静态检查(Python 3.5/TypeScript/Sorbet,:63-64)。
  • 验证输入:Word 文档故事(15 年后仍在误导,:98-129,「破坏了治疗癌症的研究」:129);OWASP 十大(:141-142)。
  • 异常:别用特殊返回值(null/0/−1,:146-150);Go/Java 签名例(:166-171);异常要有精确含义;FoundNodeException 反例(用异常控制流程,:195-206);早抛晚捕(:209);吞异常最糟(:225-226)。
  • 重试:指数退避 retry^2+设上限(:254-257);惊群效应(:258-260);抖动=加随机(:263);快速失败(:265-270)。
  • 幂等:计费重试→双倍收费(:276-278);请求唯一 ID 去重(:285-288)。
  • 资源:套接字泄漏填满连接池(:297-298);try/finally、with、Rust 析构(:308-317)。
  • 日志 6 级(TRACE/DEBUG/INFO/WARN/ERROR/FATAL,:357-383);INFO 是默认,:369;WARN 必须有具体行动,:374-376;原子日志(折行=灾难,:397-418);性能(参数化延迟拼接,:435-456;异步附加器崩溃丢日志,:464-468;改日志级别会改变时序、可能"治好"bug,:469-472);敏感数据(:475-482)。
  • 监控:计数器/仪表盘/直方图(:490);P99=2 毫秒(:502-503);SLO(:506-507);StatsD Flask 例(key_hit/key_miss/gauge/timer,:543-596);序列化常是最贵操作(:617-619);分布式调用跟踪 trace ID(:645)。
  • 配置:凌晨 3 点不该需要记住 Tcl 语法(:686-687);动态配置收益常不抵复杂度(日志分级是正当例外,:697-712);启动时记录并校验(−200 不是有效端口,:728);默认值>1024 端口(:734-736);timeout=10s 分组(:746);配置即代码(:751-758);不手动编辑生产配置(:771-776)。
  • 工具:CLI 优先、可脚本化(:789-792);AWS S3 2017-02-28 事故:手滑删节点,工具允许过多容量被快速删除(:815-829)。

ch05 依赖管理(14-ch05)

  • left-pad 事件 2016-03:一个填字符串的小包消失→成千上万项目编译失败(:3-10)。
  • 版本三特点:唯一/可比/信息(:49-57);SemVer 主.次.补丁(:69-73);0.x 无兼容保证(:91-94);RC(:101-104);构建流水号 2.13.7-alpha.2+1942(:107-108)。
  • 传递依赖:加 1 个依赖=依赖 101 个类库(:139-141);依赖树(5-2)。
  • 钻石依赖:zookeeper 要 slf4j 1.6.1,util 要 1.7.21→构建系统择一(-> 标记,:162,184-186);「兼容性是一个美丽的愿望」(:192-193);循环依赖 A→B→C→A(:197-205);Guava/google-collections Azkaban 事故(NoSuchMethodError,:214-245)。
  • 加依赖前 9 问(:251-260);隔离(复制/供应商/遮蔽 shaded,:265-294;DRY 要务实,:269-273);显式声明、勿用横向依赖(:298-308);版本指定 pinning(:312-316);Airflow flask_oauth 三种策略混用(:339-349);依赖清单 pip freeze/Cargo.lock(:356-363);「18 个月后,那些复制的依赖声明仍然没有被恢复」(:380);范围最小化(:384-392);循环检测工具(:399-401)。

ch06 测试(15-ch06)

  • 测试 5 用途:验证/保护/暴露接口设计/文档/游乐场(:12-16);TDD(:33-37)。
  • 类型:单元(快短集中,:50-56)/集成(洗碗机故事,:64-86)/系统+合成监控(:87-94)/性能(负载 vs 压力,:95-100)/验收(:101-108);开源项目分类混乱的观察(:110-123)。
  • 模拟库(:143-165;isTest 参数反模式 :154-156;过度模拟=紧耦合异味 :162);框架(setup/teardown,teardown 不保证运行 :184-187;串行/并行 :188-196);linter/圈复杂度/覆盖率(经验值 65%-85%,:222-230)。
  • 自己写测试;QA 团队早就不写单元测试(:257-259)。
  • 风险矩阵:「风险矩阵将风险定义为失败的可能性和影响」(:319-320)——BOOK-TEARDOWN 既引口径,必须沿用;测试把风险向左下移(:326-328)。
  • 过度测试:覆盖率 100% 也可能有严重 bug(:304-308);测自动生成代码是浪费(:309-316)。
  • 确定性 9 招:拍打测试(:338)/种子 RNG(:359)/不调远程(:369)/注入式时间戳(SimpleThrottler Ruby 例,:383-464;依赖注入 :462)/禁休眠(30 分钟例,:475)/关资源(:486-500)/绑 0 端口(:510)/唯一路径(tempfile/UUID,:521-523)/清状态(「留下残渣」:541)/不依赖顺序(:550)。

ch07 代码评审(16-ch07)

  • 评审 5 价值:抓 bug/教学/共同理解/决策档案/安全合规(:19-42);前提=「高度信任」环境(:43);坏评审=拉锯扯皮(:46-52)。
  • 被评审:准备(评审请求样例 UI-1343,:79-105)/草案 DRAFT/WIP(:109-124)/勿用评审触发 CI(:127-143)/大改动预排会议(:146-166)/别太在意(评审针对代码不针对人,:171)/不容忍粗鲁(:183)/保持主动(及时合并,拖久了要变基,:208-213)。
  • 评审别人:分流(:222)/预留时间(大评审建任务票,:243-248)/先懂意图(:250-259)/全面反馈(端口评论示例 :278-280)/承认优点(:284)/Nit 前缀、可选/非必须(:302,321-324)/拒绝橡皮图章(:333;数千行改动 :341)/本地迁出跑起来(:350)/评审测试代码(:358)/推动决断(谷歌:肯定能改善整体状况即批准,即使不完美,:381-383)。

ch08 软件交付(17-ch08)

  • 4 阶段:构建→发布→部署→展开(rollout)(:22-29);术语无行业标准(:15-21)。
  • 分支:主干式+CI(主分支应总是可发布,:73-74)vs 特性分支(Gitflow,:87-96);Gitflow 作者本人已不再鼓励(:112-114)。
  • 构建:包要带版本(mysql-server-8.0_8.0.21-1_amd64.deb,:133-135);资源分开打包(元包,:159-170);Python 打包洋葱(sdist/wheel/PEX/Anaconda/Freezer/镜像,:172-217)。
  • 发布:归根结底你有责任(:244);发布到专用仓库(:253-265);已发布包不可变(字节层面一致,:287);频繁发布(长周期=错误的安全感,:293-294);变更日志(给支持/开发)vs 发行说明(给用户)(:319-320);ASF 流程(签名/校验和/PMC 投票,:322-345)。
  • 部署:自动化(持续交付,:362-368;Puppet/Salt/Ansible/Terraform :369-372);原子部署(装新位置+软链接翻转,:388-389);独立部署(LinkedIn 顺序部署 20+ 环节、IRC 通宵,最终禁止,:413-439)。
  • 展开:特性开关(布尔/允许列表/百分比/函数,:486-492;数据库状态要向前向后兼容 :493-501;要清理旧开关 :502-506)/熔断器(二进制+永久+自动,:514-516;不可逆行动 :529-533)/金丝雀(1% 入站流量,:547)/蓝绿(主动/被动,切换原子化,:551-559)/摸黑启动(暗中读取/暗中写入,:580-597;Diffy 三实例对比 :607-611;Twitter 暗中写入故事 :613-643)。

ch09 On-Call(18-ch09)

  • 轮换(一周/两周,主+辅,:23-30);交接(:46-49)。
  • 技能:随时响应(「15 分钟内答复」:75)/专注(基线仪表盘 :91;On-Call 书签文件夹 :95)/优先级(P0-P4,谷歌云 P1=服务不可用 :114-122;SLI/SLO/SLA,错误率<0.001% :127-128)/沟通(503 确认例 :152-155;ETA :158)/跟踪(时间戳,下午 1:05 报延迟 vs 下午 1 点重启 :188-191)。
  • 事故 5 阶段:分流/协同/应急方案/解决方案/后续行动(:200-220);先止血后查因(:207-210)。
  • 真实事故走查:数据仓库缺数(:224-445)。分流:定优先级不排障(:238-252);协同:公告/拉人/事故指挥官/状态页/作战室(:270-286);应急:30 个数据流二分法定位坏流(:300-304),保存遥测(:319-322);解决:命令行工具能读、连接器不能→消息头(单键空值,:346-347),APM 默认注入(:347-351),命令行工具不输出空尾字节头的 bug(:352-353),禁用头解码验证理论(:356-358);科学方法(:369-376);后续:尸检/回顾,5 Why(5 连问到「APM 在开发者不知情的情况下默认了这种行为」,:439-445),「根本原因分析是一个流行但具有误导性的术语」(:448-449),对事不对人(「彼得没有禁用消息头」vs「消息头配置的改变没有经过代码评审」,:460-461),解决问题与评审会议分开(:463-464)。
  • 支持请求:珍妮特时间线(3:48PM 报告→半小时响应→ETA→次日确认,:495-514);支持是学习机会(:525-531)。
  • 不要逞英雄:救火队员→长期 On-Call→倦怠(:540-547);「我想自己想办法解决……30 分钟内请求你的帮助」(:558-562)。

ch10 技术设计流程(19-ch10)

  • 设计=螺旋(V 形/漏斗):探索→文档→评审,迭代上升(:22-57);实施中偏差要回写文档(:55-57)。
  • 定义问题:「如果我们不解决这个问题会怎么样?」(:76-78);库存例子:特性请求(扫描目录+ML 模型)→4 个提问→重写的问题陈述(SKU 多供应商、Excel 映射、优先级=数据准确性>下单时间>成本)(:86-118)。
  • 调查:公司博客是营销、只讲简化架构(:129);「你的问题不是谷歌的问题」(:142-143)。
  • 实验:概念验证要扔、不写测试不打磨(:153-157);给时间:制造者时间表(:165-171);设计尖峰=限时调查(:183-188)。
  • 要不要文档 3 标准:≥1 个月工时/长期影响/影响其他团队(:199-204)。
  • 写作暴露你不知道的东西(:229);写作是有损传递(:256-257);文档两个陷阱(提案被废弃/历史丢失,:277-283);与代码同库版本控制(:288-293)。
  • 模板 11 节(:307-325);「减少 50%内存占用」不如「解决最常见的拒绝理由」(:348-349)。
  • 协作:架构评审(重)vs RFD(轻,:456-470);不要让人惊讶(突然出现的文档=失败伏笔,:486);头脑风暴 2-5 人、约两小时、白板不幻灯(:510-521);记录员轮换(:523-524);提出问题和给予建议一样重要(:542)。

ch11 构建可演进的架构(20-ch11)

  • 复杂性=难以理解与修改(:20-21);三特点:高依赖(紧耦合+变更放大,:25-32)/高隐蔽(隐性知识,:33-39)/高惯性(作者自加,:40-45);「复杂性不总能被消除,但你可以选择把它放在哪里」(:46-47)。
  • 别赌未来:既别预判需求,也别造抽象逃生舱门,KISS(:55-58);YAGNI(:63-78;过早优化 :79-87;IDistributedQueue 并集/交集两难 :97-109;蒙茨法 :114;接口填充程序=只留头不实现 :124-129)。
  • 最小惊讶:隐藏排序需求(pontoonWorples,:151-166)、隐藏参数需求(int 只许 1-10,:167-170)。
  • 领域封装:高内聚低耦合、爆炸半径小(:187-189);技术分层的问题(:192-198);DDD(:200-204)。
  • API 演进:保持小巧(:217-228);IDL/OpenAPI(:237-238);向前 vs 向后兼容定义(:259-264);Greeter 例:加 required email=向后不兼容(:295-304),「必填项永远存在」,required 被 v3 移除+瓦尔达「可怕的错误」(:305-312);int32→sint32 双向不兼容(:317-330);新增字段序号+废弃旧字段=向前兼容(:331-345);API 版本化(网关路由 v2/v3,:364-365)。
  • 数据演进:数据库隔离(共享库丧失自主性,:405-406);显式 schema vs 无模式(JSON 大杂烩例 :473-476;users 表 :486-492;「隐藏无模式的数据是自取灭亡」:497-498);自动化迁移(Liquibase changeset/rollback,:531-556;DATABASECHANGELOG 表 :570;schema 迁移与应用部署解耦 :575-578;回滚不恢复数据 :592-595);schema 兼容(ETL 管道 :618-620;CDC=隐含 API :631-636;数据产品解耦 :644-648)。

ch12 敏捷计划(21-ch12)

  • 敏捷宣言 2001,四行价值观(:24-30);讽刺:黑带忍者与流程崇拜(:37-40)。
  • Scrum(冲刺两周,:47-48)vs 看板(限 WIP,:58-60);现实是 Scrumban/混搭:「将注意力集中在目标上,而不是机制上」(:72)。
  • 用户故事格式(:90);误用(着色器插件 8.7,:95-96);验收标准 5 条例(:106-111);尖峰(:112-116)。
  • 分解:postProfile 重试→6 步(规范/编码/单测/集成/部署/灰度,:123-141)。
  • 故事点:4 人×10 点=40 点(:150-151);1 点=4 小时工作日(:155);T 恤尺码=斐波那契 1/2/3/5/8(:156-158);相对大小(:171-178)。
  • 冲刺锁定(:204-205);站会 15 分钟、仪表盘比喻、停车场(:223-244);Scrum of Scrums(:249)。
  • 评审(演示+项目评审,每冲刺周≤1 小时,:271-272)vs 回顾(流程和工具,:305-306;3 阶段:分享/定优先级/解决问题 :293)。
  • 路线图:艾森豪威尔「计划是无用的,但计划是不可缺少的」(:329-330);年度规划与人头数(:346-347)。

ch13 与管理者合作(22-ch13)

  • 管理者=人/产品/流程;向上/横向/向下(:19-26);好的工程经理很少写代码(:23)。
  • 1:1:每周/每两周;你定议程、不是状态更新(:57-67);4 类话题(:69-80);一再取消=信号(:94);德米特里漏建 1:1 机制致组员流失(:103-118);可与资深工程师 1:1(:120-124)。
  • PPP:进展/计划/问题各 3-5 条、每条 1-3 句(:134-135);更新≤5 分钟(:173)。
  • OKR:目标+3-5 关键结果;订单服务例(99.99%/P99<20ms/5XX<0.01%/5 分钟转移,:183-187);关键结果≠待办清单(奶奶聚会:「20 日前到洛杉矶」而非「沿 I-5 行驶」,:197-200);预期成功率 60%-80%(:210-211);每季 1-3 个(:205-206)。
  • 绩效:4 问模板(:236-243);不要凭记忆(用 PPP/任务系统重建,:247-255);360 度考评(:262-269)。
  • 反馈:要具体(「在测试方面做得更好」,:291-293);别听信表面(:296);对反馈给予反馈(:303);SBI 框架=情况/行为/影响(:329;新权限服务例 :333-341;不推荐解决方案 :345);私下冷静频繁(:350);积极反馈也用 SBI(:358-367)。
  • 不顺时:HR 的作用是保持稳定(:424);给 3-6 个月观察期(:430-431);内部调动 vs 新公司(:435-441);镜中的程序员(优秀程序员=糟糕管理者,:443-463);「如果你已经给出了反馈意见……那就起身离开」(:465-468)。

ch14 职业生涯规划(23-ch14)

  • 阶梯两个过渡:初级→资深、资深→主任/首席(:14-16);资深=处理不确定性与模糊性(:22);主任=工程战略/规划/架构,仍大量写代码(:25-28);主任级分管理/个人贡献者双轨(:29-30)。
  • T 型:Valve 手册(通才横线+专家竖线,:53-57);monad 例子(:68);公司成长会推动专业化(:74-75)。
  • 主导晋升:晋升资料袋(:110);要具体反馈(「与 Level 3 工程师的设计文档对比」,:116-117);提前 3-6 个月达到下级高度(:136-137);在「达到一半」时开始晋升谈话(:140);胶水工作:塔尼娅·赖利——若管理层不认为其是晋升途径就停手(:151-157)。
  • 换工作:频繁=看不到决定的长期效果、阻碍资深直觉(:162-166);FOMO 不是理由(:169-170);换工作更易赶上市场加薪(:182-183);也别待太久(价值来自「历史学家」身份就危险,:189-190)。
  • 自我调节:一晚睡眠不足→代码质量降 50%(IEEE TSE 2020,:206-207);年假/学术休假(:214-218);「职业生涯是一场马拉松,而不是短跑冲刺」(:221)。

全书主线(供 index §3)

会写代码=战斗的一半 → 起点姿态(学/问/自我认知)→ 接手旧代码(熵与债)→ 产出可运维的代码 → 管好依赖 → 过两道闸(测试/评审)→ 交付到用户(四阶段)→ 值班扛事故(五阶段)→ 从改代码升到做设计与架构(演进)→ 与团队/管理者对齐(计划/沟通)→ 对「下一步」有判断(职级/晋升/换工作)。

可信度备注

  • 所有「证据」基本都是作者亲历故事(删库/反编译/Word 文档/AWS/Guava/left-pad/DDG/LinkedIn 部署/Twitter 暗中写入/镜中程序员),无对照实验;两处引用研究:睡眠 50%(IEEE TSE 2020)、冒充者现象(克朗斯&艾姆斯 1978)。
  • 数字多为经验值:覆盖率 65-85%、OKR 60-80%、1 点=4 小时、1:1 每周、故事点 4 人×10。
  • 硅谷口径:前言自认;On-Call/OKR 等制度在美国大厂更普遍。