Hyrum's Law: The Unseen Force Shaping Software Dependencies
In the realm of software engineering, Hyrum's Law is a principle that has profound implications for the development and maintenance of software systems. This article delves into the intricacies of Hyrum's Law, exploring its problem statement, implications, and practical applications. We will also examine code examples in Python, discuss the advantages and disadvantages, and provide considerations for software developers. What is the Problem? Definition With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody. Illustration Imagine a library that provides a function to calculate the square root of a number. The official documentation promises that the function will return the square root of the input. However, if the function also happens to print a debug message, some users might start relying on this behavior, even though it was never part of the official contract. Anecdote A developer once shared a story about how a minor change in a logging format led to a cascade of failures in dependent systems. This change was not documented, but users had come to rely on the specific format of the logs for their monitoring tools. Example Consider a Python library that provides a function to fetch data from an API. If the function returns data in a specific format, users might start relying on this format. Changing the format, even slightly, can break their code. def fetch_data(api_url): response = requests.get(api_url) return response.json() # Users might rely on the exact structure of the JSON response data = fetch_data("https://api.example.com/data") print(data["key"]) What Does the Law Suggest? Immutable Contracts Hyrum's Law suggests that once a behavior is observable, it becomes part of the contract, whether intended or not. Therefore, developers should be cautious about changing any observable behavior. Comprehensive Testing To mitigate the effects of Hyrum's Law, comprehensive testing is essential. Tests should cover not only the documented behaviors but also any observable behaviors that users might rely on. Example def fetch_data(api_url): response = requests.get(api_url) return response.json() # Comprehensive tests to ensure all observable behaviors are covered def test_fetch_data(): data = fetch_data("https://api.example.com/data") assert "key" in data assert isinstance(data["key"], str) Real world examples 1. Microsoft Excel's Calculation Bug (1997) The Bug: In Excel 97, a calculation error caused certain formulas (e.g., =60000 * 0.0000000000000001) to display incorrect results (e.g., 0 instead of 0.0000000000006). This was a minor floating-point precision issue. Hyrum's Law in Action: Users built spreadsheets that relied on the incorrect results. When Microsoft tried to fix the bug in later versions, they faced backlash because the "bug" had become a de facto feature. To maintain compatibility, they kept the flawed calculation in place for years. Outcome: The bug persisted until Excel 2003, and even today, Excel includes an option to "Enable iterative calculation" to replicate the old behavior for legacy workbooks. 2. Java 8's HashMap Change (2014) The Bug: Prior to Java 8, HashMap entries were ordered based on a deterministic hash function. Developers occasionally relied on this order, even though it was never part of the official API. Hyrum's Law in Action: In Java 8, Oracle introduced a random hash seed to prevent hash collision attacks. This broke applications that depended on the previous predictable ordering (e.g., for caching or serialization). Outcome: Developers had to update their code to avoid relying on HashMap order, but many were caught off guard because the dependency was undocumented. 3. Google Maps API's Undocumented Features The Bug: Early versions of the Google Maps API included undocumented endpoints or behaviors (e.g., geocoding shortcuts or map styling hacks) that developers used to bypass official restrictions. Hyrum's Law in Action: When Google updated the API to enforce stricter usage policies, these "features" were removed or changed, breaking third-party apps that relied on them. Outcome: Google had to maintain legacy support for some deprecated endpoints, acknowledging that users had built workflows around the undocumented quirks. 4. Windows 95's "My Computer" Icon The Bug: In Windows 95, the "My Computer" icon on the Start Menu sometimes failed to load due to a race condition in the file system. Hyrum's Law in Action: Users expected the icon to always appear, so Microsoft patched the bug but later faced complaints when the fix caused other issues. The icon’s presence became a user expectation, even if it relied on a "buggy" worka

