天天看點

Linux背景開發調試經驗分享

作者:騰訊技術工程

作者:beck

畢業超過十年了,感慨歲月無情。做了若幹年背景開發(之前做電信領域),大緻說一下常見的開發心得和調試手段。使用網際網路這麼多年,收獲的很多,總結的很少。本着網際網路精神,希望可以幫到網際網路另一端的你。由于本人是做 C 語言的開發,陳述的經驗也是 C 常用的調試手段。

調試很麻煩,困擾着無數程式員們。很難有人保證自己寫的代碼一行錯誤都沒有,有問題你就要查。怎麼查?高手者,反彙編,看 2 進制;low 一點的就 gdb、看統計;再 low 就加列印。還可以再 low 嗎?可以,自己寫 bug,别人查。方法林林總總,長期掌握總可以找到适合自己的。

而調試的目的是什麼,找到 BUG。想當年一個高手比喻的好:你找 BUG 其實你就是福爾摩斯,為啥是福爾莫斯呢?想想你看到 BUG 案發現場--合格的程式都有日志、dump 記憶體、計數等基本案發現場吧。嗯,什麼都沒有,找寫代碼的人自己查。找問題就是在衆多資訊中,抽絲剝繭,找到疑點、反複推演程式運作的代碼,最終找到作案的那一行或者幾行代碼。

這個過程很折磨人,沒有任何眉目時,令人茶不思飯不想。找到問題問題後,如打雞血般興奮,自己也會陶醉般飄飄然。真正受過折磨的人,才能體會到修改問題的滋味一二。

開發的程式大緻要經過一下兩個階段,最終才可以上線釋出。

功能開發階段

本階段的主要目标是根據業務要求,開發程式。僅僅是 coder,僅僅是寫 if else 嗎?寫程式真的是這樣嗎?如果是這樣,那麼 coder 會更加工廠話,枯燥化。

做事都講究未雨綢缪,做程式更應該這樣。大學 C 語言經典教材中定義程式為:程式 = 資料結構 + 算法。而實際生産的過程中,将商業程式做如下的補充定義,我覺得更合适:程式 = 資料結構 + 算法 + 業務邏輯(計算邏輯)+ 架構;

先說說為什麼補充業務邏輯,有意義的程式本身就是某種業務邏輯(計算邏輯)的抽象。完成這個業務邏輯才是最終的目的,請不要拿一些算法研究的 code 和我擡杠。

其實作為開發人員,測試驅動開發(TDD)很好思考問題的思路。也許有人聽過,也許有同學用過,如果感覺使用不好的兄弟,我可以告訴大家:應該是測試場景 + 場景驅動開發。對,僅僅是裡面融入“場景”這個賓語,大家在做開發的時候,就有目的性和針對性。

任何一個業務邏輯,都可以拆分為多個業務場景。場景逐一解決,場景逐一測試,我們開發其實很簡單。說的很簡單,但是整個過程,需要 50%的時間思考解決問題場景, 20%的編碼,30%的測試。其實思考問題的 50%的時間,可以放在任何時間去做(休息時,地鐵上,班車上...),隻要讓自己足夠的靜,你就會将整個業務邏輯思考的很清楚,分解為多少個業務場景也很明确。對于複雜的業務場景,建議适當的做筆記,多從全局的業務邏輯考慮:自己細化的得到結論是否符合所有的業務場景。反複的修正,直到正确。

具體編碼的時候,經過我們前面的深思熟慮,每個細節都已經很清楚了,采用疊代的方式,批量的傳遞小的功能點就可以了。

開發階段的總結兩個關鍵字:TDD + 疊代。需要詳情的同學自行 baidu,google。

Linux背景開發調試經驗分享

功能調試階段

調試的手段很多,走讀代碼,打日志,gdb,統計,coredump 等,如果有精力也可以搞搞的白盒測試什麼的。測試的意圖也很明顯,确認代碼是否按照正确的編碼意圖在運作!其實自己寫的代碼,自己還是可以輕松駕馭調試的,原因就是自己清楚代碼的本意該如何運作,現在出現了什麼問題。

