主頁 >  其他 > Go語言“十誡”[譯]

Go語言“十誡”[譯]

2021-04-13 10:26:52 其他

本文翻譯自John Arundel的《Ten commandments of Go》[1],全文如下:

作為一名全職的Go語言作家[2]和老師[3],我花了很多時間和學生們一起,幫助他們寫出更清晰、更好、更有用的Go程式,我發現,我給他們的建議可以歸納總結為一套通用原則,在這里我將這些原則分享給大家,

1. 你應該是無聊的

Go社區喜歡共識(consensus),比如:Go源代碼有一個由gofmt強制執行的統一的代碼格式規范,同樣,無論你要解決什么問題,通常都有一個標準的、類似于Go行事風格的方法來解決,有時它是標準的方式,因為它是最好的方式,但通常它只是最好的方式,因為它是標準的方式

要抵制住創意、時尚或(最糟糕的是)聰明的傭訓,這些不是Go的行事風格,Go行事風格的代碼簡單、無聊,通常相當啰嗦,而且最重要的是顯式的風格(由于這個原因,有些人把Go稱為面向顯式(obviousness-oriented)風格的編程語言),

當有疑問時,請遵循最小驚喜原則[4],爭取做到一目了然[5],要直截了當,要簡單,要顯式,要無聊,

這并不是說在軟體工程層面沒有展示令人嘆為觀止的優雅和風格的空間了;當然有,但那是在設計層面上,而不是單個代碼行,代碼并不重要,它應該以被隨時替換,重要的是程式,

2. 你應該以測驗為先

在Go中,一個常見的錯誤是先寫了一些函式(比如:GetDataFromAPI),然后在考慮如何測驗它時不知所措,函式通過網路進行了真正的API呼叫,它向終端列印東西,它寫磁盤檔案了,這是一個可怕的的不可測驗性的坑,

不要先寫那個函式,而是先寫一個測驗(比如:TestGetDataFromAPI),如何寫這樣一個測驗呢?它必須為函式的呼叫提供一個本地的TLS測驗服務器,所以你需要一種方法來注入這種依賴,它要寫資料到io.Writer,你同樣需要為此注入一個模擬外部世界的本地依賴,比如:bytes.Buffer,

現在,當你開始撰寫GetDataFromAPI函式時,一切都將變得很容易了,它的所有依賴關系都被注入,所以它的業務邏輯與它與外部世界的互動和監聽方式完全脫鉤,

HTTP handler也是如此,一個HTTP handler的唯一作業是決議請求中的資料,將其傳遞給某個業務邏輯函式來計算結果,并將結果格式化到ResponseWriter,這幾乎不需要測驗,所以你的大部分測驗將在業務邏輯函式本身,而不是handler,我們知道HTTP的作業原理,

3. 你應該測驗行為,而不是函式

如果你想知道如何在不實際呼叫API的情況下測驗這個函式,那么答案很簡單:"不要測驗這個函式",

你需要測驗的不是一些函式,而是一些行為,例如,一個可能是"給定一些用戶輸入,我可以正確地組合URL并以正確的引數呼叫API," 另一個可能是"給定API回傳的一些JSON資料,我可以正確地將其解包到某個Go結構體中,"

當你沿著這樣的思路考量問題的解決方法的時候,寫測驗就容易多了:你可以想象一些這類函式,它們每個函式都會接受一些輸入,并產生一些輸出,并且很容易給它們撰寫單元測驗,有些事情它們是不會做的,例如進行任何HTTP呼叫,

同樣,當你試圖實作"資料可以持久地存盤在資料庫中并從資料庫中檢索"這樣的行為時,你可以將其分解成更小的、更可測驗的行為,例如,"給定一個Go結構體,我可以正確地生成SQL查詢,并將其內容存盤到Postgres表中",或者 "給定一個物件,我可以正確地將結果決議到Go結構體切片中",不需要mock資料庫,不需要真正的資料庫!

4. 你不應制造文書作業

