Treating Hyrum's Law as something to pay attention to when improving software is a grave error.
There are good reasons to change undocumented behaviors with each release just to discourage dependence on them. E.g., change hash functions. People will squawk, but will be better off.
Probably the best thing is to throw exceptions from functions that used to not. People who imagine that having searched the whole call tree one time means anything deserve to be surprised. Cleanup code should always be in destructors where it will be exercised properly on every run.
I recall a bit of drama in Linux land was when ext4 broke the "write temp file + rename over old one" classic technique for safely rewriting config files. People ended up with data loss and were outraged. ext4 devs said "But POSIX never actually promised this! Doing things our way is much better performance. Add extra fsyncs to actually get things to stick".
The result as I recall was a lot of drama back and forth.
The drama was because POSIX formally offered no way to get the needed semantics without crazy changes. Shells would have had to be made very very slow. And the things made faster were already fast, and not even very important to have fast.
When shells that trace back to v6 Unix depend on a behavior, that being undocumented is a bug in documentation.
I think the lesson there is that "the spec is what the program currently does" doesn't work well for the behaviour around rare errors.
(POSIX was a red herring: Linux has never limited itself to POSIX, and anyway POSIX didn't promise that doing things the way the ext4 maintainer recommended would work either.)
Depends on what the API is, right? Like, Linux has this law encoded as “don’t break userland”, ie a very absolutist interpretation. This makes sense because the people affected by a breaking Linux API change are not the people responsible for shipping code that depends on undocumented behaviour.
But for a lot of APIs, including nearly all OSS libraries that are only updated by the developer using them, your stance makes a lot more sense.
> There are good reasons to change undocumented behaviors with each release just to discourage dependence on them. E.g., change hash functions. People will squawk, but will be better off.
How is that not paying attention to Hyrum's Law, something you just told us to not do? Hyrum's Law explicitly does not say to never change undocumented behaviors, and what you propose is a reaction to the observation in it.
Postel's law (or robustness principle) states that you should be liberal in what you accept, conservative in what you output. Hyrum's law shows the danger in being liberal in what you accept.
(Shameless plug: I've just made public an open source CLI flashcard app where the example deck includes a set of Hacker Laws including the aforementioned ones, you can try it here: https://github.com/SteveRidout/flashdown)
This is an interesting point. Taken to its extreme, Postel's law will trade some abstraction for robustness. Conversely, Hyrum's law will trade some robustness for abstraction.
Postel's law has turned out to be a disaster for security, and for extensibility. If everything you can get already means something, nothing can ever mean anything new.
"Be clear about what you will accept", instead. And, make sure there is an easy way to discover why it was not accepted.
There are different degrees of "pay attention". You should consider how Hyrum's Law affects your development; that is, feel free to change that hash function but be aware it's going to break someone.
What I think you mean is: don't live in fear of Hyrum's Law.
In fact, Hyrum Wright and Titus Winters (the person who named Hyrum’s Law) both spend a large amount of their time specifically upgrading through Hyrum’s Law examples.
This sounds like its own huge maintenance burden for me as a library developer. If I picked a particular hash function, it's because it fulfilled my requirements. I'm not necessarily going to have a list of backup options that meet those requirements and also don't negatively impact other parts of my own code.
There are good reasons to change undocumented behaviors with each release just to discourage dependence on them. E.g., change hash functions. People will squawk, but will be better off.
Probably the best thing is to throw exceptions from functions that used to not. People who imagine that having searched the whole call tree one time means anything deserve to be surprised. Cleanup code should always be in destructors where it will be exercised properly on every run.