成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我們應(yīng)該怎么樣編寫 Go 語(yǔ)言庫(kù),有哪些標(biāo)準(zhǔn)可以參考?

開發(fā) 后端
不久前我和朋友們想出一個(gè)主意,準(zhǔn)備合并我們的 IRC bots,并用 Go 重寫它們。為了防止重寫大部分現(xiàn)有功能,我們?cè)噲D找到支持 bots 程序中使用的 Web API 的現(xiàn)有庫(kù)。我們的項(xiàng)目需要一個(gè) Reddit API 的庫(kù)。

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

[[314580]]

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

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

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

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

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

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

不要引入全局變量

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

 

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

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

返回 structs,而不是 interfaces

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

 

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

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

 

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

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

使用配置結(jié)構(gòu)體來(lái)避免修改你的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ì)配置來(lái)說(shuō),我認(rèn)為允許用戶在返回的結(jié)構(gòu)體里設(shè)置不同的參數(shù)是一個(gè)更好的方法,并且只在編寫復(fù)雜方法時(shí)才使用這種特定方法。

總結(jié)

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

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

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

 

責(zé)任編輯:華軒 來(lái)源: 今日頭條
相關(guān)推薦

2020-02-05 16:55:11

Go語(yǔ)言程序員文章

2021-03-01 21:59:25

編程語(yǔ)言GoCX

2021-03-01 18:35:18

Go語(yǔ)言虛擬機(jī)

2023-04-02 23:13:07

Go語(yǔ)言bufio

2022-10-17 09:08:01

2024-08-22 08:50:51

2025-02-11 09:01:57

2011-02-25 10:12:09

GoWeb

2014-02-18 11:24:07

云計(jì)算PaaS

2023-02-13 00:24:37

Go語(yǔ)言日志庫(kù)

2023-06-07 17:46:32

AI高考

2016-09-27 21:25:08

Go語(yǔ)言Ken Thompso

2024-05-07 08:46:06

GoGoogle云原生

2021-02-03 20:20:34

ReacHook數(shù)據(jù)

2014-01-14 09:10:53

GoHTTP內(nèi)存泄漏

2022-10-21 09:23:31

腦累計(jì)算深度學(xué)習(xí)

2010-03-26 13:15:28

Python嵌入c

2019-07-19 15:42:57

Hadoop大數(shù)據(jù)YuniKorn

2023-06-30 08:23:36

Spring!SolonJavalin

2015-07-23 11:49:31

程序猿
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产最新视频在线 | 亚州精品天堂中文字幕 | 特黄级国产片 | 在线观看国产视频 | 99久久精品国产一区二区三区 | 99热首页| 91最新在线视频 | 中文字幕av在线播放 | 色悠悠久| 国产精品一区二区视频 | 久久久国产一区二区三区 | 黄色av网站在线免费观看 | 瑟瑟免费视频 | www.国产日本 | 成人午夜性成交 | 欧美极品在线 | 夜夜爽99久久国产综合精品女不卡 | a免费视频 | 国产成人精品免高潮在线观看 | 不卡一二区| 亚洲成人久久久 | 老牛影视av一区二区在线观看 | 欧美一区二区视频 | 日日骚网 | 日韩欧美一区二区三区免费观看 | 精品久久久久久久久久久久 | 亚洲第一av | 日韩亚洲欧美综合 | 一区二区三区四区在线视频 | 欧美日韩一区在线 | 国产精品69毛片高清亚洲 | 国产精品久久国产精品 | 日韩欧美视频 | 欧美h版| 天堂在线中文字幕 | 亚洲一区三区在线观看 | 国产精品99久久久久久宅男 | 激情av在线 | 久久久久久艹 | 天天操操操操操 | 99日韩|