2009-04-08 64 views
5

調試問題的標準方式是什麼?這可能看起來像一個相當廣泛的問題,有些人回答'這取決於問題',但我認爲我們很多人都是憑直覺調試,並沒有真正嘗試過我們的過程。這就是爲什麼我們說'這取決於'。調試的標準方法

最近我被迫對我的過程進行評論,因爲一些開發者和我正在解決同樣的問題,而我們正在以完全不同的方式進行調試。我希望他們明白我想要做什麼,反之亦然。

經過一番思考後,我意識到我的調試方式其實很單調。我將首先嚐試能夠可靠地複製問題(尤其是在本地計算機上)。然後通過一系列消除(並且這是我認爲它依賴於問題的地方)嘗試識別問題。

其他人試圖以完全不同的方式做到這一點。

所以,只是想知道什麼一直在爲你們在那裏工作?如果你必須用文字來形式化,你會怎麼說你的過程是用於調試的?

順便說一句,我們還沒有發現我們的問題=)

+1

你的問題是與同步模塊,你需要使用更多的XML - 也轉換到JSON是完全錯誤的。最後,你的襪子在沙發後面 – 2009-04-08 04:04:06

+0

是的,我想知道他們在哪裏=) – Fung 2009-04-08 04:10:02

回答

7

我的方法因我熟悉系統而異。通常我會這樣做:

  1. 如果可能的話,複製失敗。
  2. 檢查故障狀態以確定故障的直接原因。
  3. 如果我對這個系統很熟悉,我可能會對根本原因有一個很好的猜測。如果不是,我開始通過軟件機械地追溯數據,同時挑戰軟件做出的基本假設。
  4. 如果問題似乎有一個一致的觸發器,我可以用調試器手動前進代碼,同時挑戰代碼所做的隱含假設。

尋找根本原因當然是事情會變得毛茸茸的地方。這是一個轉儲(或更好的,一個活的,破碎的過程)可以真正無價的地方。

我認爲我調試過程中的關鍵點是挑戰預想和假設。我發現該組件中的一個錯誤的次數,我或其同事發誓工作正常是巨大的。

我被更直觀的朋友和同事告訴我,當他們看着我調試時,我很迂腐,或者讓我幫他們弄清楚什麼。 :)

+0

+ 1對挑戰性的概念和假設。 – Fung 2009-04-08 03:59:29

3

當我起來反對,我不能讓似乎想出一個錯誤,我想使問題的典範。製作問題代碼部分的副本,並逐個從其中刪除功能。在每次移除後對代碼運行單元測試。通過這個過程,您將刪除具有該錯誤的功能(並因此找到該錯誤),或者將錯誤隔離到包含問題本質的核心代碼段。一旦你發現問題的本質,它很容易解決。

1

我也是使用淘汰過程的忠實粉絲。排除變量極大地簡化了調試任務。這往往是應該做的第一件事。

另一個真正有效的技術是儘可能回滾到上一個工作版本,然後重試。這可以是非常強大的,因爲它給你堅實的腳步,更仔細地進行。其中的一個變體就是讓代碼處於工作的地步,功能更少,而不是處理更多的功能。

當然,不只是嘗試一些事情是非常重要的。這會增加你的絕望,因爲它永遠不會工作。我寧願做50次運行來收集有關bug的信息,而是大肆揮灑,希望它能奏效。

2

我通常通過根據我手邊的信息形成一個假設開始。一旦完成,我會努力證明它是正確的。如果它證明是錯誤的,我開始時有一個不同的假設。

大多數多線程同步問題很容易用這種方法解決。

此外,您還需要對您正在使用的調試器及其功能有一個很好的理解。我在Windows應用程序上工作,發現windbg對查找錯誤非常有幫助。

+1

我發現這隻適用於經驗豐富的開發人員。當新手試圖做到這一點時,看起來更像是隨機射擊,希望能夠擊中一個。我想主要是因爲他們缺乏從最合理的假設開始的經驗。所以真的不要爲新員工提供建議。 – Fung 2009-04-08 04:14:32

2

將錯誤減至最簡單的形式通常會導致對該問題的更好理解,並增加了在必要時能夠讓其他人蔘與的好處。

設置一個快速複製場景,以便有效利用您的時間來測試您選擇的任何虛擬變量。

創建工具以快速轉儲環境以進行比較。

通過日誌記錄創建並重現錯誤,達到最高級別。

檢查系統日誌是否有任何報警。

查看文件日期和時間戳以獲得感覺問題是否是最近的介紹。

通過源代碼庫查看相關模塊中的最近活動。

應用演繹推理並應用Ockham's Razor原則。

願意退後一步,並從問題中休息一下。

+0

最糟糕的錯誤是那些暴露了基本設計缺陷的錯誤。那些讓我哭泣。 – 2009-04-08 04:11:42

1

我選了那些在網上或某些我不記得的書(它可能已被CodingHorror ...)

調試101:

  • 重現
  • 逐步範圍窄
  • 避免調試器
  • 變化只做一件事一時間

心理方法:

  • 木製印度
  • 不要推測
  • 不要太快責備工具
  • 瞭解雙方的問題及解決
  • 稍事休息
  • 考慮多種原因

