content: add "Go Modules: v2 and Beyond" article

Change-Id: I1ee6d40da259e7082916d469b8d3f30bcc35898a
Reviewed-on: https://go-review.googlesource.com/c/blog/+/205557
Reviewed-by: Jay Conrod <jayconrod@google.com>
diff --git a/content/migrating-to-go-modules.article b/content/migrating-to-go-modules.article
index 6889fdc..975e706 100644
--- a/content/migrating-to-go-modules.article
+++ b/content/migrating-to-go-modules.article
@@ -11,6 +11,7 @@
 - Part 1 — [[/using-go-modules][Using Go Modules]]
 - *Part*2*—*Migrating*To*Go*Modules* (this post)
 - Part 3 — [[/publishing-go-modules][Publishing Go Modules]]
+- Part 4 — [[/v2-go-modules][Go Modules: v2 and Beyond]]
 
 Go projects use a wide variety of dependency management strategies. [[https://golang.org/cmd/go/#hdr-Vendor_Directories][Vendoring]] tools such as [[https://github.com/golang/dep][dep]] and [[https://github.com/Masterminds/glide][glide]] are popular, but they have wide differences in behavior and don't always work well together. Some projects store their entire GOPATH directory in a single Git repository. Others simply rely on `go`get` and expect fairly recent versions of dependencies to be installed in GOPATH.
 
diff --git a/content/publishing-go-modules.article b/content/publishing-go-modules.article
index c9a37e5..8edc5e3 100644
--- a/content/publishing-go-modules.article
+++ b/content/publishing-go-modules.article
@@ -11,13 +11,13 @@
 - Part 1 — [[/using-go-modules][Using Go Modules]]
 - Part 2 — [[/migrating-to-go-modules][Migrating To Go Modules]]
 - *Part*3*—*Publishing*Go*Modules* (this post)
+- Part 4 — [[/v2-go-modules][Go Modules: v2 and Beyond]]
 
 This post discusses how to write and publish modules so other modules can depend
 on them.
 
-Please note: this post covers development up to and including `v1`. A future
-article will cover developing a module at `v2` and beyond, which requires
-changing the module's path.
+Please note: this post covers development up to and including `v1`. If you are
+interested in `v2`, please see [[/v2-go-modules][Go Modules: v2 and Beyond]].
 
 This post uses [[https://git-scm.com/][Git]] in examples.
 [[https://www.mercurial-scm.org/][Mercurial]],
diff --git a/content/using-go-modules.article b/content/using-go-modules.article
index c5380ee..ea13545 100644
--- a/content/using-go-modules.article
+++ b/content/using-go-modules.article
@@ -13,6 +13,7 @@
 - *Part*1*—*Using*Go*Modules* (this post)
 - Part 2 — [[/migrating-to-go-modules][Migrating To Go Modules]]
 - Part 3 — [[/publishing-go-modules][Publishing Go Modules]]
+- Part 4 — [[/v2-go-modules][Go Modules: v2 and Beyond]]
 
 Go 1.11 and 1.12 include preliminary
 [[https://golang.org/doc/go1.11#modules][support for modules]],
@@ -22,7 +23,6 @@
 and easier to manage.
 This blog post is an introduction to the basic operations needed
 to get started using modules.
-A followup post will cover releasing modules for others to use.
 
 A module is a collection of
 [[https://golang.org/ref/spec#Packages][Go packages]]
diff --git a/content/v2-go-modules.article b/content/v2-go-modules.article
new file mode 100644
index 0000000..f66f134
--- /dev/null
+++ b/content/v2-go-modules.article
@@ -0,0 +1,182 @@
+Go Modules: v2 and Beyond
+7 Nov 2019
+Tags: tools, versioning
+
+Jean de Klerk
+
+Tyler Bui-Palsulich
+
+* Introduction
+
+This post is part 4 in a series.
+
+- Part 1 — [[/using-go-modules][Using Go Modules]]
+- Part 2 — [[/migrating-to-go-modules][Migrating To Go Modules]]
+- Part 3 — [[/publishing-go-modules][Publishing Go Modules]]
+- *Part*3*—*Go*Modules:*v2*and*Beyond* (this post)
+
+As a successful project matures and new requirements are added, past features
+and design decisions might stop making sense. Developers may want to integrate
+lessons they've learned by removing deprecated functions, renaming types, or
+splitting complicated packages into manageable pieces. These kinds of changes
+require effort by downstream users to migrate their code to the new API, so they
+should not be made without careful consideration that the benefits outweigh the
+costs.
+
+For projects that are still experimental — at major version `v0` — occasional
+breaking changes are expected by users. For projects which are declared stable
+— at major version `v1` or higher — breaking changes must be done in a new major
+version. This post explores major version semantics, how to create and publish a new
+major version, and how to maintain multiple major versions of a module.
+
+* Major versions and module paths
+
+Modules formalized an important principle in Go, the
+[[https://research.swtch.com/vgo-import][*import*compatibility*rule*]]:
+
+    If an old package and a new package have the same import path,
+    the new package must be backwards compatible with the old package.
+
+By definition, a new major version of a package is not backwards compatible with
+the previous version. This means a new major version of a module must have a
+different module path than the previous version. Starting with `v2`, the major
+version must appear at the end of the module path (declared in the `module`
+statement in the `go.mod` file). For example, when the authors of the module
+`github.com/googleapis/gax-go` developed `v2`, they used the new module path
+`github.com/googleapis/gax-go/v2`. Users who wanted to use `v2` had to change
+their package imports and module requirements to `github.com/googleapis/gax-go/v2`.
+
+The need for major version suffixes is one of the ways Go modules differs from
+most other dependency management systems. Suffixes are needed to solve
+the [[https://research.swtch.com/vgo-import#dependency_story][diamond dependency problem]].
+Before Go modules, [[http://gopkg.in][gopkg.in]] allowed package maintainers to
+follow what we now refer to as the import compatibility rule. With gopkg.in, if
+you depend on a package that imports `gopkg.in/yaml.v1` and another package that
+imports `gopkg.in/yaml.v2`, there is no conflict because the two `yaml` packages
+have different import paths — they use a version suffix, as with Go modules.
+Since gopkg.in shares the same version suffix methodology as Go modules, the Go
+command accepts the `.v2` in `gopkg.in/yaml.v2` as a valid major version suffix.
+This is a special case for compatibility with gopkg.in: modules hosted at other
+domains need a slash suffix like `/v2`.
+
+* Major version strategies
+
+The recommended strategy is to develop `v2+` modules in a directory named after
+the major version suffix.
+
+    github.com/googleapis/gax-go @ master branch
+    /go.mod    → module github.com/googleapis/gax-go
+    /v2/go.mod → module github.com/googleapis/gax-go/v2
+
+This approach is compatible with tools that aren't aware of modules: file paths
+within the repository match the paths expected by `go`get` in `GOPATH` mode.
+This strategy also allows all major versions to be developed together in
+different directories.
+
+Other strategies may keep major versions on separate branches. However, if
+`v2+` source code is on the repository's default branch (usually `master`),
+tools that are not version-aware — including the `go` command in `GOPATH` mode
+— may not distinguish between major versions.
+
+The examples in this post will follow the major version subdirectory strategy,
+since it provides the most compatibility. We recommend that module authors
+follow this strategy as long as they have users developing in `GOPATH` mode.
+
+* Publishing v2 and beyond
+
+This post uses `github.com/googleapis/gax-go` as an example:
+
+    $ pwd
+    /tmp/gax-go
+    $ ls
+    CODE_OF_CONDUCT.md  call_option.go  internal
+    CONTRIBUTING.md     gax.go          invoke.go
+    LICENSE             go.mod          tools.go
+    README.md           go.sum          RELEASING.md
+    header.go
+    $ cat go.mod
+    module github.com/googleapis/gax-go
+    
+    go 1.9
+    
+    require (
+        github.com/golang/protobuf v1.3.1
+        golang.org/x/exp v0.0.0-20190221220918-438050ddec5e
+        golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3
+        golang.org/x/tools v0.0.0-20190114222345-bf090417da8b
+        google.golang.org/grpc v1.19.0
+        honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099
+    )
+    $
+
+To start development on `v2` of `github.com/googleapis/gax-go`, we'll create a
+new `v2/` directory and copy our package into it.
+
+    $ mkdir v2
+    $ cp *.go v2/
+    building file list ... done
+    call_option.go
+    gax.go
+    header.go
+    invoke.go
+    tools.go
+    
+    sent 10588 bytes  received 130 bytes  21436.00 bytes/sec
+    total size is 10208  speedup is 0.95
+    $
+
+Now, let's create a v2 `go.mod` file by copying the current `go.mod` file and
+adding a `v2/` suffix to the module path:
+
+    $ cp go.mod v2/go.mod
+    $ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
+    $
+
+Note that the `v2` version is treated as a separate module from the `v0`/`v1`
+versions: both may coexist in the same build. So, if your `v2+` module has
+multiple packages, you should update them to use the new `/v2` import path:
+otherwise, your `v2+` module will depend on your `v0`/`v1` module. For example,
+to update all `github.com/my/project` references to `github.com/my/project/v2`,
+you can use `find` and `sed`:
+
+    $ find . -type f \
+        -name '*.go' \
+        -exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;
+    $
+
+Now we have a `v2` module, but we want to experiment and make changes before
+publishing a release. Until we release `v2.0.0` (or any version without a
+pre-release suffix), we can develop and make breaking changes as we decide on
+the new API. If we want users to be able to experiment with the new API before
+we officially make it stable, we can publish a `v2` pre-release version:
+
+    $ git tag v2.0.0-alpha1
+    $ git push origin v2.0.0-alpha1
+    $
+
+Once we are happy with our `v2` API and are sure we don't need any other breaking
+changes, we can tag `v2.0.0`:
+
+    $ git tag v2.0.0
+    $ git push origin v2.0.0
+    $
+
+At that point, there are now two major versions to maintain. Backwards
+compatible changes and bug fixes will lead to new minor and patch releases
+(for example, `v1.1.0`, `v2.0.1`, etc.).
+
+* Conclusion
+
+Major version changes result in development and maintenance overhead and
+require investment from downstream users to migrate. The larger the project,
+the larger these overheads tend to be. A major version change should only come
+after identifying a compelling reason. Once a compelling reason has been
+identified for a breaking change, we recommend developing multiple major
+versions in the master branch because it is compatible with a wider variety of
+existing tools.
+
+Breaking changes to a `v1+` module should always happen in a new, `vN+1` module.
+When a new module is released, it means additional work for the maintainers and
+for the users who need to migrate to the new package. Maintainers should
+therefore validate their APIs before making a stable release, and consider
+carefully whether breaking changes are really necessary beyond `v1`.