1. 程式人生 > >關於代碼調試de那些事

關於代碼調試de那些事

左右 == 一次 done 推斷 編輯 有用 track 幾分鐘

原文出處:http://www.wklken.me/posts/2014/11/23/how-to-debug.html

  • 關於代碼調試de那些事
    • 1.你得明白你在做什麽, 保持清醒
    • 2.想清楚了再寫代碼
    • 3.關於腳手架代碼
    • 4.寫完一段代碼第一時間自己review一下
    • 5.review中註意, 代碼是摳過來的麽?
    • 6.搞明白問題的表現是什麽(癥狀)
    • 7.調試過程中, 需要時刻註意
    • 8.環境/數據一致性
    • 9.先不要動代碼, 假設代碼是正確的
    • 10.首先要懷疑自己
    • 11.對於莫名其妙的問題, 多試幾種情況
    • 12.先回到正確的代碼
    • 13.如果一段代碼是沒動過的代碼
    • 14.bug總是傾向於集中出現在一起
    • 15.對於很長很長, 上二分法
    • 16.print or debug?
    • 17.十分十分詭異的問題
    • 18.當一個問題超過半小時
    • 19.關於google
    • 20.關於求助
    • 21.吃一塹長一智

寫代碼最完美的就是, 想清楚, 碼, 運行, perfect, DONE, 下班.

當然, 那是完美的狀態. 大多數時候只存在於理想中.

現實是, 我們會被各種坑, 被環境坑, 被語言坑, 被依賴坑, 被第三方庫坑, 被編輯器坑, 被自己坑(三個月前的自己/昨天的自己/幾分鐘前的自己), 被數據庫坑, 被緩存坑, 被隊友坑(這個比較慘), 被需求變更坑(這個也是)......

所以, 總是避免不了代碼調試.

今天順帶過了下<<想計算機科學家一樣思考Python>>, 裏面每一章最後都有關於調試的一些觀點, 例如閱讀 - 深思 - 修改/運行/回退

, 所以決定來寫寫關於代碼調試的一些東西.

其實, 代碼調試是論如何排查問題的一個過程, 根據一切蛛絲馬跡, 推斷出問題所在, 並消滅之.(破案的即視感)

技術分享

下面是一些關於一些自己在寫代碼和調試的總結


1.你得明白你在做什麽, 保持清醒

代碼調試有時候會讓你陷入無盡的自我懷疑/迷茫/憤怒/沮喪/窘迫/挫敗(無限負能量), 很容易被這些情緒左右, 不清醒, 陷入懷疑自我(一定是我調用的方式不對), 或者懷疑一切(一定是數據庫問題, 不對, 緩存問題, 不對, 接口問題, 好像不對, 數據問題), 或者胡亂改代碼(改-跑-錯了-再改-跑-又錯-再改, 傳說中的隨機行走編程), 或者......(掙紮吧......)

此刻, 保持清醒的自我是非常重要的, 要明確: 我在做什麽, 問題是什麽癥狀, 原來邏輯是什麽, 最有可能出問題的是哪裏?

2.想清楚了再寫代碼

如果連需求是什麽, 想要做什麽都沒整明白, 就吭哧吭哧開寫, 意圖在實踐中摸索通向勝利的道路, 是很愚蠢的行為.

需要去理解需求, 自己要做什麽, 然後, 在大腦中構造, 現在有什麽, 為了完成需求需要做什麽, 完成大體的組成結構/步驟流程的思考後, 再著手去做.

大到整體設計, 小到一個函數, 都可以這麽處理

例如, 遇到復雜問題, 可以先寫註釋, 完整所有函數整體設計, 然後再填充細節

def dosomething():
        “””
        “””
        # step1: call func test()

        # step2: parse url to 

        # step3: judge

        # step4: convert and return

3.關於腳手架代碼

在邏輯的關鍵位置, print/assert關鍵信息, 用於在調試中迅速確認問題. (一些中間值/狀態/條件判斷結果)

當然, 信息除了關鍵這個特性, 還需要足夠豐富顯眼, 一遍一次性定位問題. (既要好看又要有用)

你需要確定下如何用順手的編輯器快速輸入這些代碼, 可以用各類語言的snippets

例如, 在寫python時候, 我很喜歡prt(k-vim自動補全), 快速插入一些需要的信息

print "TRACK ================= result", type(result), result, result == "test"

4.寫完一段代碼第一時間自己review一下

事實證明, review的效果比寫完直接跑再來調, 效率高多了.

剛寫完一段代碼, 思路還很清晰, 跳到開始, review過程中註意各類變量, 條件判斷, 函數調用, 上下文, 一致性, 錯誤處理等, 花不了多少時間, 卻能發現一些顯而易見的問題, 省下很多無謂的調試時間(沒問題不需要調試!).

5.review中註意, 代碼是過來的麽?

很多時候從其他地方copy代碼過來(一行或幾行, 有時候只是一個函數調用或一個判斷), 但是很容易忘了根據當前情況修改一些必要的值, 導致問題

