Hacker News new | ask | show | jobs
by tiziano88 1082 days ago
By definition, if a library is updated (even at the same semver version), something in its behaviour must have changed. By Hyrum's law, that's a breaking change at least for someone. It makes no sense to try and enforce versioning by only looking at the types of an API. In fact that's the least useful way, since the compiler will already trivially catch such mismatches.
5 comments

Hyrum's "law" may claim that somebody out there will run into trouble if I change the internals of my library, but it certainly doesn't say that I have any obligation to care about it.

If you're working for a big company with a monorepo where everyone is trying to live at head, maybe you have to care.

But if I'm giving away my software for free to anyone who cares to use it, I'm entirely comfortable in saying that if you relied on undocumented internals you get to keep both pieces when it breaks.

There might just be new functionality added with no change to existing behavior. And sure, someone might rely on undocumented behavior[1], but that's a bug in their program – nobody can reasonably complain that you've improved performance. Also, the compiler won't necessarily catch this – you might, say, change a Foo parameter to impl Into<Foo> and have it work fine for all your tests, but it might break type inference for some of your users.

[1] which may hint at deficiencies in your library

> There might just be new functionality added with no change to existing behavior.

Even this can be a breaking change for you. Suppose you're writing a bootloader that must fit in 512 bytes and you import a library. If the size of the library plus your code exceeds 512 B, then your program doesn't fit the target and will not compile. Hyrum's law is real.

If your program has to fit in 512 bytes you're probably not pulling in a heap of external libraries?
It doesn't matter. Pick a number. Maybe you have a 650 MiB cap because you're releasing software on CD. Maybe you have a 25 GB cap because you're releasing on BD. Or 100 MB for some app store. Yet, semver only considers API compatibility, not other factors such as binary size. Any minor change could push the size beyond an acceptable limit. The point still stands.
But at a higher, more reasonable limit a tiny change is much less likely to push you over the line.

Also remember it's not the size of the dependency that matters it's the size of the portions of the dependency used less any cross-crate optimizations. So you're always going to have to be careful and test regularly.

Libraries have clear API contacts, especially in Rust where the interfaces are strict and side effects are rarer. The ecosystem is also relatively young, so it hasn't developed true Hyrum's ossification. In practice vast majority of library updates goes smoothly.

> since the compiler will already trivially catch such mismatches

That's too late — that breaks someone else's build. The goal is to check types before publishing an update.

If looking at types is the least useful way to enforce versioning, then what are _any_ better ways?
Do not strictly enforce versioning (still publish guidelines and make tools though). Allow third parties to publish adaptors between different versions instead. The correctness of adaptor can be verified to varying extent in many ways.

People seem to give too much weight to versioning, but it's just a means to communication. Like any other communication mechanism, it's subject to error which should be somehow detected and/or corrected. And versioning only concerns with detection---it doesn't say what you should do when a breaking change is dropped! Focusing to the error correction is more sustainable and user-friendly.

Consumer Driven Contracts is one way https://martinfowler.com/articles/consumerDrivenContracts.ht... (implemented in pact for example).
But the point is not to catch every possible observable change, as you say, any of those could break someone's build or change runtime behaviour in a non-desirable way.

The point is to catch changes that are part of the library's public API. That's something the author can be reasonably expected to evolve in a controlled fashion.

If you care about the internals, the onus in on you.