GoModule:v2及新版本(Go Modules: v2 and Beyond譯文)

GoModule:v2及新版本

英文原版:https://blog.golang.org/v2-go-modules

介紹

這是系列文章的第四部分

隨着項目中新需求的添加,之前的功能和設計可能不太合適。開發者可能移除廢棄的function,重命名type、或者將package分割成更好管理的多個部分。這種變動需要下游使用者調整代碼來適應新的API,因此在做這種改動之前要仔細權衡利弊。

處於實驗階段的項目(majro版本爲v0)可能會有大的改動,而stable階段的項目(major版本爲v1或以上)如果有大的改動則需要發佈新的major版本。本文主要介紹如何發佈新的major版本以及如何維護多個majro版本。

majro版本及module路徑

module的正式且重要的規則:import compatibility rule

如果新的包與舊的包使用相同的導包路徑,那麼新的包必須兼容舊的包

根據定義,package的新major版本不會兼容之前的版本,意味着新的major版本必須有與之前版本不同的module路徑。從v2開始,major版本必須出現在module路徑的結尾(在go.mod文件的module語句中聲明)。例如,當github.com/googleapis/gax-go發佈了v2版本,那新的module路徑就是github.com/googleapis/gax-go/v2,使用v2的用戶需要修改import爲github.com/googleapis/gax-go/v2

major版本作爲後綴是GoModule與其他依賴管理的區別之一。後綴需要解決diamond dependency problem。在GoModule之前,gopkg.in允許package維護人員遵循我問現在稱之爲import compatibility rule的內容。對於gopkg.in,如果當前依賴包的import是gopkg.in/yaml.v1且另一個包的import是gopkg.in/yaml.v2這種,跟新的規則並不衝突,因爲這兩個yaml包的導包路徑不同。go命令接受.v2這種major版本作爲路徑後綴,這是爲gopkg.in做的特殊兼容,其他域名的module仍應使用/v2這種後綴。

major版本策略

推薦的策略是在新的以major版本後綴命名的目錄下進行v2級以上版本的開發。

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

這種方法兼容非module模式的工具:代碼庫的文件路徑與GOPATH模式下的go get兼容,這個策略也允許各個major版本在獨立的目錄下開發。

有的策略將不同majro版本放在不同分支,但是如果v2及以上的代碼在代碼庫的默認分支上,那麼不支持版本的工具(包括GOPATH模式下的go命令)可能無法識別major版本。

本文的示例將遵循major版本子目錄的策略,這樣可以保證最大的兼容性。我們建議module開發者遵循這種策略使得其用戶也可以在GOPATH模式下開發。

發佈v2及以上版本

本文以github.com/googleapis/gax-go爲例:

$ 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
)
$

要開始v2版本的開發,首先新建一個v2文件夾並將package複製進去

$ 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
$

現在從當前go.mod創建一個v2的go.mod並添加v2後綴到module路徑中:

$ cp go.mod v2/go.mod
$ go mod edit -module github.com/googleapis/gax-go/v2 v2/go.mod
$

注意v2版本會認爲是與v0、v1獨立的版本:這兩個版本共存在同一個build。所以如果v2級以上版本的module用於多個package,他們都需要升級到新的/v2導包路徑:除非v2及以上版本依賴v0或v1版本。例如升級所有的github.com/my/project裏面對github.com/my/project/v2的引用,可以使用findsed

$ find . -type f \
    -name '*.go' \
    -exec sed -i -e 's,github.com/my/project,github.com/my/project/v2,g' {} \;
$

現在就有了v2的module,但是我們想在發佈之前先試一下。在發佈v2.0.0(或其他非預發佈版本)之前,仍可以開發新的API或者做重大改動。如果想讓用戶在我們發佈新版本前實驗新的API,可以先發布v2的預發佈版本:

$ git tag v2.0.0-alpha.1
$ git push origin v2.0.0-alpha.1
$

一旦我們認爲v2版本的API可用,並且確定不需要再做其他大改動,可以打上v2.0.0的tag:

$ git tag v2.0.0
$ git push origin v2.0.0
$

這時就維護了兩個major版本,兼容修改或者bug修復將需要發佈新的minor或者patch版本(如v1.1.0、v2.0.1等)。

總結

升級major版本會帶來開發及維護成本,並且下游的用戶需要做點事情才能進行遷移。項目越大開銷越大,所以最好在確實需要的情況下進行major版本的升級。一旦確定了有重大變更,建議在master分支中開發多個major版本,這樣可以與其他現有工具兼容。

對v1及以上module做重大變更應始終發生在vN+1版本上。發佈新module意味着開發維護人員需要做更多的工作來遷移到新版本。因此請在發佈新版本前驗證其API並仔細考慮是否有必要在v1之後做重大變更。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章