如果你嘗試學習 Go,或者你正在為自己建立一個 PoC 或一個玩具專案,這個專案佈局是沒啥必要的。從一些非常簡單的事情開始(一個 main.go 檔案綽綽有餘)。隨著專案的增長,請記住保持程式碼結構良好非常重要,否則你最終會得到一個凌亂的程式碼,這其中就包含大量隱藏的依賴項和全域性狀態。當有更多的人參與這個專案時,你將需要更多的結構。這時候,介紹一種管理包/庫的通用方法是很重要的。當你有一個開源專案時,或者當你知道其他專案從你的專案儲存庫中匯入程式碼時,這時候擁有私有(又名 internal)包和程式碼就很重要。克隆儲存庫,保留你需要的內容,刪除其他所有的內容!僅僅因為它在那裡並不意味著你必須全部使用它。這些模式都沒有在每個專案中使用。甚至 vendor 模式也不是通用的。
Go 1.14 Go Modules 終於可以投入生產了。除非你有特定的理由不使用它們,否則使用 Go Modules 。如果你使用,就無需擔心 $GOPATH 以及專案放置的位置。儲存庫中的 go.mod 檔案基本假定你的專案託管在 Github 上,但這不是要求。模組路徑可以是任何地方,儘管第一個模組路徑元件的名稱中應該有一個點(當前版本的 Go 不再強制使用該模組,但如果使用稍舊的版本,如果沒有 mod 檔案構建失敗的話 ,不要驚訝)。如果你想知道更多資訊,請參閱 Issues 37554 和 32819 。
此專案佈局是通用的,並且不會嘗試強加一個特定的 Go 包結構。
這是社群的努力。 如果看到新的模式,或者認為一個現有的模式需要更新,請提一個 issue。
如果需要命名、格式和樣式方面的幫助,請執行 gofmt 和 golint 。還要確保閱讀這些 Go 程式碼風格的指導方針和建議:
更多關於包的命名和組織以及其他程式碼結構的建議:
GopherCon EU 2018: Peter Bourgon - Best Practices for Industrial ProgrammingGopherCon Russia 2018: Ashley McNamara + Brian Ketelsen - Go best practices.GopherCon 2017: Edward Muller - Go Anti-PatternsGopherCon 2018: Kat Zien - How Do You Structure Your Go AppsGo 目錄/cmd
本專案的主幹。
每個應用程式的目錄名應該與你想要的可執行檔案的名稱相匹配(例如,/cmd/myapp)。
不要在這個目錄中放置太多程式碼。如果你認為程式碼可以匯入並在其他專案中使用,那麼它應該位於 /pkg 目錄中。如果程式碼不是可重用的,或者你不希望其他人重用它,請將該程式碼放到 /internal 目錄中。你會驚訝於別人會怎麼做,所以要明確你的意圖!
通常有一個小的 main 函式,從 /internal 和 /pkg 目錄匯入和呼叫程式碼,除此之外沒有別的東西。
有關示例,請參閱 /cmd 目錄。
/internal
私有應用程式和庫程式碼。這是你不希望其他人在其應用程式或庫中匯入程式碼。請注意,這個佈局模式是由 Go 編譯器本身執行的。有關更多細節,請參閱Go 1.4 release notes 。注意,你並不侷限於頂級 internal 目錄。在專案樹的任何級別上都可以有多個內部目錄。
你可以選擇向 internal 包中新增一些額外的結構,以分隔共享和非共享的內部程式碼。這不是必需的(特別是對於較小的專案),但是最好有有視覺化的線索來顯示預期的包的用途。你的實際應用程式程式碼可以放在 /internal/app 目錄下(例如 /internal/app/myapp),這些應用程式共享的程式碼可以放在 /internal/pkg 目錄下(例如 /internal/pkg/myprivlib)。
/pkg
外部應用程式可以使用的庫程式碼(例如 /pkg/mypubliclib)。其他專案會匯入這些庫,希望它們能正常工作,所以在這裡放東西之前要三思:-)注意,internal 目錄是確保私有包不可匯入的更好方法,因為它是由 Go 強制執行的。/pkg 目錄仍然是一種很好的方式,可以顯式地表示該目錄中的程式碼對於其他人來說是安全使用的好方法。由 Travis Jeffery 撰寫的 I'll take pkg over internal 部落格文章提供了 pkg 和 internal 目錄的一個很好的概述,以及什麼時候使用它們是有意義的。
當根目錄包含大量非 Go 元件和目錄時,這也是一種將 Go 程式碼分組到一個位置的方法,這使得執行各種 Go 工具變得更加容易(正如在這些演講中提到的那樣: 來自 GopherCon EU 2018 的 Best Practices for Industrial Programming , GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps 和 GoLab 2018 - Massimiliano Pippi - Project layout patterns in Go )。
如果你想檢視哪個流行的 Go 儲存庫使用此專案佈局模式,請檢視 /pkg 目錄。這是一種常見的佈局模式,但並不是所有人都接受它,一些 Go 社群的人也不推薦它。
如果你的應用程式專案真的很小,並且額外的巢狀並不能增加多少價值(除非你真的想要:-),那就不要使用它。當它變得足夠大時,你的根目錄會變得非常繁瑣時(尤其是當你有很多非 Go 應用元件時),請考慮一下。
/vendor
應用程式依賴項(手動管理或使用你喜歡的依賴項管理工具,如新的內建 Go Modules 功能)。go mod vendor 命令將為你建立 /vendor 目錄。請注意,如果未使用預設情況下處於啟用狀態的 Go 1.14,則可能需要在 go build 命令中新增 -mod=vendor 標誌。
如果你正在構建一個庫,那麼不要提交你的應用程式依賴項。
注意,自從 1.13 以後,Go 還啟用了模組代理功能(預設使用 https://proxy.golang.org 作為他們的模組代理伺服器)。在here 閱讀更多關於它的資訊,看看它是否符合你的所有需求和約束。如果需要,那麼你根本不需要 vendor 目錄。
國內模組代理功能預設是被牆的,七牛雲有維護專門的的模組代理 。
服務應用程式目錄/api
OpenAPI/Swagger 規範,JSON 模式檔案,協議定義檔案。
有關示例,請參見 /api 目錄。
Web 應用程式目錄/web
特定於 Web 應用程式的元件:靜態 Web 資產、伺服器端模板和 SPAs。
通用應用目錄/configs
配置檔案模板或預設配置。
將你的 confd 或 consul-template 模板檔案放在這裡。
/init
System init(systemd,upstart,sysv)和 process manager/supervisor(runit,supervisor)配置。
/scripts
執行各種構建、安裝、分析等操作的指令碼。
這些指令碼保持了根級別的 Makefile 變得小而簡單(例如, https://github.com/hashicorp/terraform/blob/master/Makefile )。
有關示例,請參見 /scripts 目錄。
/build
打包和持續整合。
將你的雲( AMI )、容器( Docker )、作業系統( deb、rpm、pkg )包配置和指令碼放在 /build/package 目錄下。
將你的 CI (travis、circle、drone)配置和指令碼放在 /build/ci 目錄中。請注意,有些 CI 工具(例如 Travis CI)對配置檔案的位置非常挑剔。嘗試將配置檔案放在 /build/ci 目錄中,將它們連結到 CI 工具期望它們的位置(如果可能的話)。
/deployments
IaaS、PaaS、系統和容器編排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些儲存庫中(特別是使用 kubernetes 部署的應用程式),這個目錄被稱為 /deploy。
/test
額外的外部測試應用程式和測試資料。你可以隨時根據需求構造 /test 目錄。對於較大的專案,有一個數據子目錄是有意義的。例如,你可以使用 /test/data 或 /test/testdata (如果你需要忽略目錄中的內容)。請注意,Go 還會忽略以“.”或“_”開頭的目錄或檔案,因此在如何命名測試資料目錄方面有更大的靈活性。
有關示例,請參見 /test 目錄。
其他目錄/docs
設計和使用者文件(除了 godoc 生成的文件之外)。
有關示例,請參閱 /docs 目錄。
/tools
這個專案的支援工具。注意,這些工具可以從 /pkg 和 /internal 目錄匯入程式碼。
有關示例,請參見 /tools 目錄。
/examples
你的應用程式和/或公共庫的示例。
有關示例,請參見 /examples 目錄。
/third_party
外部輔助工具,分叉程式碼和其他第三方工具(例如 Swagger UI)。
/githooks
Git hooks。
/assets
與儲存庫一起使用的其他資產(影象、徽標等)。
/website
如果你不使用 Github 頁面,則在這裡放置專案的網站資料。
有關示例,請參見 /website 目錄。
你不應該擁有的目錄/src
有些 Go 專案確實有一個 src 資料夾,但這通常發生在開發人員有 Java 背景,在那裡它是一種常見的模式。如果可以的話,儘量不要採用這種 Java 模式。你真的不希望你的 Go 程式碼或 Go 專案看起來像 Java:-)
不要將專案級別 src 目錄與 Go 用於其工作空間的 src 目錄(如 How to Write Go Code 中所述)混淆。$GOPATH 環境變數指向你的(當前)工作空間(預設情況下,它指向非 windows 系統上的 $HOME/go)。這個工作空間包括頂層 /pkg, /bin 和 /src 目錄。你的實際專案最終是 /src 下的一個子目錄,因此,如果你的專案中有 /src 目錄,那麼專案路徑將是這樣的: /some/path/to/workspace/src/your_project/src/your_code.go。注意,在 Go 1.11 中,可以將專案放在 GOPATH 之外,但這並不意味著使用這種佈局模式是一個好主意。