
Backwards compatibility in Go (2015) - alpb
http://blog.merovius.de/2015/07/29/backwards-compatibility-in-go.html
======
xja
The author is essentially saying any API change has the potential to break
backward compatibility and that we should define what kind of breakage is ok.

That's kind of interesting, and I'd not considered many of the scenarios
mentioned (which apply beyond go).

Perhaps the "correct", but cumbersome thing to do is supply different versions
of the API when maintaining backward compatibility and never change the old
version.

~~~
bottled_poe
There's no need to reinvent the wheel. Semantic versioning already defines a
standard for managing version changes in a pragmatic way.

[http://semver.org/](http://semver.org/)

~~~
alpb
I think you either did not read the article or missed the point. Author says
if you make _seemingly innocent non-breaking changes_ you might think it does
not require a major version change in SemVer but in fact (for instance in case
of adding struct fields) it does.

~~~
zigzigzag
Yes but only in Go. There are projects that have successfully evolved APIs in
not only source compatible but binary compatible ways over a period of
decades. Win32 and Java are the obvious candidates.

Not changing or deleting existing functions and fields is easy. The problem is
that Go apparently doesn't let you reliably add things either. That is kind of
a joke, how is anyone expected to be able to evolve an API if you can't even
add things?

Seems like the consensus is "well it doesn't happen often so it's not an
issue" which is weak. Go isn't even trying for binary compatibility, the
article is only talking about source compat!

~~~
Merovius
> Yes but only in Go.

I don't believe this to be true. I'd say at least _most_ languages/projects
would have exactly the same kind of problems (some of them at runtime, some of
them at compile time), it's just that in practice they don't really matter. So
you don't know about it and it seems, to a casual observer, to work just fine.

> The problem is that Go apparently doesn't let you reliably add things
> either.

Neither does, at least, C. I'd guess that python also doesn't let you do it. I
don't know enough about java, but I'd assume that it has the same problems.

What you need to understand is, that I applied an extremely nit-picky
interpretation of stability. It's not like any of the things I mentioned are
learned from experience or practical problems; I just understand the go type
system enough and thought really hard whether there is an obviously correct
and useful interpretation of API stability under its constraints and came up
with a (mostly theoretical) result. Most projects in go that use SemVer apply
a more generous and naive notion that works well enough in practice. C
projects do exactly the same.

------
ndr
This reminded me of "Spec-ulation" from Rich Hickey [0]

[0]
[https://www.youtube.com/watch?v=oyLBGkS5ICk](https://www.youtube.com/watch?v=oyLBGkS5ICk)

------
Groxx
Well yeah, much of this is true for many languages / libraries. And some of
the more annoying ones that other languages don't tend to suffer from (adding
a method) are largely due to Go's duck-typed interfaces, or the lack of
constructors (there's no way to have optional values, except via factory
methods. you _could_ use nothing but factory methods, but it simplifies
initializers so much you are disincentivized to do so).

------
0xCMP
I think what the author was trying to figure out was not just when you should
do a major/minor version update, but how that could be done automatically. An
example is how in Elm it can detect a major vs minor change and bump your
numbers automatically when you publish. Something like that for Go could be
built into some tool to help package maintainers (public + private) keep
SemVar up to date automatically since there are already types and there are
ways to possibly detect changes since a previous version.

I imagine you could write a tool that would check the previous highest "v*"
tag in git's version of the project vs now using something like go-guru and
determine if any public interfaces were changed and that could automatically
determine if it's a major or minor bump.

~~~
Merovius
You are interpreting me correctly :) Indeed, the article was written when I
started writing that tool and quickly figured out that it was impossible to do
satisfactory.

I'm a mathematician, so the only satisfactory solution to me would be one that
is "clearly correct". As soon as you need to first get agreement about the
definition you are using, you are probably not designing a clean and beautiful
thing :)

~~~
0xCMP
Yea I've had this discussion with a friend of mine who likes Haskell and got
me in to Elm. He claimed you could only get that kind of tool in something
like those languages which have stricter and stronger type systems. I'm not
familiar with the details, but it looks like you ran in to that problem too.

------
alpb
After I posted this I thought of writing a tool that checks if you are making
breaking API changes in your go package. Turns out there is already one:
[https://github.com/bradleyfalzon/apicompat/](https://github.com/bradleyfalzon/apicompat/)

~~~
Merovius
The article was created because I was starting to write a tool to do this.
After sitting down and thinking about it quickly, I came to the conclusion in
the article: There _is_ no non-breaking change (or rather: That determination
can not be made from the package you are looking at). At that point I put the
idea to rest :)

------
nothrabannosir
> Changing a function/method signature

Another reason for methods is a user could have created an interface based on
your method, and assigned your implementing object to a variable of that type.
Changing the method signature makes that assignment invalid.

------
Merovius
Author of the article here. Weird to be on HN ^^ If you have questions, shoot
away.

------
throwaw180ay
> tl;dr: There are next to no "backwards compatible API changes" in go. You
> should explicitely name your compatibility-guarantees.

It's not a problem in languages that come with a package manager, or at least
promote a specific one to handle dependencies.

It's only a problem in languages where developers thinks "you don't need
that". There is this weird belief in the Go community that Go is a miraculous
language where good programming practices don't apply because Go magically
make them irrelevant. It also stems from the Go team itself, which used to
claim that "at Google, we don't need this or that" and then the Go community
spreading the "gospel" : "Go doesn't suit you because it wasn't created for
you"(?!?).

Hopefully Russ Cox sees that light, he even wrote a paper about "Go zealots" (
[https://news.ycombinator.com/item?id=13356531](https://news.ycombinator.com/item?id=13356531)
) and how they refuse any change in the language, even when "teams at Google
needs it". The irony

~~~
Merovius
> It's not a problem in languages that come with a package manager, or at
> least promote a specific one to handle dependencies.

No. It is pretty much _only_ a problem in languages with a package manager.
Languages without the notion of package versioning don't run into the issue of
needing to have a notion of what a version is, clearly. A package manager just
helps automatically enforce versioning, it does zero to help you figure out
what the correct version is.

Yes, not coming with versioning and a package manager comes with its own
disadvantages and pain, no doubt. And we can surely debate which pain
outweighs or is worse. But claiming that package managers would solve this
problem just isn't true (I wrote the article when the whole "SemVer and
package manager for go" debate was taking off and I tried to come up with a
better approach).

> It's only a problem in languages where developers thinks "you don't need
> that". There is this weird belief in the Go community that Go is a
> miraculous language where good programming practices don't apply because Go
> magically make them irrelevant.

Can you source that? I am one of the most vocal opponents of package managers
and versioning in go, but this contradicts everything I believe about it. My
believes aren't, that go doesn't need it, but that a) it comes with its own
set of problems, that b) those outweigh most of the benefits, IMO and c) that
by considering and discussing it carefully, we might be able to come up with
an actually innovative new solution to the problems.

Nowhere do I claim that go doesn't have those problems, on the contrary. I'm
just arguing that, traditionally, go is a language that prefers doing things
right over doing things like they were always done.

