Go 項目文件命名規範是什麼?

計算機科學中只有兩件難事:緩存失效和命名。—— 菲爾 · 卡爾頓(Phil Karlton)。

在編程世界中,選擇正確的命名約定是打開可讀和可維護代碼大門的重要途徑。在使用 Go 語言開發大型項目時,文件命名是構建清晰項目結構的關鍵一環,一個合理的文件命名規範不僅能提高開發效率,還能降低團隊協作中的溝通成本。

在這篇博文中,我們將深入探討 Go 中命名的最佳實踐。

在探討 Go 文件命名規範之前,我們有必要先來了解下 Go 項目中的目錄和包的命名規範是什麼。

目錄名

關於 Go 目錄命名規範,在網上搜索相關資料,基本能找到如下兩條共識:

項目本身也是一個目錄,所以項目名也遵循這兩條規範。

其實我們可以借鑑流行的 Go 項目,參考這些優秀的項目是如何對目錄進行命名的。比如 Kubernetes 項目就非常具有參考價值。

如下是 Kubernetes 項目 /cmd 目錄部分截圖:

K8s /cmd

可以發現,Kubernetes 項目目錄名都採用全小寫單詞,並且必要時可以使用中劃線分隔。

不過,值得注意的是,有些目錄名並沒有使用中劃線進行分隔,而是直接將多個單詞連在了一起。所以何時使用中劃線是一個選擇問題,而不是固定的強制規範。

我們再看下 Kubernetes 項目 /pkg 目錄部分截圖:

K8s /pkg

可以發現,/pkg 目錄下所有目錄名都沒有使用中劃線分隔。有意思的是,甚至 kubeapiserver 也連在了一起,回看上面 /cmd 目錄中的寫法是 kube-apiserver。看來 Kubernetes 項目不同目錄有着各自的命名規範。

針對這點,我的理解是:/cmd/kube-apiserver,作爲項目中組件的入口文件目錄,使用中劃線分隔可以起到見名知意的效果;而 /pkg/kubeapiserver 作爲包路徑不使用中劃線分隔,是爲了方便包的導入。

如下列舉幾個目錄名正反示例。

正確示例:

cmd
internal
pkg
task
kube-scheduler
kube-controller-manager

反向示例:

CMD
kubeScheduler
KubeScheduler
kube_scheduler

不過凡事總有特例,我之前寫過一篇文章《如何設計一個優秀的 Go Web 項目目錄結構》,裏面介紹了一個 Go 項目的標準佈局。其中包含一個外部輔助工具目錄 third_party,用來存放 fork 的代碼和其他第三方工具。這裏 third_party 就採用了下劃線命名,這種算是約定俗成的命名,就無需刻意遵循目錄命名規範了。

另外,關於項目本身的的命名,其實還有一些額外的規範:

如下列舉幾個項目名正反示例。

正確示例:

user
userapi
redis-go
kubernetes

反向示例:

user_api
Product
AIInfra
AiInfra

以下是我個人的一些建議:

包名

接下來,我們再一起探究下 Go 項目中包名的命名規範是什麼。

幸運的是,對於包名,Go 官方博客給出了參考建議,也是最爲權威的規範。

在 Package names 這篇 Go 官方博文中,給出了幾條好的包命名原則:

Go Team 成員 David Crawshaw 在 2014 Google I/O talk 中也對包命名規範給出了建議:

同目錄名規範一樣,包名也存在例外的情況:

如下列舉幾個包名正反示例。

正確示例:

controller
stringset
tabwriter

反例:

MyUtil
util
time // 與標準庫重名
tabWriter
TabWriter
tab_writer

文件名

前文分別介紹了 Go 項目中目錄名和包名的命名規範,現在終於可以探討 Go 文件的命名規範了,這也是本文的重頭戲。

不過,對於 Go 文件的命名規範,即沒有 Go 團隊的官方博客作爲參考,也沒有著名的 Gopher 站出來分享  Go 文件到底改如何命名。

這是一個少有人特意提及的規範項,不過我在 Go 項目的 GitHub 倉庫中找到了一條討論這個問題的 issue doc: filename conventions。

雖然不少人蔘與了討論,但遺憾的是,這個問題現在仍然沒有定論。不過,這也正是此問題值得探討的原因,也是本文的意義所在。

其實遇到規範相關問題,我們最先想到的,應該就是參考 Go 源碼本身。很不巧,針對 Go 文件的命名規範問題,Go 源碼做的也不夠好。

正如 doc: filename conventions 問題 issue 提問者列舉的幾個 Go 文件名示例中,存在很大差異:

這就比較有意思了 😁。

issue 中點贊最多的是 peterbourgon 的評論:

There is a de facto standard for Go source file names: all lowercase with underscore separation when necessary, i.e. snake case. (The exceptions are exceptions.) I'd appreciate having it as a documented standard, too, to answer questions like @carnott-snap notes, especially among junior Gophers. In my opinion it needn't be so formal as entering Effective Go, a short new section on CodeReviewComments is more than sufficient.

這個回答的核心是:all lowercase with underscore separation when necessary, i.e. snake case. (The exceptions are exceptions.)

即大家達成了三點共識:

前面兩條好理解,例外情況都有哪些?我總結大概有如下幾種:

雖然很多人達成了上面三點共識,但其實文件命名和目錄命名規範一樣,存在 “灰色地帶” —— 必要時用下劃線分隔。

到底何時是必要的時候

這也是最不統一的一點規範,我發現很多人推薦,在名稱出現多個單詞時採用下劃線分隔。例如 task_status.goweb_shell.go

但還有一小部分人,更推崇不採用下劃線的命名方式,例如 taskstatus.gowebshell.go

而我個人的偏好則更傾向於後者。如果單詞數量爲 2 個,我會傾向於不使用下劃線分隔,例如 taskstatus.go;如果單詞數量爲 3~4 個,則傾向於使用下劃線分隔,例如 import_known_versions.godefault_storage_factory_builder.go

但最好的方案,仍然是儘量用簡短有意義的單個單詞或縮寫作爲文件名。

NOTE: 我傾向於不使用下劃線分隔的幾點理由:

  • 與包名對齊

  • kubernetes 也經常這麼幹。

  • 你看,testdata 就沒有使用下劃線分隔 😄。

  • ... 想到了再說 :)。

如下列舉幾個文件名正反示例。

正確示例:

router.go
middleware.go
webshell.go

反面示例:

routers.go // 複數
fooBar.go
Service.go

總結

計算機科學中只有兩件難事:緩存失效和命名。本文探討的是後者。

Go 語言雖然是後起之秀,但在項目佈局、命名規範等的確沒有一個統一的標準。不過社區還是給出了一些共識性建議:

希望本文能對你有所啓發。

延伸閱讀

聯繫我

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/reVRrXYexMB6c8RChFW2Lg