In the realm of software engineering, Hyrum's Law is a principle that has profound implications for the development and maintenance of software systems. This article delves into the intricacies of Hyrum's Law, exploring its problem statement, implications, and practical applications. We will also examine code examples in Python, discuss the advantages and disadvantages, and provide considerations for software developers.
What is the Problem?
Definition
With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.
Illustration
Imagine a library that provides a function to calculate the square root of a number. The official documentation promises that the function will return the square root of the input. However, if the function also happens to print a debug message, some users might start relying on this behavior, even though it was never part of the official contract.
Anecdote
A developer once shared a story about how a minor change in a logging format led to a cascade of failures in dependent systems. This change was not documented, but users had come to rely on the specific format of the logs for their monitoring tools.
Example
Consider a Python library that provides a function to fetch data from an API. If the function returns data in a specific format, users might start relying on this format. Changing the format, even slightly, can break their code.
def fetch_data(api_url):
response = requests.get(api_url)
return response.json()
# Users might rely on the exact structure of the JSON response
data = fetch_data("https://api.example.com/data")
print(data["key"])
What Does the Law Suggest?
Immutable Contracts
Hyrum's Law suggests that once a behavior is observable, it becomes part of the contract, whether intended or not. Therefore, developers should be cautious about changing any observable behavior.
Comprehensive Testing
To mitigate the effects of Hyrum's Law, comprehensive testing is essential. Tests should cover not only the documented behaviors but also any observable behaviors that users might rely on.
Example
def fetch_data(api_url):
response = requests.get(api_url)
return response.json()
# Comprehensive tests to ensure all observable behaviors are covered
def test_fetch_data():
data = fetch_data("https://api.example.com/data")
assert "key" in data
assert isinstance(data["key"], str)
Real world examples
1. Microsoft Excel's Calculation Bug (1997)
-
The Bug: In Excel 97, a calculation error caused certain formulas (e.g.,
=60000 * 0.0000000000000001
) to display incorrect results (e.g.,0
instead of0.0000000000006
). This was a minor floating-point precision issue. - Hyrum's Law in Action: Users built spreadsheets that relied on the incorrect results. When Microsoft tried to fix the bug in later versions, they faced backlash because the "bug" had become a de facto feature. To maintain compatibility, they kept the flawed calculation in place for years.
- Outcome: The bug persisted until Excel 2003, and even today, Excel includes an option to "Enable iterative calculation" to replicate the old behavior for legacy workbooks.
2. Java 8's HashMap Change (2014)
-
The Bug: Prior to Java 8,
HashMap
entries were ordered based on a deterministic hash function. Developers occasionally relied on this order, even though it was never part of the official API. - Hyrum's Law in Action: In Java 8, Oracle introduced a random hash seed to prevent hash collision attacks. This broke applications that depended on the previous predictable ordering (e.g., for caching or serialization).
-
Outcome: Developers had to update their code to avoid relying on
HashMap
order, but many were caught off guard because the dependency was undocumented.
3. Google Maps API's Undocumented Features
- The Bug: Early versions of the Google Maps API included undocumented endpoints or behaviors (e.g., geocoding shortcuts or map styling hacks) that developers used to bypass official restrictions.
- Hyrum's Law in Action: When Google updated the API to enforce stricter usage policies, these "features" were removed or changed, breaking third-party apps that relied on them.
- Outcome: Google had to maintain legacy support for some deprecated endpoints, acknowledging that users had built workflows around the undocumented quirks.
4. Windows 95's "My Computer" Icon
- The Bug: In Windows 95, the "My Computer" icon on the Start Menu sometimes failed to load due to a race condition in the file system.
- Hyrum's Law in Action: Users expected the icon to always appear, so Microsoft patched the bug but later faced complaints when the fix caused other issues. The icon’s presence became a user expectation, even if it relied on a "buggy" workaround.
- Outcome: The icon remained a staple of Windows interfaces for decades, despite its origins in a bug.
5. Python's Dictionary Order (Pre-3.7)
- The Bug: Before Python 3.7, dictionaries did not guarantee insertion order. However, in CPython (Python’s reference implementation), they often preserved order as a side effect of their hash table implementation.
- Hyrum's Law in Action: Developers began relying on this undocumented behavior, leading to breakage when Python 3.6 introduced "ordered dictionaries" as a semi-official feature. By Python 3.7, insertion order became guaranteed, but earlier code that assumed unordered data broke.
- Outcome: The Python community had to balance backward compatibility with clear documentation, eventually formalizing the order in 3.7.
6. The "Left-pad" Incident (2016)
-
The Bug: While not a bug itself, the
left-pad
npm package (a tiny utility for string padding) was removed by its maintainer, breaking thousands of projects that depended on it indirectly. - Hyrum's Law in Action: The incident highlighted how even trivial dependencies can become critical when widely adopted. The package was reinstated, but it underscored the risks of relying on undocumented or under-maintained open-source components.
- Outcome: The incident spurred discussions about dependency management and the importance of semantic versioning.
7. Windows API's "SendMessageTimeout" Flags
-
The Bug: The Windows API function
SendMessageTimeout
included undocumented flags that developers used to tweak message delivery behavior. - Hyrum's Law in Action: When Microsoft updated the API to remove or change these flags, applications relying on them crashed or malfunctioned.
- Outcome: Microsoft had to document or preserve some flags to avoid breaking legacy software, even though they were never part of the official API.
Implications
-
Unintended Dependencies:
- Users may rely on side effects, implementation details, or even bugs, treating them as part of the API's contract.
- Even "private" or undocumented features can become critical to users' workflows.
-
Backward Compatibility Challenges:
- Breaking changes to "unintended" aspects can cause widespread issues, forcing maintainers to retain legacy code.
- Refactoring or improving internal logic becomes risky due to hidden dependencies.
-
API Design Rigor:
- Developers must carefully define and document the public interface to avoid accidental exposure of non-essential details.
- Clear boundaries between stable, supported features and internal implementation are crucial.
-
Testing and Documentation Burden:
- Comprehensive testing is required to catch regressions in both intended and unintended behaviors.
- Documentation must explicitly state supported vs. unsupported features to guide users away from fragile dependencies.
-
Technical Debt Accumulation:
- Over time, maintaining deprecated or outdated features increases complexity and slows development.
- Legacy code may persist indefinitely due to reliance on "unintended" aspects.
-
User Reliance on Hacks/Workarounds:
- Users may exploit undocumented behaviors (e.g., parsing logs, abusing error messages) as shortcuts, leading to frustration when those behaviors change.
-
Deprecation Requires Caution:
- Removing or altering features—even unintended ones—requires gradual deprecation cycles and clear communication.
-
"No Private Methods" Principle:
- In public APIs, there are effectively no truly "private" components once released, as users may depend on anything observable.
-
Law of Unintended Consequences:
- Hyrum's Law is a software-specific manifestation of the broader principle that users will find and rely on every possible aspect of a system.
Considerations
Documentation
Comprehensive documentation is vital. Developers should document not only the intended behaviors but also any observable behaviors that users might rely on.
Communication
Effective communication with users is essential. Informing users about potential changes and gathering feedback can help in managing dependencies and reducing the impact of changes.
Practical Applications
API Design
When designing APIs, developers should consider Hyrum's Law and strive to minimize observable behaviors that are not part of the intended contract. This can be achieved through careful design and thorough documentation.
Legacy Systems
For legacy systems, understanding Hyrum's Law can help in managing dependencies and planning for changes. Developers should identify critical observable behaviors and ensure they are preserved during updates.
Limitations
Scope
Hyrum's Law primarily applies to systems with a large number of users. In smaller systems, the impact of unintended dependencies may be less significant.
Evolution
Software systems must evolve, and Hyrum's Law can sometimes hinder this evolution. Developers must balance the need for stability with the need for progress.
References
- Hyrum Wright, "Hyrum's Law: The Hidden Cost of Software Dependencies," ACM Queue, 2018.
- Martin Fowler, "API Design Principles," martinfowler.com, 2019.
- Robert C. Martin, "Clean Code: A Handbook of Agile Software Craftsmanship," Prentice Hall, 2008.
Epilog
By understanding and applying Hyrum's Law, developers can create more robust and reliable software systems. While it imposes certain constraints, it also offers valuable insights into the nature of software dependencies and the importance of maintaining observable behaviors.