> ## Documentation Index
> Fetch the complete documentation index at: https://meta.niceshare.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 海勒姆定律

> 海勒姆定律指出：用户足够多时，系统一切可观察行为终将被人依赖。了解其起源、应对策略、经典案例与适用边界。

<Info>
  **类别**: 定律<br />
  **类型**: 软件兼容与 API 演化定律<br />
  **来源**: Hyrum Wright（提出观察）；Titus Winters 命名；《Software Engineering at Google》（2020）推广<br />
  **别名**: 隐式接口定律；逐 bug 兼容（bug-for-bug compatibility）
</Info>

<Note>
  **快速回答** — **海勒姆定律**（Hyrum's Law）指出：API 用户足够多时，人们会依赖一切可观察行为，而不只依赖文档承诺。文档画了一条线，真实用法会画出更粗的线。实践上要把“看得见”本身当作合约风险，并为隐式依赖规划变更。
</Note>

## 什么是海勒姆定律？

**海勒姆定律**（Hyrum's Law）是一条观察：用户足够多时，系统的每一种可观察行为都会变成某人的依赖——无论官方合约是否写明。

> 只要 API 用户足够多，你在合约里承诺什么并不重要：系统的一切可观察行为，都会被某人依赖。

可以把菜单当成合约，把后厨习惯当成实现：客人可能开始期待从未写进菜单的餐盘尺寸、等待时间和配菜。软件里，排序结果、错误文案、耗时，甚至 bug，都可能变成承重墙。规模一大，“私有”实现就不再私有：消费者集体把整块表面钉死。

### 海勒姆定律的三层理解

* **入门**：用户看得见的东西，总会有人拿来搭积木——管你写没写进文档。
* **实践**：改库或改 API 之前，先问调用方可能已经依赖了哪些“文档之外”的行为。
* **进阶**：按使用熵来设计——减少意外可观察面，用测试发现破坏，并在必须改隐式接口时预留迁移成本。

## 起源

**Hyrum Wright** 在 Google 做大规模库与基础设施变更时提炼出这一观察：即便对核心 C++ 库做“看不见”的微调，也会弄坏远处那些依赖偶然行为的系统。他把极端形式称为**隐式接口定律**——消费者足够多时，实质上不存在私有实现，维护者往往需要**逐 bug 兼容**。

同事 **Titus Winters** 将其命名为 **Hyrum's Law**，并在 Google 内部推广。2020 年 O'Reilly 出版的《Software Engineering at Google》（Winters、Wright、Manshreck）把它当作长生命周期代码的核心约束：讨论变更必须正视海勒姆定律，就像讨论效率必须正视熵——可以缓解，无法消灭。

Wright 的公开站点（hyrumslaw\.com）固定了经典表述，并把它与 Joel Spolsky 的**泄漏抽象定律**（Law of Leaky Abstractions）相连：消费者终究会注意到、并依赖从抽象中漏出来的细节。

## 核心要点

海勒姆定律与其说是道德戒律，不如说是对大规模用户如何冻结可见行为的预测。

<Steps>
  <Step title="可观察压过已文档化">
    合约写的是允许什么；用法写的是依赖什么。错误字符串、响应字段顺序、缓存耗时、默认格式，一旦被调用方写进代码，就成为真实接口的一部分。
  </Step>

  <Step title="规模把偶然变成刚需">
    一个用户依赖怪癖，是一份 bug 报告；上万用户依赖怪癖，就是一个迁移项目。流行度不发明新物理定律——它只放大“谁会注意到每个细节”。
  </Step>

  <Step title="兼容常常意味着逐 bug 兼容">
    修 bug 可能弄坏那些靠它绕道的调用方。团队于是在保留 bug、双路径并行、或支付协同迁移之间选择——这与[波斯特尔定律](/zh/laws/postels-law)在宽容与严格之间的权衡相邻。
  </Step>

  <Step title="测试能发现依赖，不能消除依赖">
    广泛自动化测试能更早暴露隐式期望。它们并不消解依赖图；只是让破坏成本在发布前可见。
  </Step>
</Steps>

## 应用场景

只要某样东西共享得足够广，“没人会依赖那个”就往往是一厢情愿——这时就用海勒姆定律。

