這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
- 視頻資訊
- 命名
- Object Creation
- 日誌
interface
vs struct
- 什麼時候 panic
- 檢查 error
- 允許啟用庫的調試能力
- 為測試而設計
- 並發
- channels
- 什麼時候發起
goroutine
- 什麼時候使用 context.Context
- 其它注意事項
視頻資訊 #
Practical Advice for Go Library Authors
by Jack Lindamood
at GopherCon 2016
https://www.youtube.com/watch?v=5v2fqm_8jYI
幻燈地址:http://go-talks.appspot.com/github.com/cep21/go-talks/practical-advice-for-go-library-authors.slide#1
命名 #
包名是將來使用過程中的一部分,所以避免重複包名和結構與函數。比如
1 |
var h client.Client → var h http.Client |
1 |
context.NewContext() => context.Background() |
Object Creation #
golang 沒有建構函式,因此建立對象一般有兩種辦法
- 預設的
0
值
- 單獨的建構函式,
NewSomething()
推薦使用預設 0
值的構造方法
在預設0
值的情況下,各個方法要處理好0
值,比如有些東西發現是0
值後,給入一個預設值。
New()
建構函式很靈活,可以做任何事情,因此對於代碼閱讀上不利,意味著隱藏了很多東西。
有些庫使用私人 struct,公開介面的方法,authImpl struct
and Auth interface
,這是反模式,不推薦使用。
不推薦使用 Singleton,雖然標準庫中大量使用了 Singleton 模式,但是 Jack 個人不喜歡這種模式。
使用高階函數作為選項這種形式不推薦:NewSomething(WithThingA(), WithThingB())
日誌 #
一些日誌是直接列印到標準輸出去,這是非常不好的設計,因為使用者如果想關根本關不了。
建議
- 確定一下作為庫是不是真的需要列印日誌,是不是應該把輸出日誌的工作交給調用方決定?
- 如果一定需要日誌,那麼使用回呼函數方式
- 輸出日誌到一個
interface
- 不要假定傳進來的就是標準庫的
log
,有很多選擇。
- 尊重
stdout
和 stderr
- 不要使用
singleton
interface
vs struct
#
接受 interface
,但返回的是 struct
這點和 Java 不同,Java 更傾向於所有東西都是通過 interface
操作。而 golang 不需要,golang 使用的是隱性interface
。
什麼時候 panic #
最好都不 panic
。如果非要 panic
,可能最合適的地方是 init
的時候,因為剛一運行就能看到掛了,比較容易處理。但即使如此,也盡量不要 panic
。
檢查 error #
問:我們是需要檢查所有的 error
嗎?比如有些似乎不大容易出錯。
答:需要,特別是你說的這些不大容易出錯的!!
我們用 error
代替了 exception
,所以不要忽略這個東西。
處理的辦法
- 最好的辦法是 Bubble up,也就是傳回調用方
- 但有的時候(比如 go routine) 不適合,那就:
什麼時候應該返回錯誤比較合適?
允許啟用庫的調試能力 #
為測試而設計 #
並發 #
channels #
雖然 channel 是 golang 一個處理並發很好地東西,但是並非所有場合都需要。比如標準庫中就很少有在 API 中使用 channel
的。
- 將使用
channel
的位置向上層移動。
- 可以使用回呼函數。
- 不要混合使用
mutex
和 channel
什麼時候發起 goroutine
#
- 有一些庫的
New()
會發起他們的 goroutine
,這是不好的。
- 標準庫使用的是
Serve()
函數。以及對應的 Close()
函數
- 將
goroutine
向上層推
什麼時候使用 context.Context #
- 所有的阻塞、長時間的操作,都應該可以被
cancel
- 由於
context.Context
很容易儲存東西,所以很容易被濫用。要儘力去避免使用 Context
Singleton
和 context.Value()
是同樣性質的東西,像全域變數一樣,對於程式狀態來說是個黑箱。
其它注意事項 #
- 如果什麼東西很難做,嗯,那就讓別人去做吧
- 為了效率而升級
- 但是,正確性要比效率重要,在正確性的前提下,注意效率
- 不要在庫中使用
/vendor
(在 main
包中可以)
- 注意 build tag
- 保持乾淨