Go 語言中常見 100 問題 - 項目結構混亂
項目結構混亂
創建一個好的 Go 項目結構並不是一件容易的事情,由於 Go 語言在設計包和模塊方面提供了很大的自由度,因此在這方面沒有通用的最佳實踐。本文將首先討論創建項目的常用組織結構,然後討論一些最佳實踐,給出改進項目組織方式的方法。
項目結構
Go 語言維護者對構建 Go 項目結構沒有嚴格的約定,在 github 上有一個稱爲標準 Go 項目結構的模板(https://github.com/golang-standards/project-layout)),注意該模板不是 Go 官方提供的。如果我們的項目很小(只有幾個文件),或者公司和項目組已經指定了項目結構規範,重新調整或遷移到上述模板格式可能不值得。如果項目還沒有結構規範,那前面這個結構值得參考借鑑。現在我們來看看這個結構模板的佈局,都有些什麼內容:
-
/cmd 項目主要的應用程序. foo 應用程序的 main.go 應該位於 / cmd/foo/main.go 中。
-
/internal 私有的應用程序代碼庫,這裏面的代碼是不希望被其它人導入的。
-
/pkg 外面的應用程序可以使用的代碼庫,是向其它人公開的公共代碼。
-
/test 存儲測試數據和代碼。Go 語言中的單元測試文件與源文件通常都在一個包中。但像公共 API 測試或集成測試代碼應該存放在 / test 中。
-
/configs 存放配置文件
-
/docs 存放設計和用戶文檔
-
/examples 應用程序或公共庫函數的實例程序
-
/api api 接口定義文件(Swagger, Protocol Buffers 等)
-
/web web 應用程序的資源文件(靜態圖片等)
-
/build 打包和持續集成(CI) 文件
-
/scripts 用於分析、安裝等腳本文件
-
/vendor 應用程序的依賴文件(例如 Go 模塊的依賴庫)
可以看到上面的標準結構中沒有 / src 目錄,這是因爲 / src 目錄太泛了,因此採用了 / cmd、/internal 和 / pkg 這種目錄。
「NOTE: 在 2021 年,Go 語言的核心維護者 Russ Cox 對上面的項目結構表達反對意見。儘管它號稱是 Go 項目標準結構,但不是官方的標準,有誤導人嫌疑。對於項目結構,沒有強制性約定必須採用上述模板。我們必須意識到這一個點,唯一注意的是項目中的各個模塊結構要保持一致,達成統一。避免在不同的結構之間發生遷移,這會浪費時間。」
包組織結構
在 Go 語言中,沒有子包的概念。但是,我們可以在子目錄中創建包。下面是標準庫 net 中的目錄結構。net 既充當包,又充當包含其他包的目錄。但是 net/http 包不繼承 net 或對 net 包具有特定的訪問權限。外界能看到 net/http 中可導出的元素。子目錄的主要好處是將包中代碼保存在具有高內聚性的地方。
/net
/http
client.go
...
/smtp
auth.go
...
addrselect.go
...
對於 Go 包的組織形式,有不同的觀點。例如,我們應該按業務類型還是按層來組織應用程序,這取決於自己的喜好。我們可能傾向於按業務類型(例如客戶業務,合同業務等)對代碼進行分組,或者我們傾向於遵循六邊形原則對其進行分組。只要選擇出了適合我們的方法,保持統一即可。
對於軟件包,我們應該遵循一些最佳實踐。首先,應該避免過渡設計,因爲這可能會使得項目過於複雜。當我們搞清楚了項目包含的內容後,最好使用一個簡單的形式組織並讓項目不斷的發展,而不是強迫自己預先制定完美的結構。
包的粒度是另一個需要考慮的重要因素,我們應該避免有幾十個包含一兩個文件的小包。如果這樣設計,可能錯過了這些包之間的一些邏輯聯繫,使得項目更難讓人理解。此外,我們也應該避免使用包含很多文件的大包。總之,對於包的粒度,我們不應該走極端,導致包極小或極大。
包的命名也應該謹慎考慮。衆所周知,命名是程序開發中一件困難的事情。爲了幫助用戶理解 Go 項目,我們應該根據它提供的內容命名包,而不是它包含的內容。此外,包名要有意義。因此,包的名稱應該簡短、簡潔和富有表現力,按照慣例,應該是一個小寫單詞。
對於包導出什麼,規則非常簡單。我們應該儘可能減少應該導出的內容,以減少包之間的耦合並隱藏不必要導出的元素。如果不確定是否要導出一個元素,應該默認它不導出,在後面發現需要導出時,再調整代碼支持將其導出。我們還要注意一些特殊情況,例如,當我們對一個結構體對象調用 encoding/json 標準庫對其進行序列化或反序列化時,該結構體對象的字段需要是可導出的(即首字母要大寫),否則會忽略該字段。
組織好一個項目結構並不是一件簡單的事情,遵循上述這些規則有助於我們更容易維護。記住一點,保持結構一致對於簡化可維護非常有幫助。因此,應確保代碼庫中的代碼儘可能保持一致。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/epK_0yn_EPIWJjz9xmddcA