I'm on the other end of the spectrum for this one. Breaking changes in a stable library (i.e. has reached v1) should be totally avoided.
Statically typed languages, fancy features like intellij's structural find and replace, they just don't cut the pain and annoyance of fixing an unexpected change in behaviour of a library in a large code base.
It's just horrific drudge work, utterly unenjoyable, thoughtless labour that needs careful attention.
The go module versioning is clearly designed by someone who has worked on a large many developer code base before.
I can have V2 and V3 linked into my binary at the same time - a blessing for incremental refactoring.
I think you have named the one good argument for this scheme: to allow a go module to exist in several versions in a project.
Before the module system, this was just not possible. Which, in general, is a good idea. Programs today tend to have a too big dependency tree anyway, at least there should be only one copy of a module in the system. However, this is an idealistic view and depending on the number of dependencies, at some point it might not be possible to maintain this idea. npm on the other side goes totally crazy, every module import is local, you can have hundreds of copies of the same module in your system.
The go module approach seems to be like a middle line. It puts a lot of pressure onto module maintainers not to break things within a major revision. They seem to be aware that this is not always guaranteed, that is why the module system not only tracks the major revision, but the exact subrevision of the module. But at least it can enforce, that changes which absolutely do break backwards compatibility are on differen major revisions. Of which you are allowed several inside your project.
Statically typed languages, fancy features like intellij's structural find and replace, they just don't cut the pain and annoyance of fixing an unexpected change in behaviour of a library in a large code base.
It's just horrific drudge work, utterly unenjoyable, thoughtless labour that needs careful attention.
The go module versioning is clearly designed by someone who has worked on a large many developer code base before.
I can have V2 and V3 linked into my binary at the same time - a blessing for incremental refactoring.