所有的程式都會在某一點上涉及到一些繁瑣的、不可避免的資料倒換重組活動;我們可以把所有這類活動歸入文書作業的范疇,對程式員來說,唯一的問題是,這些文書作業在API邊界的哪一邊?

如果是放在用戶側,那就意味著用戶必須撰寫大量的代碼來為你的庫準備文書作業,然后再撰寫大量的代碼來將結果解壓成有用的格式,

相反(將文書作業放在API實作側),寫零文書作業的庫,可以在一行中呼叫:

game.Run()

不要讓用戶呼叫一個建構式來獲取某個物件,然后再基于這個物件進行方法呼叫,那就是文書作業,只要讓一切在他們直接呼叫時發生就可以了,如果有可配置的設定,請設定合理的默認值,這樣用戶根本不用考慮,除非他們因為某些原因需要覆寫默認值,功能選項(functional option)[6]是一個很好的模式,

這是另一個先寫測驗的好理由,如果你寫的API中創造了文書作業,那么在測驗時你將不得不自己做所有的文書作業,以便使用你自己的庫,如果這被證明是笨拙、啰嗦和耗時的,可以考慮將這些文書作業移到API邊界內,

5. 你不應該殺死程式

你的庫沒有權利終止用戶的程式,不要在你的包中呼叫像os.Exit、log.Fatal、panic這樣的函式,這不是你能決定的,相反,如果你遇到了不可恢復(recover)的錯誤,將它們回傳給呼叫者,

為什么不呢?因為它迫使任何想使用你的庫的人去寫代碼,不管panic是否真的被觸發,出于同樣的原因,你永遠不應該使用會引起panic的第三方庫,因為一旦你用了,你就需要recover它們,

所以你千萬不要顯式呼叫(這些可以殺死程式的函式),但是隱式呼叫呢?你所做的任何操作,在某些情況下可能會panic(比如:索引一個空的片斷,寫入一個空map,型別斷言失敗)都應該先檢查一下是否正常,如果不正常就回傳一個錯誤,

6. 你不要泄露資源

對于一個打算永遠運行而不崩潰或出錯的程式來說,對其的要求要比對單次命令列工具要嚴格一些,例如,想想太空探測器:在關鍵時刻意外重啟制導系統,可能會讓價值數十億美元的飛行器駛向星系間的虛空,對于負責的軟體工程師來說,這很可能會導致一場沒有咖啡的面談,讓人有些不舒服,

我們不是都在為太空器寫軟體,但我們應該像太空工程師一樣思考,自然,我們的程式應該永遠不會崩潰(最壞的情況下,它們應該優雅地退化,并提出退出程序的詳實資訊),但它們也需要是可持續的,這意味著不能泄露記憶體、goroutines、檔案句柄或任何其他稀缺資源,

每當你有一些可泄漏的資源時,當你知道你已經成功獲得它的那一刻,你應該想著釋放它,無論函式如何退出或何時退出,保證將其清理掉,我們可以用Go帶給我們的禮物:defer[7],

任何時候啟動一個goroutine,你都應該知道它是如何結束的,啟動它的同一個函式應該負責停止它,使用waitgroups或者errgroups,并且總是向一個可能被取消的函式傳遞一個context.Context,

7. 你不應該限制用戶的選擇

我們如何撰寫友好、靈活、強大、易用的庫呢?一種方法是避免不必要地限制用戶對庫的操作,一個常見的Gopherism(Go主義)是 "接受介面,回傳結構",但為什么這是個好建議呢?

假設你有一個函式,接受類似于一個*os.File的引數 ,并向其寫入資料,也許被寫入的東西是一個檔案并不重要,具體來說,它只需要是一個 "你可以寫入的東西"(這個想法由標準庫介面,如io.Writer表達),有很多這樣的東西:網路連接、HTTP response writer、bytes.Buffer等等,

通過強迫用戶傳遞給你一個檔案,你限制了他們對你的庫的使用,通過接受一個介面(如 io.Writer)來代替,你將打開新的可能性,包括尚未被創造的型別,后續它們仍然可以滿足(介面) ,可以與你的代碼io.Writer一起作業,

