The blog post argues that the current approach to software versioning and breaking changes, particularly the emphasis on Semantic Versioning (SemVer), is flawed. It contends that breaking changes are inevitable and often subjective, making strict adherence to SemVer impractical and sometimes misleading. Instead of focusing on meticulously categorizing every change, the author proposes a simpler approach: clearly document all changes, regardless of their perceived impact, and empower users with robust tooling to navigate and manage these changes effectively. This includes tools for automated code modification and comprehensive diffing, enabling developers to adapt to changes smoothly even without perfect backwards compatibility. The core message is that thoughtful documentation and effective tooling are more valuable than rigidly adhering to a potentially arbitrary versioning scheme.
Adding an "Other" enum value to an API often seems like a flexible solution for unknown future cases, but it creates significant problems. It weakens type safety, forcing consumers to handle an undefined case and potentially misinterpret data. It also makes versioning difficult, as any new enum value must be mapped to "Other" in older versions, obscuring valuable information and hindering analysis. Instead of using "Other," consider alternatives like an extensible enum, a separate field for arbitrary data, or designing a more comprehensive initial enum. Thorough up-front design reduces the need for "Other" and leads to a more robust and maintainable API.
HN commenters largely agree with Raymond Chen's advice against adding "Other" enum values to APIs. Several commenters share their own experiences of the problems this creates, including difficulty in debugging, versioning issues as new enum members are added, and the loss of valuable information. Some suggest using an associated string value alongside the enum for unexpected cases, or reserving a specific enum value like "Unknown" for situations where the actual value isn't recognized, which provides better forward compatibility. A few commenters point out edge cases where "Other" might be acceptable, particularly in closed systems or when dealing with legacy code, but emphasize the importance of careful consideration and documentation in such scenarios. The general consensus is that the downsides of "Other" typically outweigh the benefits, and alternative approaches are usually preferred.
The Okta bcrypt incident highlights crucial API design flaws that allowed attackers to bypass account lockout mechanisms. By accepting hashed passwords directly, Okta's API inadvertently circumvented its own security measures. This emphasizes the danger of exposing low-level cryptographic primitives in APIs, as it creates attack vectors that developers might not anticipate. The post advocates for abstracting away such complexities, forcing users to interact with higher-level authentication flows that enforce intended security policies, like lockout mechanisms and rate limiting. This abstraction simplifies security reasoning and reduces the potential for bypasses by ensuring all authentication attempts are subject to consistent security controls, regardless of how the password is presented.
Several commenters on Hacker News praised the original post for its clear explanation of the Okta bcrypt incident and the proposed solutions. Some highlighted the importance of designing APIs that enforce correct usage and prevent accidental misuse, particularly with security-sensitive operations like password hashing. The discussion touched on the tradeoffs between API simplicity and robustness, with some arguing for more opinionated APIs that guide developers towards best practices. Others shared similar experiences with poorly designed APIs leading to security vulnerabilities. A few commenters also questioned Okta's specific implementation choices and debated the merits of different hashing algorithms. Overall, the comments reflected a general agreement with the author's points about the need for more thoughtful API design to prevent similar incidents in the future.
Summary of Comments ( 29 )
https://news.ycombinator.com/item?id=43497506
Hacker News users generally agreed with the author's premise that breaking changes are often overemphasized, particularly in the context of libraries. Several commenters highlighted the importance of semantic versioning as a tool for managing change, not a rigid constraint. Some suggested that breaking changes are sometimes necessary for progress and that the cost of avoiding them can outweigh the benefits. A compelling point raised was the distinction between breaking changes for library authors versus application developers, with more leniency afforded to applications. Another commenter offered an alternative perspective, suggesting the "silly" aspect is actually the over-reliance on libraries instead of building simpler solutions in-house. Others noted the prevalence of "dependency hell" caused by frequent updates, even without breaking changes. Finally, the inherent tension between maintaining backwards compatibility and improving software was acknowledged as a complex issue.
The Hacker News post titled "The way we're thinking about breaking changes is silly" generated a moderate amount of discussion with a mix of agreement, disagreement, and nuanced perspectives on the topic of semantic versioning and breaking changes.
Several commenters echoed the author's sentiment that focusing solely on the mechanical aspects of breaking changes, like changing a function signature, misses the broader point of whether a change actually breaks existing user workflows. They argued that a purely semantic approach can lead to situations where a technically non-breaking change (e.g., adding a new parameter with a default value) disrupts user expectations or requires them to modify their code for reasons other than functionality changes. This sentiment was expressed through anecdotes of libraries subtly changing behavior despite adhering to semantic versioning, causing frustration and unexpected integration work for users.
Some commenters took a more pragmatic stance, acknowledging the limitations of semantic versioning but defending its value as a useful tool. They pointed out that while it's not perfect, it provides a baseline level of predictability and allows developers to automate dependency management and updates. They suggested that the problem isn't semantic versioning itself, but rather its misapplication or overly rigid interpretation.
A few commenters offered alternative approaches to managing breaking changes, such as emphasizing thorough testing and communication with users. They suggested that automated tests specifically designed to catch unintended behavioral changes could be more effective than relying solely on semantic versioning. Clear and proactive communication with users about potential changes, even those technically non-breaking, was also highlighted as a key factor in mitigating disruption.
Another line of discussion focused on the trade-offs between stability and evolution. Commenters acknowledged the tension between maintaining backwards compatibility and introducing necessary improvements or new features. They explored strategies like providing long-term support branches for older versions, allowing users to gradually migrate to newer versions without immediate disruption.
There was also discussion about the role of tooling and static analysis in detecting breaking changes. Some commenters suggested that more sophisticated tools could help identify potential issues that might not be caught by a simple semantic version check.
Finally, a few commenters raised the issue of differing interpretations of what constitutes a "breaking change" across different programming languages and communities. They emphasized the importance of clear documentation and community guidelines to ensure consistent understanding and application of versioning principles.