摘要:你可以使用這個佈局模版作爲你的 Go 項目的起點: https://github.com/golang-standards/project-layout [24]。一些項目將內部庫放在 pkg 目錄下,以便保持與其它部分代碼結構的一致。

點擊上方藍色“ Go語言中文網 ”關注我們, 領全套Go資料 ,每天學習 Go 語言

本文還是基於 GOPATH,這塊忽略,其他部分可以借鑑

讀過了 `Tour of Go` [1] ,在 https://play.studygolang.com/ [2] 上把玩過,然後你感覺你準備好寫一些代碼了。 很棒! 但是,你不確定該如何組織你的項目。 可以將代碼放在你想放的任意地方嗎? 有沒有組織代碼的標準方式? 如果想有多個應用程序的二進制文件呢? “go getable” 是指什麼? 你可能會問自己這些問題。

首先,你必須瞭解 Go 的工作空間。 `How to Write Go Code` [3] 是個很好的起點。缺省地,Go 將所有代碼保管在同一個工作空間,並期望所有代碼都在同一個工作空間。這個地方由環境變量 GOPATH 來標識。對你來說這意味着什麼?意味着你必須 將代碼放在默認的工作空間 或者必須修改 GOPATH 環境變量,指向你自己的代碼位置。不管哪種方式,項目的真正源代碼都需要放在 src 子目錄下(即 $GOPATH/src/your_project $GOPATH/src/github.com/your_github_username/your_project )。技術上講,如果你無需導入外部包且使用相對路徑導入自己的代碼,你的工程不一定非要放在工作空間裏,但不推薦這樣做。不過玩具項目或概念驗證(Poc)項目這麼做是可以的。Go 1.1 確實引入了模塊的概念,允許你將項目代碼放在 GOPATH 之外,且不受上述的導入限制,但直到現在這還是一個實驗性的功能。

你已經將你的項目目錄放在正確的地方。接下來呢?

對於你是唯一開發者的概念驗證(Poc)項目或特別小的項目,將項目代碼都寫在根目錄下的 main.go 裏就夠了。如果知道你的項目將會變得足夠大或者它會上生產環境,而且其他人會貢獻代碼,那你就應該考慮至少採用這裏羅列的項目佈局樣式中的一些。

有一些項目佈局樣式在 Go 生態系統中脫穎而出。 cmdpkg 目錄是最常見的兩個樣式。你應當採用這些樣式,除非你的項目特別小。

cmd 佈局樣式在你需要有多個應用程序二進制文件時十分有用。每個二進制文件擁有一個子目錄(即 your_project/cmd/your_app )。這個樣式幫助保持你的項目下的包(project/package) ‘go gettable’。什麼意思?這意味着你可以使用 go get 命令拉取(並安裝)你的項目,項目的應用程序以及庫(比如, go get github.com/your_github_username/your_project/cmd/appxg )。你不必非要拆分應用程序文件,通過設置正確的 go build 標記你可以構建每個應用程序,但是由於不知道該構建哪個應用程序, go get 就無法正常工作了。官方的 Go tools [4]cmd 佈局樣式的一個例子。很多知名的項目也使用了同樣的樣式: Kubernetes [5] , Docker [6] , Prometheus [7] , Influxdb [8]

pkg 佈局樣式也十分受歡迎。對新手 Go 開發者來講這是最容易混淆的一個包結構概念,因爲 Go 的工作空間就有一個同名的目錄但那個目錄有不同的用途(用來存儲 Go 編譯器構建的包的 object 文件)。 pkg 目錄是放置公共庫的地方。它們可以被你的應用內部使用。也可供外部項目使用。這是你和你代碼的外部使用者之間的非正式協定。其它項目會導入這些庫並期望它們正常工作,所以在把東西放到這裏前請三思。很多知名的項目使用了這個樣式: Kubernetes [9] , Docker [10] , Grafana [11] , Influxdb [12] , Etcd [13] .

pkg 目錄下的某些庫並不總是爲了公共使用。爲什麼呢?因爲很多現有的 Go 項目誕生在能隱藏內部包之前。一些項目將內部庫放在 pkg 目錄下,以便保持與其它部分代碼結構的一致。另外一些項目將內部庫放置在 pkg 目錄之外另外的目錄裏。 Go 1.4 [14] 引入了使用 internal 隱藏內部庫的能力。什麼意思呢?如果你將代碼放在 ‘internal’目錄,外部項目則無法導入那些代碼。即使是項目內部的其它代碼,如果不在 internal 目錄的父目錄裏,也無法訪問這些內部代碼。這個功能使用還不廣泛因爲它相對較新;但是作爲一個額外(在 Go 用大小寫區分函數可見性的規則之外)的控制層它有極大價值。很多知名的項目使用了這個樣式: Dep [15] , Docker [16] , Nsq [17] , Go Ethereal [18] , Contour [19]

internal 目錄是放置私有包的地方。你可以選擇性地添加額外的結構來分離內部共享的庫(比如, your_project/internal/pkg/your_private_lib )以及不希望別人導入的應用程序代碼(比如, your_project/internal/app/your_app )。當你將全部私有代碼都放在 ‘internal’ 目錄, cmd 目錄下的應用程序就可以被約束成一些小文件,其只需定義對應於應用程序二進制文件的 ‘main’ 函數。其餘代碼都從 internalpkg 目錄導入(Heptio 中的 ark [20] ,以及 Grafana 中的 loki [21] ,是這個 微型 main 函數 包樣式的好例子)。