程式員的三大悲劇之一,就是不知道什麼時候需要定位一個其他人寫的 bug。定位前也需要必須要了解另外一位程式員寫這段代碼的意圖是什麼,否則沒有辦法定位。了解其他的人寫的代碼途徑也就是通過閱讀代碼了解大緻思路,通過日志、gdb、或者統計資訊補充代碼意圖的更多細節,或者修正了解不對的思路。

這個過程可能很枯燥,也可能很有挑戰,試圖通過種種迹象去了解另外一個程式員寫代碼的初衷和意圖,會不會有窺探人家隐私的趕腳!

其實,上面說了這麼多隻是告訴大家調試好的前提,和調試的初衷。

一個優秀的程式員,你會發現他有很多調試技巧,也就是很多調試手段擷取自己想得到資訊。資訊擷取的多,自然就很容易清除程式本身的意圖。

調試工具的使用細節和說明,同學們可以自行 baidu,google。

我在這裡簡單的闡述一下自己是怎麼調試程式的,怎麼了解各種工具的,歡迎大蝦門指點交流?

1)關于日志

如何打好日志絕對是門學問。日志列印多了,自然會影響背景程式的性能;同樣列印的少了,沒有辦法定位問題;更苦逼的是列印到空指針,更有可能 coredump 掉自己的程式;

是以日志的技巧就是:少,且内容豐富。

如何少,其實就是彙聚。

能不能将表達同一個意思的列印減少?

能不能在關鍵異常的地方加上統計(輸出統計)?

能不能不打?

能不能記憶體中記錄關鍵資訊,在想要的時候,控制其列印時機?

如何豐富,其實就是少打描述性詞彙,多打有用的程式運作資訊。

方法很多,大家多多思考。并且列印的優化,是反複優化的過程,不是一蹴而就的。曾經遇見一個大牛,測試部提問題了,這哥們從來不去定位。直接告訴測試的兄弟,幫忙執行以下軟調,将收集的日志給他分析一下就可以解決問題。

2)關于 gdb

還有大牛說過:“我就是程式,程式就是我”。我常用 gdb 來檢驗自己對程式的了解。常用的 gdb 功能就是列印一些程式的運作資訊,修改一些内部運作資訊,構造複雜場景。

其實很簡單,程式在什麼場景下應該有什麼樣的行為,我自己的必須清楚。必須知道關鍵變量的資訊是否正确,周期 gdb 出來,确認變量的資訊是否正确,然後決定程式是否符合預期在執行。

可靠性的程式都有類似的保護機制,但是通常需要繁瑣的構造測試條件,觸發保護機制(如檢測到丢包率很高,要告警等)。其實大多數的保護機制都是通過記錄一些狀态後,程式然後觸發的保護機制。

其實,可以 gdb 構造出異常狀态,确認告警機制是否生效。gdb 很好的補充這方面的測試和驗證工作。

3)關于統計

統計資訊,是關鍵資訊彙集的最好的例子。資料少,切資訊明了。

電信軟體中,很多子產品都通過這樣的資訊:自證清白。也很容易發現問題出現哪裡。

統計的實質,就是通過全局變量,記錄一些程式正常,異常點的統計資訊。然後通過某種手段輸出出來。

4)關于 coredump

大家看到 coredump 都會頭痛,其實 coredump 也是很好的定位手段。

首先程式 coredump 後,會有詳細的 coredump 檔案,該檔案詳細的記錄了程式在 core 之前的運作資訊。gdb 這個 coredump 檔案,你想看什麼都可以。這隻是簡單的使用 coredump。

如果碰到複雜的問題,難搞的問題,其實也可以使用 coredump 來定位。

比如程式執行到一個十分不常見的代碼分支,然後程式就 core 掉了,但是目前輸出資訊(日志等),根本沒有辦法進一步定位問題。

怎麼辦?有沒有想過在複現問題的環節,出個調試版本的程式,在異常分支上主動觸發記憶體異常,産生 coredump,利用 coredump 資訊,來确定程式是如何異常的。

5)關于代碼修改

這個也是我常用的手段之一,反複的對比修改前後的代碼,确認修改代碼的準确性,全面性,反思自己代碼修改是否全面?其實這裡面工具就是 beyondcompare。

coding 數載,偶有所得,記錄于此,望各位有所得!

繼續閱讀