例如函數調用, 這個地方調用參數可能跟你copy這行代碼需要參數不一樣, 但是放在這裏並不會報錯(一切運作正常), 最終結果並不對.....

好了, 開始調試

6.搞明白問題的表現是什麽(癥狀)

運行代碼, 報錯了, 有些人會瞬切回編輯器, 開始改代碼(作高效狀)......>_<#

問題是: 報錯提示你看了麽, 看明白了麽?

現在大部分語言, 其報錯提示已經很明顯了, 精確到行/變量, 雖然整個異常棧信息可能很長(非常長), 但是都有其特征(在最前或在最後,或在中間靠後, 有關鍵字), 仔細看下報錯信息, 精確制導才是王道.

所以, 你需要從錯誤信息中先確認

錯誤類型
發生錯誤的地方

很多語法問題可以根據這個信息直接定位

7.調試過程中, 需要時刻註意

改的是不是正確的目錄下正確的文件?(大坑)

保存了麽(編譯了麽)?(又一個坑)

服務重啟了麽?

跟數據庫有沒有關系/跟緩存有沒有關系, 要不要清?

……

以上問題, 隨便碰上一個你都可能發現, 自己書寫的代碼和當前運行來調試的代碼不一樣.(會浪費你巨量的時間)

自己調試半天怎麽還是一樣的結果

我一直在修改, 但是沒有什麽區別(出現這種情況要自問一下了)

可以顯示在代碼頭部打印或者故意出錯, 確認是同一套代碼

8.環境/數據一致性

當你發現在本地無法復現別人報過來的問題(在我電腦上是正常的), 這時候, 需要考慮是否是環境和數據的問題.

9.先不要動代碼, 假設代碼是正確的

遇到問題, 不要急著修改代碼, 需要假設, 代碼是正確的, 然後去復現, 復現之後定位.

10.首先要懷疑自己

你不能一旦代碼跑不動就懷疑是別人的問題, 然後拋給別人, 這樣做同樣是很不負責任而且很愚蠢的.

首先, 你需要懷疑自己, 排查問題, 當確定不是自己的問題之後, 將問題定位, 輸入, 預期結果, 現在的異常結果都處理好, 生成一個問題, 拋給對應負責人. (一切沒有價值的懷疑都是無意義的)

程序員都是好人, 每次都在想: 一定是我的問題

11.對於莫名其妙的問題, 多試幾種情況

有時候碰上一些詭異的問題, 例如有一種情況的輸入會報錯, 這時候, 再跳過去修改代碼前, 可以多嘗試幾種輸入, 涉及邊界/異常/正常等情況, 排除法, 精確制導.

例如, 可以變換輸入值的範圍(擴大或縮小, 可能用二分法), 變換輸入類型和格式

12.先回到正確的代碼

如果這段代碼是由於修改導致的, 可以註掉此次變更代碼, 同樣的輸入再次驗證定位

13.如果一段代碼是沒動過的代碼

如果你確保確實沒動過, 此時, 先不要懷疑自己, 更大的可能是別人的問題.

可能情況: 依賴出了問題(調用函數返回數據不對/異常? 依賴請求掛了? ……), 數據出了問題(表結構變更/服務返回數據變更), 環境問題(數據庫/緩存)

14.bug總是傾向於集中出現在一起

很多時候, bug是紮堆的, 可以回憶下之前修改的地方, 確認問題.

15.對於很長很長, 上二分法

可能函數很長, 或者調用鏈很長, 不易調試.(光打調試信息就得打得手疼)

找到關鍵變量, 上二分法, 無上利器.

16.print or debug?

個人偏好簡單粗暴的print, 主要是用的vim+sinppet, 快速高效.

當然, 如果用IDE, 用 debug

17.十分十分詭異的問題

debug, 打斷點, 一點點調試吧, 只能這樣了.

18.當一個問題超過半小時

歇一歇, 走動走動, 打個水, 呼吸下新鮮空氣.

這時候有利於脫出情境, 去掉挫敗感/憤怒/迷信等

很多時候突然靈感一到, 瞬間明了(這種感覺很奇妙)

19.關於google

有些錯誤信息, 如果覺得比較獨特詭異, 可以google下, 你會找到更多的一些信息的.

20.關於求助

實在搞不定, google大神也搞不定, 此時可能需要求助了.

前提, 你自己能把問題想清楚, 並且邏輯清晰地描述出來.(什麽業務什麽位置的什麽邏輯, 報錯類型和報錯信息, 輸入輸出, 迄今做了哪些嘗試等等) 要學會聰明地問問題, 高效, 尊重自己也尊重別人.

如果你自己都沒整明白怎麽問, 別人也無能為力.

遇到很多人, 直接上來就一句xxx出問題了, 沒有前置條件後置結果中間癥狀......

不過, 如果你會聰明地問, 那就放心大膽地問吧, 不用磨磨唧唧的, 程序員大都是善良的孩子.

21.吃一塹長一智

被坑了就要總結總結, 有個記錄, 不被同一個問題坑兩次.

如果被坑了就忘, 還需要去反復求助, 那這屬於坑隊友的行為(鄙視下)


好了, 就這些:)

關於代碼調試de那些事