3 ms·
One possible 'solution' to this is to disallow publishing minor versions that break the api, basically compare all the public signatures to see if they change.
by infogulch 8y ago
One possible 'solution' to this is to disallow publishing minor versions that break the api, basically compare all the public signatures to see if they change. E.g. adding a new field is ok, changing a field type is not, adding varargs parameter is ok, changing the order of parameters is not etc etc.
The problem with this solution is that behavior is part of the api, but it is not encoded anywhere that can be compared automatically.
That's exactly what happened in the example in the linked article. Two new fields were added (no problem, that's allowed), and the implementation of another field was changed. This change is either fine because it doesn't change the behavior (refactoring, optimization, fix a bug, etc) or not fine and it changes behavior that breaks existing code, which is what happened in the example.
This behavior was not encoded anywhere, so an automatic publishing gate wouldn't have caught this.
- weberc2 8y agoIt’s not just public signatures, its also things like types—even private types. For example, if public struct type Foo has a private member of private struct type bar, and private type bar is changed to add a field, this changes the public interface because the memory layout of the type has changed.
- ninkendo 8y agoeh... does this matter though? Go uses static linkage, you have to recompile your code when you update third party libraries anyway.
- kasey_junk 8y agoIt can cause behavior changes. Especially around memory usage & gc.
- pjmlp 8y agoThat is not longer the truth for quite some time now. Yes, Go uses static linking by default, but it also supports dynamic linking and also has a plugin concept built on top of it.
- zbentley 8y agoYou are right: signatures do not encompass behavior. Some other examples I have observed: What if the implementation of some (signature-identical) function changed its performance characteristics dramatically, such that it was no longer valid for use in certain scenarios (i.e. something that previously checked the filesystem now makes a costly query against a remote database)? What if a function that was previously thread-safe changed, and became non-thread-safe? What about changes in space (memory) consumed by a function? These aren't rare classes of behavior change, and they certainly aren't rare pathologies for bugs. And, at least in Go, there's no easy way to encode them in the signatures and/or memory layout of your package in such a way that two non-identical versions can be tested for compatibility automatically. These aren't edge cases.
- deleted 8y ago[deleted]
- dolmen 8y agoThe behavior in the example was broken by a release, but could have as well been restored by a patch release. See https://news.ycombinator.com/item?id=17123583 https://news.ycombinator.com/item?id=17123583 I don't see a vgo issue.
- Cthulhu_ 8y agoOne way to enforce this is to never do manual releases. There's a package / standard out there called Conventional Changelog, which enforces a certain style for commits (notably, putting the type of code change in the commit), and which allows a script to automatically change the (semantic) version of a package - if there is any commit with a backwards incompatible change, it'll make it a major release. Of course, this still depends on humans to type the correct commit message. Especially with Node libs, and I can imagine the same is true for go libs, there's no four eyes requirement, little to no review before a version is released.