Bug預防方法:

  • Monit或者你自己的錯注射習慣
  • 介紹調試工具的早期
  • 鬆耦合和信息隱藏
  • 撰寫回歸測試,以防止再次發生

技術方法:

  • 惰性跟蹤語句
  • 查閱第三方產品的日誌文件
  • 搜索的堆棧跟蹤
  • 網頁介紹契約式設計
  • 徹底清除
  • 間歇錯誤
  • Explot Localility
  • 介紹虛擬實現和子類
  • 重新編譯/重新鏈接
  • 探頭邊界條件和特例
  • 檢查版本依賴關係(第三方)
  • 已經改變最近
  • 不信任的錯誤消息
  • 圖形錯誤
+0

我其實覺得這個答案挺有用的。不明白爲什麼它被標記爲-1。 – Hexagon 2009-04-26 15:25:24

0

我調試的方法是不同的,可能是因爲我仍然初學者校驗碼。

當我遇到邏輯錯誤時,我似乎最終添加了更多的變量,以查看哪些值到了哪裏,然後在導致問題的代碼段中逐行調試。

0

複製問題並生成可重複的測試數據集絕對是調試的第一步也是最重要的步驟。

如果我能確定一個可重複的錯誤,我通常會嘗試隔離所涉及的組件,直到找到問題。我經常會花一點時間排除一些情況,這樣我就可以明確地指出:問題不在於組件X(或進程Y等)。

4

考慮一下David J Agans編寫的書「Debugging」。小標題是「尋找即使是最棘手的軟件和硬件問題的9條不可或缺的規則」。他調試規則的列表 - 在網站(而且也爲這本書的鏈接,太)在海報的形式提供是:

  • 瞭解系統
  • 使其失敗
  • 退出的思考和期待
  • 分而治之
  • 一次更改一件事
  • 保留的審計線索
  • 檢查插頭
  • 獲取新鮮的觀點
  • 如果你沒有解決它,它是不固定的

最後一點是在軟件行業尤爲重要。

0

首先,我嘗試複製錯誤,但不能複製錯誤,在非平凡的程序中猜測問題基本上是不可能的。

然後,如果可能,請在單獨的獨立項目中分解代碼。造成這種情況的原因有幾個:如果原始項目很大,則很難進行調試,因此消除或突出顯示有關代碼的任何假設。

我通常總是有另一個VS打開的副本,我用它來在迷你項目中調試部件,並測試後來添加到主項目中的例程。

一旦在單獨模塊中再現錯誤,戰鬥幾乎贏了。

有時候很難分解出一段代碼,所以在這種情況下,我會根據問題的複雜程度採用不同的方法。在大多數情況下,關於數據的假設似乎出現並咬我,所以我嘗試在代碼中添加大量斷言,以確保我的假設是正確的。我還使用#ifdef禁用代碼,直到錯誤消失。消除對其他模塊的依賴......等等,像禿鷲一樣緩慢地盤旋在一起。

我想我沒有真正意識到這樣做的方式,它有很大的變化,但總體原則是消除這個問題周圍的噪音,直到它明顯是什麼。希望我沒有聽起來太混亂:)

1

我發現「調試」的最佳時間是在編寫代碼的時候。換句話說,要防守。檢查返回值,自由使用斷言,使用某種可靠的日誌記錄機制並記錄所有內容。

爲了更直接地回答這個問題,我調試問題的最有效方法是閱讀代碼。擁有日誌可以幫助您快速找到相關的代碼。沒有記錄?花時間把它放進去。看起來好像你找不到錯誤,你可能不會。日誌記錄可能會幫助您找到另一個錯誤,並且最終一旦您已經完成了足夠的代碼,就會發現它......比設置調試器並嘗試重現問題,單步執行等更快。

在調試過程中,我試着想一下可能出現的問題。我提出了一個相當任意的分類系統,但它適用於我:所有錯誤都歸入四類之一。請記住,我在說的是運行時問題,而不是編譯器或鏈接器錯誤。這四個類別是:

  • 動態存儲器分配
  • 堆棧溢出
  • 未初始化的變量
  • 邏輯錯誤

這些類別已最有用的我與C和C++,但我期望他們在別處適用得非常好。邏輯錯誤類別很大(例如,當正確的東西是< = b時,輸入<b),並且可能包含諸如未能在線程之間同步訪問的情況。

知道我在找什麼(這四件事中的一件)可以幫助我們找到它。發現錯誤似乎總比修復它們困難得多。

用於調試的實際機制最經常有:

  1. 做我有一個自動化測試,證明了問題?
    • 如果沒有,添加一個失敗的測試
  2. 更改代碼,使測試通過
  3. 確保所有其他測試還通過
  4. 檢查的變化

在你的環境中沒有自動化測試?沒有時間像現在這樣來設置它。太難組織的東西,所以你可以測試你的程序的個別部分?花時間做到這一點。可能需要「太長時間」才能解決這個特定的錯誤,但是越早開始,其他一切就會越快。同樣,您可能無法修復您正在尋找的特定錯誤,但我敢打賭,您一路上找到並修復了其他錯誤。