日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
我們應(yīng)該怎么樣編寫 Go 語言庫,有哪些標(biāo)準(zhǔn)可以參考?

 不久前我和朋友們想出一個(gè)主意,準(zhǔn)備合并我們的 IRC bots,并用 Go 重寫它們。為了防止重寫大部分現(xiàn)有功能,我們?cè)噲D找到支持 bots 程序中使用的 Web API 的現(xiàn)有庫。我們的項(xiàng)目需要一個(gè) Reddit API 的庫。這篇文章啟發(fā)于我找到的前三個(gè)庫,我不打算說出它們的名字,以免羞辱它們的作者。

上面說的每一個(gè)庫都存在一些基本問題以至于它們?cè)谡鎸?shí)場(chǎng)景中不可用。并且每個(gè)庫都以這樣一種方式編寫:不以非向后兼容的方式修改現(xiàn)有庫的 API,這樣是不可能修復(fù)問題的。不幸的是,由于很多其他的庫也存在同樣的問題,所以我會(huì)在下面列出一些作者錯(cuò)誤的地方。

不要對(duì) HTTP 客戶端硬編碼

很對(duì)庫都包含了對(duì) http.DefaultClient 的硬編碼。雖然對(duì)庫本身來說這并不是問題,但是庫的作者并未理解應(yīng)該怎樣使用 http.DefaultClient 。正如 default client 建議它只在用戶沒有提供其他 http.Client 時(shí)才被使用。相反的是,許多庫作者樂意在他們代碼中涉及 http.DefaultClient 的部分采用硬編碼,而不是將它作為一個(gè)備選。這會(huì)導(dǎo)致在某些情況下這個(gè)庫不可用。

首先,我們很多人都讀過這篇講述 http.DefaultClient 不能自定義超時(shí)時(shí)間的文章《Don’t use Go’s default HTTP client (in production)[1]》,當(dāng)你沒法保證你的HTTP 請(qǐng)求一定會(huì)完成(或者至少要等一個(gè)完全無法預(yù)估時(shí)間的響應(yīng))時(shí),你的程序可能會(huì)遇到奇怪的 goroutine 泄漏和一些無法預(yù)知的行為。在我看來,這會(huì)是每一個(gè)對(duì) http.DefaultClient 采用硬編碼的庫不可用。

其次,網(wǎng)絡(luò)需要一些額外的配置。有時(shí)候需要用到代理,有時(shí)候需要對(duì) URL 進(jìn)行一丟丟的改寫,甚至可能 http.Transport 需要被一個(gè)定制的接口替換。當(dāng)一個(gè)程序員在你的庫里用他們自己的 http.Client 實(shí)例時(shí),以上這些都很容易被實(shí)現(xiàn)。

在你的庫中處理 http.Client 的推薦方式是使用提供的客戶端,但是如果需要的話,有一個(gè)默認(rèn)的備選:

 
 
 
  1. func CreateLibrary(client *http.Client) *Library {    if client == nil {        client = http.DefaultClient    }    ...} 

或者如果你想從工廠函數(shù)中移除參數(shù),請(qǐng)?jiān)谀愕?struct 中定義一個(gè)輔助方法,并且讓用戶在需要時(shí)設(shè)置其屬性:

 
 
 
  1. type Library struct {    Client *http.Client}func (l *Library) getClient() *http.Client {    if l.Client == nil {        return http.DefaultClient    }    return l.Client} 

另外,如果一些全局的特性對(duì)于每個(gè)請(qǐng)求來講都是必須的,人們經(jīng)常感覺到需要用他們自己的實(shí)例來替換 http.Client。這是一個(gè)錯(cuò)誤的方法 — 如果你需要在你的請(qǐng)求中設(shè)置一些額外的 headers,或者在你的客戶端引入某類公共的特性,你只需要簡(jiǎn)單為每個(gè)請(qǐng)求進(jìn)行設(shè)置或者用組裝定制客戶端的方式來代替完全替換它。

不要引入全局變量

另一個(gè)反面模式是允許用戶在一個(gè)庫中設(shè)置全局變量。舉個(gè)例子,在你的庫中允許用戶設(shè)置一個(gè)全局的 http.Client 并被所有的 HTTP 調(diào)用執(zhí)行:

 
 
 
  1. var libraryClient *http.Client = http.DefaultClientfunc SetHttpClient(client *http.Client) {    libraryClient = client} 

