vim-go 的 tutorial 裡頭有很多有趣、有用的技巧。取出一些我覺得比較好用的。
Import 的技巧
:GoImportAs ff fmt
:GoImport strings
Edit 的技巧
if 表示函數的內部 inside a function
dif = delete inside a function
yif = yank inside a function
vif = visual mode inside a function
af 表示整個函數 -> a function
daf = delete a function
yaf = yank a function
vaf = visual mode a function
Trace 程式碼的技巧
對 channel 的理解
:GoChannelPeers 選擇某個channel,顯示它的send/receive/def
對 variable 的理解
:GoReferrers 選擇某個變數,顯示所有被使用的地方。
對於 type 的理解
:GoImplements 選擇某個類別,顯示它實作的介面。(一個有搭配函數的類別就很可能是有實作介面的類別)
:GoDescribe 選擇某個類別,顯示所有使用它的函數。(用使用範例來"描述"一個類別)
對於 error 的理解
:GoWhicherrs 選擇某個錯誤,顯示它可能包含的錯誤資訊。
對 func 的理解
:GoCallees 選擇某個區域變數(該變數的型態是函數),顯示它可以對應到的函數。
:GoCallstack 選擇某個函數顯示它被呼叫時的call stack
:GoCallers 選擇某個函數的定義,顯示它被呼叫的位置
Refactor 的技巧
將區段的程式碼抽取出來,變成函數
:GoFreevars 區塊選擇一段程式碼之後,顯示這段程式碼裡的輸入變數(input variables)
:GoRename 修改一個變數的命名,自動修改多個位置。
註:在新版的 vim-go ,已經用 guru 取代了 oracle 。所以如果沒有看到 oracle ,不用再去找了。
Wednesday, August 31, 2016
log 與 error handling --- 讓錯誤看得出來是錯誤
公司的同事 mike 前幾天跟我講了幾句話,讓我受用無窮:
於是我歸納了一些要寫出嚴謹的 golang 程式,可以注意的重點:
- 很多程式設計師寫出了幽靈程式碼,總是抓不出錯。這是因為在撰寫程式時,就不夠嚴謹。
- 要如何寫出嚴謹的程式碼呢? 遇到異常(exception)或是錯誤(error),有辦法處理,就要設法處理。沒有辦法處理時,也要寫在規格(也就是註解),至少讓後來維護的人知道這邊有個「坑」
於是我歸納了一些要寫出嚴謹的 golang 程式,可以注意的重點:
- 不要亂用 log level ,要小心地使用 log level 。比方說,在 golang 裡, log.Fatal 就會呼叫 exit(1) ,這個就絕對不可以亂用。有時候,網路上找到的 code snippet 就用了 log.Fatal。如果直接不加思索的照抄。那程式就會異常終止了。
- log level 和 log message 要好好地搭配使用: 比方說,如果引入了 logrus 這套 log level 的函式庫。對於不會影響程式正常運作的 log level 就有 info, warn, error 三種。既然已經用了 warn 的 log level ,其實 log message 就該避開使用 error 這個關鍵字。
- 儘量在程式裡處理所有的函數傳回的 error 。要做到這件事,有一個 golang tool 可以使用: errcheck 。這個工具可以檢查出,所有傳回錯誤,錯誤卻沒有被處理的函數。如果有用 vim-go 的話,可以下指令 :GoErrCheck
Labels:
debug,
error_handling,
loglevel
Thursday, August 18, 2016
依賴注入 - dependency injection
寫單元測試時,常常會遇到一問題,原始的程式碼本身的結構,難以加入單元測試。
最近我遇到了一個問題,我寫的程式會呼叫 git clone ,而 git clone 在網路環境不佳時,甚至會執行超過24小時,將程式的 go routine 整個卡住。所以解法就是需要將 golang 的外部指令呼叫,改成有 timeout 的。
要加上這個 timeout 並不難,困難點是,要如何測試這個功能?因為其實要模擬出 git clone 長時間執行的環境,並不是很簡單的事。
解法是這樣子:
加上這個功能時,必須將這個「為指令加上 timeout 功能」實作成一個獨立的函數,使它的功能獨立,並不「依賴」於 git clone 。換言之,「 git clone 」對應的指令,會成為這個函數的輸入變數(input argument),由外部「注入」。於是這個功能就可以獨立地來寫單元測試來測。測試它的時候,就可以用「 sleep 500 」對應的指令,來做為它的輸入變數(input argument)
原始程式碼的修改
新增的程式碼和單元測試
最近我遇到了一個問題,我寫的程式會呼叫 git clone ,而 git clone 在網路環境不佳時,甚至會執行超過24小時,將程式的 go routine 整個卡住。所以解法就是需要將 golang 的外部指令呼叫,改成有 timeout 的。
要加上這個 timeout 並不難,困難點是,要如何測試這個功能?因為其實要模擬出 git clone 長時間執行的環境,並不是很簡單的事。
解法是這樣子:
加上這個功能時,必須將這個「為指令加上 timeout 功能」實作成一個獨立的函數,使它的功能獨立,並不「依賴」於 git clone 。換言之,「 git clone 」對應的指令,會成為這個函數的輸入變數(input argument),由外部「注入」。於是這個功能就可以獨立地來寫單元測試來測。測試它的時候,就可以用「 sleep 500 」對應的指令,來做為它的輸入變數(input argument)
原始程式碼的修改
新增的程式碼和單元測試
Labels:
dependency_injection
除錯的利器 - tcpdump
開發程式,我最常用來除錯的技巧主要就是幾種:
然而,上述兩種技巧都有一些限制。
單元測試的話,如果原本的程式寫的很差,我自己新寫的部分有時也很難測,要先重構舊的程式才能寫單元測試。查 log 檔的話,如果一些 bug 是在 production 環境才出現,也很難取得完整的 log ,因為在 production 環境, loglevel 通常是設定成 info 而已。
也因此,在 production 環境之下,用 tcpdump 有時可以取得比 log 還更完整的資訊。
- 寫單元測試
- 查 log 檔
然而,上述兩種技巧都有一些限制。
單元測試的話,如果原本的程式寫的很差,我自己新寫的部分有時也很難測,要先重構舊的程式才能寫單元測試。查 log 檔的話,如果一些 bug 是在 production 環境才出現,也很難取得完整的 log ,因為在 production 環境, loglevel 通常是設定成 info 而已。
也因此,在 production 環境之下,用 tcpdump 有時可以取得比 log 還更完整的資訊。
Labels:
debug,
production_environment
Wednesday, August 17, 2016
例外處理
寫程式有一段時間了,有一些習慣問題,卻一直沒有深刻的認識。直到真的寫出 bug 以後,才會理解。
上方的例子,就是一個不好的例子。 GetCurrPluginVersion() 的傳回值,其實應該要有兩個資料型態,一個應該要用 string ,另一個應該要用 error 。而上頭的例子,只用一個 string 就裝了兩個不同資料型態的資料。這樣子讓使用 GetCurrPluginVersion() 的使用者,很容易潛意識地主觀認為,這個函數是一定會成功的,不會有 error 。於是,真的有 error 時,就一直穿透,直到很後期才發現。
Labels:
error_handling
Subscribe to:
Posts (Atom)