<CardGroup cols={2}>
  <Card title="库与 API 所有权">
    把有意保证写清楚；对必须保留变更自由的偶然行为，尽量隐藏或随机化（例如哈希遍历顺序）。
  </Card>

  <Card title="产品与平台变更">
    把截图布局、CSV 列顺序、webhook 载荷怪癖当作合作伙伴与重度用户的事实 API——不只是工程师的事。
  </Card>

  <Card title="团队流程与制度">
    未写明的“我们一直这么做”会像[康威定律](/zh/laws/conways-law)塑造结构一样承重——改仪式，就有静默东西断裂。
  </Card>

  <Card title="个人工具与学习">
    当你为表格的偶然排序或应用的怪异导出写脚本时，给依赖贴标签；厂商“修好”怪癖时要预期它会失效。
  </Card>
</CardGroup>

## 经典案例

Python 字典排序展示了海勒姆定律如何把实现细节变成语言承诺。在 **CPython 3.6**（2016）中，紧凑字典重设计让插入顺序得以保留，但这只是**实现细节**——有用且可见，却不是对所有 Python 实现的语言保证。调用方仍开始在实践中假设该顺序。

到 **2017 年 12 月 15 日**，经 python-dev 讨论，Guido van Rossum 裁定：“Make it so. ‘Dict keeps insertion order’ is the ruling.” **Python 3.7**（**2018 年 6 月 27 日**发布）随后把插入顺序保留宣布为语言规范的正式部分，合规实现必须遵守。项目选择**追认**已被广泛观察的行为，而不是故意打乱顺序并弄坏已适应的生态。教训很尖锐：足够多用户看得见某种行为后，“从未承诺”是弱辩护；要么吸收成合约，要么支付强制迁移。边界同样尖锐：追认只是一种策略——当偶然行为有害或锁死更好设计时，并不总是正确选择。

## 边界与失效场景

海勒姆定律在**广泛共享、长期存活的接口**上最强。只有两个用户的个人脚本可以自由改；有数百万客户端的平台 API 不行。

它不能当作**永远不改进**的借口。定律预测破坏风险，并不禁止变更。它要求你为排查、沟通与迁移定价——而不是永久冻结。

常见误用是一边骂用户“误用” API，一边继续发出高度可见却未文档化的怪癖。可见却不清晰，就是在邀请依赖。另一种误用是把每个毛刺都奉为神圣：有些 bug 仍应通过带版本的破坏与迁移路径修复，尤其当它们制造安全或正确性债务时。

## 常见误区

用清之前，先把预测、归咎与设计策略分开。

<AccordionGroup>
  <Accordion title="海勒姆定律等于文档没用">
    不对。清晰合约仍能减少意外耦合并引导诚实用户。定律只是说：仅靠文档挡不住人们对仍可见之物的依赖。
  </Accordion>

  <Accordion title="它只适用于公有云 API">
    不对。内部库、CLI、配置格式，甚至家里共享的表格，只要足够多人在上面搭东西，就服从同一模式。
  </Accordion>

  <Accordion title="唯一应对是永远不改">
    不对。应对包括隐藏可观察面、版本化、双跑、对客户端做混沌测试，以及有时把流行行为提升为显式保证——正如 Python 对字典顺序所做的。
  </Accordion>
</AccordionGroup>

## 相关概念

这些页面有助于把海勒姆定律放在互操作、系统生长与意外耦合之中理解。

<CardGroup cols={3}>
  <Card title="波斯特尔定律" href="/zh/laws/postels-law">宽容有助于互通——也可能把怪癖固化成日后的隐式合约。</Card>
  <Card title="康威定律" href="/zh/laws/conways-law">组织结构塑造系统；非正式习惯同样塑造人们依赖什么。</Card>
  <Card title="盖尔定律" href="/zh/laws/galls-law">能工作的复杂系统从简单系统长成——用户也会抓住偶然表面。</Card>
  <Card title="古德哈特定律" href="/zh/laws/goodharts-law">指标成目标就会扭曲；怪癖成依赖就会冻结。</Card>
  <Card title="意外后果法则" href="/zh/laws/unintended-consequences">可见副作用会成为用户真实结果集的一部分。</Card>
  <Card title="沃斯定律" href="/zh/laws/wirths-law">软件复杂度会吃掉硬件增益——复杂度也会繁殖可观察面。</Card>
</CardGroup>

## 一句话总结

<Tip>
  把每一种可见行为都当作潜在合约——并按“已经有人依赖它”来设计、测试与迁移。
</Tip>