通常在一個(gè)庫中不應(yīng)該存在一堆全局變量。當(dāng)你寫代碼的時(shí)候,你應(yīng)該想想用戶在他們的程序中多次使用你的這個(gè)庫會(huì)發(fā)生什么。全局變量會(huì)使不同的參數(shù)沒有辦法被使用。而且,在你的代碼中引入全局變量會(huì)引起測(cè)試上的問題并造成代碼上不必要的復(fù)雜度。使用全局變量可能會(huì)導(dǎo)致在你程序的不同模塊有不必要的依賴。在寫你的庫的時(shí)候,避免全局狀態(tài)是格外重要的。

返回 structs,而不是 interfaces

這是一個(gè)普遍的問題(實(shí)際上我在這一點(diǎn)上也犯過錯(cuò))。很多庫都有下面這類函數(shù):

 
 
 
  1. func New() LibraryInterface {    ...} 

在上面的 case 中,返回一個(gè) interface 使 struct 的特性在庫里被隱藏了。實(shí)際上應(yīng)該這么寫:

 
 
 
  1. func New() *LibraryStruct { ...} 

在庫里不應(yīng)該存在接口的聲明,除非它被用在某個(gè)函數(shù)參數(shù)中。如果出現(xiàn)上面的 case,你就應(yīng)該想想你在寫這個(gè)庫的時(shí)候的約定。當(dāng)返回一個(gè) interface 時(shí),你基本上得聲明一系列可用的方法。如果有人想用這個(gè)接口來實(shí)現(xiàn)他們自己的功能(比如說為了測(cè)試),他得打亂他們的代碼來添加更多的方法。這意味著盡管在 struct 里添加方法是安全的,但在 interface 里不是。這個(gè)想法在這篇文章中被總結(jié)得很好《Accept Interfaces Return Struct in Go[2]》。這個(gè)方案也能解決配置的問題。你想修改庫中的一些特性,你可以簡(jiǎn)單的修改 struct 中一些公開的字段。但是如果你的庫只提供給用戶一個(gè) interface,這就玩不轉(zhuǎn)了。

使用配置結(jié)構(gòu)體來避免修改你的APIs

另一種配置方法是在你的工廠函數(shù)中接收一個(gè)配置結(jié)構(gòu)體,而不是直接傳配置參數(shù)。你可以很隨意的添加新的參數(shù)而不用破壞現(xiàn)有的 API。你只需要做一件事情,在Config結(jié)構(gòu)體中添加一個(gè)新的字段,并且確保不會(huì)影響它原本的特性。

 
 
 
  1. func New(config Config) *LibraryStruct {    ...} 

下面是一種添加結(jié)構(gòu)體字段的正確的場(chǎng)景,如果一個(gè)用戶初始化結(jié)構(gòu)體的時(shí)候忘了添加字段名,這是一種我認(rèn)為修改他們的代碼能得到原諒的場(chǎng)景。為了維護(hù)兼容性,你應(yīng)該在你的代碼中用 person{name: "Alice", age: 30} 而不是 person{"Alice", 30}。

你能在 golang.org/x/crypto[4] 包里看到對(duì)上面的補(bǔ)充??傊?,對(duì)配置來說,我認(rèn)為允許用戶在返回的結(jié)構(gòu)體里設(shè)置不同的參數(shù)是一個(gè)更好的方法,并且只在編寫復(fù)雜方法時(shí)才使用這種特定方法。

總結(jié)

根據(jù)經(jīng)驗(yàn)來講,在寫一個(gè)庫的時(shí)候,你應(yīng)該總是允許用戶指定他們自己的 http.Client來執(zhí)行 HTTP 調(diào)用。而且考慮到未來迭代修改帶來的影響,你可以嘗試用可擴(kuò)展的方式編寫代碼。避免全局變量,庫不能存儲(chǔ)全局狀態(tài)。如果你有任何疑問-參考標(biāo)準(zhǔn)庫是怎么寫的。

我認(rèn)為有一個(gè)很好的想法,在你的程序中用你的庫來測(cè)試并問自己一些問題:

  • 如果你嘗試多次引入庫會(huì)發(fā)生什么?
  • 你的庫有沒有單元測(cè)試?
  • 在不破壞原有代碼的前提下,有沒有一種非侵入式的方式來擴(kuò)展你的庫?
  • 在不破壞原有代碼的前提下,是否可以添加額外配置參數(shù)?

分享文章:我們應(yīng)該怎么樣編寫 Go 語言庫,有哪些標(biāo)準(zhǔn)可以參考?
瀏覽路徑:http://www.5511xx.com/article/djdeocp.html