Skip to content
Rabin Poudyal
Rabin Poudyal
← All models

Software and engineering

Hyrum's law

With enough users of an interface, every observable behaviour gets depended on by someone, whatever the contract promises.

Hyrum Wright, from his years running large-scale code migrations at Google; named by Titus Winters; stated on Wright's site hyrumslaw.com and in Software Engineering at Google (2020).

Wright's statement: with a sufficient number of users of an application programming interface (API), it does not matter what you promise in the contract, all observable behaviours of your system will be depended on by somebody. Users do not test against documentation, they test against behaviour. If a function happens to return a sorted list, someone relies on the order. If an error message has a stable wording, someone parses it. The Software Engineering at Google chapter gives hash iteration order as the standard case: everyone knows a hash table is unordered, and yet code exists that uses the iteration order as a cheap random-number generator. Every change is then a breaking change for someone.

It holds for a statistical reason. Each user depends on any given accidental detail with some small probability, so the expected number of users depending on it grows with the user count until it passes one. Wright tried to call it the law of implicit dependencies, which names the mechanism better. Raymond Chen's 2003 account of Windows application compatibility shows what it costs at scale: Microsoft kept shims for programs that relied on undocumented behaviour because a single incompatible program could stop a company upgrading, and game vendors would not patch a title with a shelf life of a few months. The observable surface, not the documented one, is the real interface.

The law is not a reason to freeze. It says that if you do not want a behaviour depended on, make it unobservable or visibly unstable: randomise the order, vary the wording, add jitter. With a small user base it is cheaper to coordinate the change than to engineer against it, and 'sufficient number' is deliberately undefined. Applied to everything, it turns into fear of all change; applied to the behaviours that would hurt most to lose, it is a design rule. When you must change a depended-on behaviour, the owner of the interface should run the migration with tooling rather than asking thousands of callers to notice a changelog.

Example

Before Go 1, the Go language specification left map iteration order undefined, and in practice the order differed between hardware platforms, so a test that walked a map could pass on one machine and fail on another. In the Go 1 release of 28 March 2012 the team made the order deliberately unpredictable, different even between two runs of the same loop on the same map. The stated reasoning was Hyrum's law in reverse: code that relied on an order would break early and be fixed before it mattered, and the runtime gained the freedom to balance maps however it liked.

Where it applies

Treat the error strings, field order, timing and default sort of your API as part of its contract, because your callers will. When you change a model version or a prompt template, assume someone parses the exact output format and someone else relies on its latency; randomise what you do not want relied on, and run the migration tooling yourself.

Think about it

Which accidental behaviour of something you maintain would break the most callers if you fixed it tomorrow?

Applied it to something real? Log it.

Test yourselfYour library documents that a function returns items in no particular order, but it has always returned them sorted. Why does Hyrum's law say you cannot simply change that?

With enough users, someone depends on the observed sorted order regardless of the contract, so the change breaks them. Either keep the order, or make it visibly unpredictable so no one can rely on it.

Related models

Sources and further reading