如果你 fork 並修改了外部項目的一塊該如何?有些項目將這些代碼放在 pkg 目錄下,但更好的做法是將它放在頂層目錄下的 third_party 目錄,以便將你自己的代碼和你從別人那裏借用的代碼區分開來。

你在項目裏導入的外部包呢?它們去哪裏?你有幾個選項。你可以將它們放在項目以外。使用 go get 安裝的包將保存在你的 Go 工作空間。大部分情況下可以正常工作,但視具體包而定,它可能會變得脆弱和不可預測,因爲別人在構建你的項目時他們可能會拿到這個包的一個不向後兼容的版本。解決辦法是 ‘vendoring’。使用 ‘vendoring’ 你通過將依賴與項目一起提交來將它們固定。 Go 1.6 [22] 導入了一種標準的方式來 ‘vendor’ 外部包(在 Go 1.5 中是實驗性功能)。將外部包放在 vendor 目錄。這與 third_party 目錄有何區別呢?如果你導入了外部代碼且原樣使用它就放在 vendor 目錄。如果你使用的是修改版的外部包就放在 third_party 目錄。

如果你想學習更多關於其他 Go 項目使用的項目結構請閱讀 ‘Analysis of the Top 1000 Go Repositories’ [23] 。它有點陳舊,不過依然有用。

一個真正的項目也會有另外的目錄。你可以使用這個佈局模版作爲你的 Go 項目的起點: https://github.com/golang-standards/project-layout [24] 。它涵蓋了這篇博客裏描述的 Go 項目佈局樣式幷包括很多你需要的支持目錄。

現在是時候寫些代碼了!如果你還沒安裝 Go 請查看這個 quick setup guide for Mac OS X [25] (其他平臺的安裝也是類似的)。如果還沒瀏覽過請你瀏覽 ‘Tour of Go’ [26] ,然後讀一下 ’50 Shades of Go’ [27] 去了解 Go 中最常見的坑,這會在你開始寫代碼和調試代碼時節省很多時間。

  • Golang [28]

  • Go [29]

  • Standards [30]

  • Project Structure [31]

via: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2

作者: Kyle C. Quest [32] 譯者: krystollia [33] 校對: DingdingZhou [34]

本文由 GCTT [35] 原創編譯, Go 中文網 [36] 榮譽推出

參考資料

[1]

Tour of Go : https:/tour.studygolang.com

[2]

https://play.studygolang.com/: https://play.studygolang.com/

[3]

How to Write Go Code : https://golang.org/doc/code.html

[4]

Go tools: https://github.com/golang/tools/tree/master/cmd

[5]

Kubernetes: https://github.com/kubernetes/kubernetes/tree/master/cmd

[6]

Docker: https://github.com/moby/moby/tree/master/cmd

[7]

Prometheus: https://github.com/prometheus/prometheus/tree/master/cmd

[8]

Influxdb: https://github.com/influxdata/influxdb/tree/master/cmd

[9]

Kubernetes: https://github.com/kubernetes/kubernetes/tree/master/pkg

[10]

Docker: https://github.com/moby/moby/tree/master/pkg

[11]

Grafana: https://github.com/grafana/grafana/tree/master/pkg

[12]

Influxdb: https://github.com/influxdata/influxdb/tree/master/pkg

[13]

Etcd: https://github.com/coreos/etcd/tree/master/pkg

[14]

Go 1.4: https://golang.org/doc/go1.4

[15]

Dep: https://github.com/golang/dep/tree/master/internal

[16]

Docker: https://github.com/moby/moby/tree/master/internal

[17]

Nsq: https://github.com/nsqio/nsq/tree/master/internal

[18]

Go Ethereal: https://github.com/ethereum/go-ethereum/tree/master/internal

[19]

Contour: https://github.com/heptio/contour/tree/master/internal

[20]

ark: https://github.com/heptio/ark/blob/master/cmd/ark/main.go

[21]

loki: https://github.com/grafana/loki/blob/master/cmd/loki/main.go

[22]

Go 1.6: https://golang.org/doc/go1.6

[23]

‘Analysis of the Top 1000 Go Repositories’: http://blog.sgmansfield.com/2016/01/an-analysis-of-the-top-1000-go-repositories/

[24]

https://github.com/golang-standards/project-layout: https://github.com/golang-standards/project-layout

[25]

quick setup guide for Mac OS X: https://medium.com/golang-learn/quick-go-setup-guide-on-mac-os-x-956b327222b8

[26]

‘Tour of Go’: https://tour.golang.org/

[27]

’50 Shades of Go’: https://tour.golang.org/

[28]

Golang: https://medium.com/tag/golang

[29]

Go: https://medium.com/tag/go

[30]

Standards: https://medium.com/tag/standards

[31]

Project Structure: https://medium.com/tag/project-structure

[32]

Kyle C. Quest: https://medium.com/@CloudImmunity

[33]

krystollia: https://github.com/krystollia

[34]

DingdingZhou: https://github.com/DingdingZhou

[35]

GCTT: https://github.com/studygolang/GCTT

[36]

Go 中文網: https://studygolang.com/

推薦閱讀

喜歡本文的朋友,歡迎關注“ Go語言中文網

Go語言中文網啓用微信學習交流羣,歡迎加微信: 274768166 ,投稿亦歡迎

相關文章