Live data from Hacker News

Hyrum’s Law in Golang

abenezer.org

41–50 of 190 posts

Re: Hyrum’s Law in Golang

#41
post #11
post #5

Solution to the specifically mentioned problem: Don't use string-based errors, use sentinel errors [1]. More generally: Don't produce code where consumers of your API are the least bit inclined to rely on non-technical strings. Instead use first-level language constructs like predefined error values, types or even constants that contain the non-technical string so that API consumers can compare the return value again…

The frustrating thing is that the error in question already is a sentinel error -- Grafana (the top-level culprit in the linked search) should be using `errors.As(&http.MaxBytesError{})` rather than doing a string compare. The whole point of Hyrum's Law is that it doesn't matter how well you design your API: no matter what, people will depend on its behavior rather than its contract.

But it looks like that until 3 years ago, this string comparison was the only way to do it. https://github.com/golang/go/pull/49359/files

Re: Hyrum’s Law in Golang

#42
post #11
post #5

Solution to the specifically mentioned problem: Don't use string-based errors, use sentinel errors [1]. More generally: Don't produce code where consumers of your API are the least bit inclined to rely on non-technical strings. Instead use first-level language constructs like predefined error values, types or even constants that contain the non-technical string so that API consumers can compare the return value again…

The frustrating thing is that the error in question already is a sentinel error -- Grafana (the top-level culprit in the linked search) should be using `errors.As(&http.MaxBytesError{})` rather than doing a string compare. The whole point of Hyrum's Law is that it doesn't matter how well you design your API: no matter what, people will depend on its behavior rather than its contract.

Early Go lacked lots of features such as errors.As. It was and still is sometimes idiomatic to generate Go because it is so featureless and writing it is often a chore. So it is very much about how well you design your API.

Re: Hyrum’s Law in Golang

#45
post #11

Earlier quoted context omitted.

The frustrating thing is that the error in question already is a sentinel error -- Grafana (the top-level culprit in the linked search) should be using `errors.As(&http.MaxBytesError{})` rather than doing a string compare. The whole point of Hyrum's Law is that it doesn't matter how well you design your API: no matter what, people will depend on its behavior rather than its contract.

But it looks like that until 3 years ago, this string comparison was the only way to do it. https://github.com/golang/go/pull/49359/files

Good catch. So in a sense this isn't really Hyrum's Law (which would be more appropriate to things like the Sim City / Windows 3.x UAF bug described in a sibling comment); it's more like, if people need to do something, and you don't give people an explicit way to do it, they'll find an implicit way, and then you're stuck supporting whatever that happened to be.

Re: Hyrum’s Law in Golang

#46

Earlier quoted context omitted.

As a user of your code this is true, and I'm very grateful indeed that you take this approach. I would add as a slight caveat that to benefit from this policy, users absolutely must read the release notes on major go versions before upgrading. We recently didn't, and we were burnt somewhat by the change to disallow negative serial numbers in the x509 parser without enabling the new feature flag. Completely our fault…

We have gotten a liiiiittle more liberal ever since we introduced the new GODEBUG feature flag mechanism. I've been meaning to write a "how to safely update Go" post for a while, because the GODEBUG mechanism is very powerful but not well-known and we could build a bit of tooling around it. In short, you can upgrade your toolchain without changing the go.mod version, and these things will keep working like they did,…

That sounds good.

Breaking changes in major version updates is a completely normal thing in most software and we usually check for it. Ironically the only reason we weren't previously bothering in go is that the maintainers were historically so hyper-focused on absolute backwards compatibility that there were never any breaking changes!

Re: Hyrum’s Law in Golang

#47
post #5

Solution to the specifically mentioned problem: Don't use string-based errors, use sentinel errors [1]. More generally: Don't produce code where consumers of your API are the least bit inclined to rely on non-technical strings. Instead use first-level language constructs like predefined error values, types or even constants that contain the non-technical string so that API consumers can compare the return value again…

Code that checks raw error strings is just plain bad and should be exempt from Go’s backwards compatibility guarantees. There is almost never an excuse for it, especially in stdlib.

Re: Hyrum’s Law in Golang

#48
An interesting topic is how to fight Hyrum's law. A possibility is to add randomness in things you don't want people to rely on. If I remember well, this is what the QUIC protocol does. Some fields are unused in the current version, but required by the specification to be set to random values, not null bytes, so that routers don't start relying on them to identify the packets.

EDIT.

I think I found the source: https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1

> The value in the Unused field is set to an arbitrary value by the server. Clients MUST ignore the value of this field. [...] Note that other versions of QUIC might not make a similar recommendation.

I think they call it "greasing", to prevent "ossification".

Re: Hyrum’s Law in Golang

#50
post #5

Solution to the specifically mentioned problem: Don't use string-based errors, use sentinel errors [1]. More generally: Don't produce code where consumers of your API are the least bit inclined to rely on non-technical strings. Instead use first-level language constructs like predefined error values, types or even constants that contain the non-technical string so that API consumers can compare the return value again…

Using string error comparisons was the only way to do this few years ago; and Go has a backwards compatibility promise.
Post reply on HN