為什么要 "回傳結構體"?好吧,假設你回傳一些介面型別,這極大地限制了用戶對該值的操作(他們能做的就是呼叫其上的方法),即使他們事實上可以用底層的具體型別做他們需要做的事情,他們也必須先用型別斷言來解包它,換句話說,這就是額外的文書作業(應該避免),

另一種避免限制用戶選擇的方法是不要使用只有當前Go版本才有的功能,相反,考慮至少支持最近兩個主要的Go版本:有些人不能立即升級,

8. 你應該設定邊界

讓每一個軟體組件在自己的內部是完整的、有能力的;不要讓它的內部關注點暴露出來,越過它的邊界滲入到其他組件中,這一點對于與其他人的代碼的邊界來說,是雙倍的,

例如,假設你的庫呼叫了某個API,這個API會有自己的模式和自己的詞匯,反映自己的關注點和自己的領域語言,

邊界是那些與你的代碼接觸的點:例如,呼叫API并決議其回應的函式,我把它稱為 "airlock "函式,因為它的作業部分是確保你的內部型別和關注點不會泄露出去,并防止外來資料泄露進來,

一旦你讓一點外來資料在你的程式內部自由運行,它很快就會到處亂跑,你的其他包都需要匯入這些外來型別,這很煩人,而且代碼將會有一股糟糕的味道,

相反,你的airlock函式應該做兩件事:它應該將外來資料轉化為你自己的內部格式,而且應該確保資料是有效的,現在,你的所有其他代碼只需要處理你的內部型別,它不需要擔心資料是否會出錯、丟失或不完整,

另一種執行良好邊界的方法是始終檢查錯誤,如果你不這樣做,無效的資料可能會泄露進來,

9. 你不應該在內部使用介面

一個介面值說:"我不知道這個東西到底是什么,但也許我知道有些事情我可以用它來做," 這在Go程式中是一種超級不方便的值,因為我們不能做任何沒有被介面指定的事情,

對于空介面(interface{})來說,這也是雙倍的,因為我們對它一無所知,因此,根據定義,如果你有一個空的介面值,你需要把它型別化為具體的東西才能使用它,

在處理任意資料(也就是在運行時型別或模式未知的資料)時,不得不使用它們是很常見的,比如無處不在的map[string]interface{}[8],但是,我們應該盡快使用airlock將這一團無知轉化為某種具體型別的有用的Go值,

特別是,不要用interface{}型別值來模擬泛型(Go有泛型[9]),不要寫一個函式,接受一些可以是七種具體型別之一的值,然后對其進行型別轉換,為該型別找到合適的操作,相反,寫七個函式,每個具體型別一個,

不要僅因為你可以在測驗中注入mock,就創建一個公共的介面,這是一個錯誤,創建一個真正的用戶在呼叫你的函式之前必須實作的介面,這違反了“無文書作業原則”,不要在一般情況下寫mock;Go不適合這種風格的測驗,(當Go中的某些東西很困難時,這通常是你做錯事的標志,)

10. 你不要盲目地遵從誡命,而要自己思考

人們說:"告訴我們什么是最佳做法",仿佛有一本小秘籍,里面有任何技識訓組織問題的正確答案,(是有的,但不要說出去,我們不希望每個人都成為顧問),

小心任何看似清楚、明確、簡單地告訴你在某種情況下該怎么做的建議,它不會適用于每一種情況,在適用的地方,它都需要告誡,需要細微的差別,需要澄清,

每個人都希望得到的是不需要真正理解就能應用的建議,但這樣的建議比它能帶來的幫助更危險:它能讓你走到橋的一半,然后你會發現橋是紙做的,而且剛開始下雨,


非常感謝比爾-肯尼迪(Bill Kennedy)[10]和伊南克-古姆斯(Inanc Gumus)[11]對這篇文章的有益評論,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275399.html

標籤:AI

上一篇:實時 OLAP, 從 0 到 1

下一篇:重磅官宣:Nacos2.0性能提升10倍

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more