I guess maybe I should start with what led us here, right? We released
go get about eight years ago now, and if you go back and read the mail thread, the very first thing that someone asked was “Well, what are you gonna do about versions?” and we said “I don’t know, we’ll find out.”
go get has actually been fairly useful, but of course, not having versions hinders various things… So we started these discussions at GopherCon in 2016, and then into the fall, and that led to dep being released.
The really important thing that dep did is that it got package authors thinking explicitly about issuing releases that are tagged with versions, and users thinking about consuming tagged versions, and this was something that
go get had not had; everyone was just “I’ll put my code out there, and you pick a commit that looks good to you. Even though they have these random hex numbers, just pick one you like.”
So this idea that “I’m gonna mark the ones that I think you should be using, and you probably shouldn’t be using the other ones” is really an important social change for the community, and I think that that’s the most important thing that’s happened as far as like changing people’s behaviors.
But there’s this problem that was really bugging me about a year ago that I couldn’t articulate at first… It was that one of the major goals of Go is to work well for these really large-scale software developments, and that means you have to have gradual changes. And by gradual I mean that you’ve got some change that you wanna make throughout your whole project, and it has to be okay to make that change one package, or maybe even one file at a time, because you’ve just got too much source code to change it all in one commit.
[00:16:12.14] I gave a talk at GothamGo a few years ago, showing how important it was to make gradual changes for various code repair, and I was showing in particular how type aliases are essentially required for that kind of gradual change when you’re moving a type from one package to another.
A similar problem happens when you need to update a large program from using v1 of a package to v2 of a package. You can’t expect that the entire project is gonna move from v1 to v2 in one commit. For one thing, the code is coming from different repositories, so there’s no such thing as one commit. So once your program gets big enough, it absolutely has to be the case that you can migrate the program a little at a time. One part of it is now on v2, now more of it is on v2, and eventually it’s all converted, but it’s this gradual thing and you’ve got a working program the whole time.
So I was thinking about, you know, how is this gonna apply? Dep’s design really forces you to decide; it says “For the entire build, I wanna know which one version I’m gonna use.” This seems like — if one of Go’s goals is to work for software at scale, this isn’t gonna actually work.
I thought a lot about this, and this led me to this idea that, well, if we’re gonna take semver, which is what people want and kind of expect – everyone is expecting semver – then semver actually gives us a way to talk about this, because they have this idea of a major version, and if the major version is the same, and otherwise the version is newer, then it’s supposed to be backwards-compatible with this older one. But when the major version changes, then it’s okay to make breaking changes.
So if you just put the major version in the import path, now you’ve established that any particular import path should never change what it means. New things might get added, but things shouldn’t be removed, things shouldn’t break. And if you do that – and I call this now Semantic Import Versioning – then a lot of other things get a lot simpler, and a lot of the complexity that’s involved in selecting which version you’re gonna use and all that sort of stuff, a lot of that complexity just melts away.
This took me probably six months to realize… I’m mostly doing other things; I get pulled off for other projects at Google sometimes. But around November of last year – that was sort of the a-ha moment that I had when I said “Wow… If we do this, it really seems that this might work really well.”
Then I spent a chunk of the next couple months prototyping this idea, trying to convince myself that it was worth sharing with people. Then of course in mid-February I posted a whole lot of text about it, and that’s where we are now.