Go 部落格

整理 Go 程式碼

Andrew Gerrand
2012 年 8 月 16 日

簡介

Go 程式碼是以不同方式整理的。這篇文章會說明如何命名並封裝 Go 程式元素,以最符合使用者的需求。

選用好的名稱

您選擇的名稱會影響您如何思考自己的程式碼,因此在為套件以及其導出的識別碼命名時,務必小心謹慎。

套件名稱會提供其內容的背景資訊。例如,在標準函式庫中的 bytes 套件 會匯出 Buffer 型別。就 Buffer 這個名稱本身來說,並無太大的說明性質,但如果和其套件名稱結合來看,意思就會很清楚:bytes.Buffer。如果套件使用一個比較沒有說明性的名稱,例如 util,那緩衝區很可能就會有更長且笨重的名稱 util.BytesBuffer

進行撰寫時,不要害怕重新命名。在撰寫程式時,您會更了解其各部分如何相互整合,進而釐清各部分的名稱為何。您毋須將自己侷限於早期的決定。(gofmt 指令 有提供 -r 旗標,可提供具備語法辨識能力的搜尋與替換功能,讓大規模的重構變得更簡單。)

一個好名稱是軟體介面中最重要的部分:名稱是每個程式碼用戶端都會看到的第一個東西。因此,精心挑選的名稱是良好說明文件的起點。以下許多準則是由於好的命名而自然產生的。

選擇一個好的導入路徑(讓您的套件可以「go get」到)

導入路徑是使用者用來導入套件的字串。它指定套件原始程式碼所在的目錄(相對於 $GOROOT/src/pkg$GOPATH/src)。

導入路徑應該是全域唯一的,所以使用來源儲存庫的路徑為其基礎。例如,來自 go.net 子儲存庫的 websocket 套件會有一個 "golang.org/x/net/websocket" 導入路徑。Go 專案擁有 "github.com/golang" 路徑,所以其他作者不能將該路徑用於不同的套件。由於儲存庫 URL 和導入路徑是一致的,go get 指令可以自動擷取和安裝套件。

如果您不使用託管的來源儲存庫,請選擇一些唯一的字首,例如網域、公司或專案名稱。舉例來說,所有 Google 內部 Go 程式碼的導入路徑都以字串 "google" 開頭。

導入路徑的最後一個元素通常與套件名稱相同。例如,導入路徑 "net/http" 包含套件 http。這不是一個必要條件 - 如果你喜歡,你可以讓它們不同 - 但為了可預測性,你應該遵循慣例:使用者可能會驚訝於導入 "foo/bar" 會將識別碼 quux 帶入套件名稱空間。

有時人們會將 GOPATH 設定為他們來源儲存庫的根目錄,並將他們的套件放在相對於儲存庫根目錄的目錄中,例如 "src/my/package"。一方面,這讓導入路徑變得很短("my/package" 代替 "github.com/me/project/my/package"),但另一方面,它會中止 go get 並迫使用戶重新設定他們的 GOPATH 來使用套件。不要這樣做。

最小化已輸出的介面

你的程式碼可能由許多有用的程式碼小片組成,所以很誘人想在你的套件的已輸出介面中顯示大部分的功能。克制住這種衝動!

提供的介面越大,您必須支援的內容就越多。使用者會迅速依賴您匯出的每一類型、函式、變數和常數,從而建立一個隱含合約,您必須永遠遵守,否則就會有損害使用者程式風險。在準備 Go 1 時,我們仔細檢閱了標準函式庫的匯出介面,並移除我們尚未準備好承諾的部分。您在散佈您自己的函式庫時,應該採取類似的謹慎態度。

如果有疑問,就不要投入!

應放入套件的內容

很容易將所有內容丟入「萬用手提袋」套件,但這樣會淡化套件名稱的意義(因為它必須囊括大量功能),並迫使套件小部分的使用者編譯和連結許多無關的程式碼。

另一方面,過度將您的程式碼分割成小套件也很容易,在這種情況下,您可能會陷入介面設計的困境,而無法完成工作。

請參閱 Go 標準函式庫作為指南。有些套件很大,有些則很小。例如,http 套件包含 17 個 go 原始檔(不含測試)並匯出 109 個識別碼,而 hash 套件包含一個只匯出三個宣告的檔案。沒有嚴格且快速的規則;兩種方法在特定的脈絡下都是適當的。

話雖如此,package main 通常比其他套件大。複雜的指令包含許多在可執行檔的脈絡外幾乎沒有用處的程式碼,而且經常將所有內容保存在一個地方會比較簡單。例如,go 工具超過 12000 行,散佈於 34 個檔案 中。

文件化您的程式碼

良好的文件化是可用且可維護的程式碼必備的品質。請閱讀 Godoc:文件化 Go 程式碼 文章,以了解如何撰寫良好的文件化註解。

下一篇文章:App Engine 1.7.1 中的 Go 更新
上一篇文章:GCC 4.7.1 中的 Gccgo
網誌索引