天天看點

遇到無法複現的 Bug 該怎麼辦?

作者:CSDN
遇到無法複現的 Bug 該怎麼辦?

【CSDN 編者按】這篇文章探讨了軟體開發中常見的問題:無法在開發者的機器上複現使用者報告的 bug。文章強調了開發者應該承擔起責任,努力追蹤問題,而不是強迫使用者證明 bug 的存在。文章提出了解決 bug 的雙管齊下的方法,強調了使用者行為和溝通在 bug 解決中的作用,介紹了解決 bug 的工具和技術,讨論了并發問題,并分享了一些實際的調試案例。

原文連結:https://dev.to/codenameone/cant-reproduce-a-bug-3l56

未經允許,禁止轉載!

作者 | Shai Almog 譯者 | 明明如月

責編 | 夏萌出品 | CSDN(ID:CSDNnews)

“在我的機器上可以運作”這一說法雖然聽起來有趣,但實際上反映了開發領域中一種普遍存在的态度,也就是隻有當使用者證明了 bug 的存在,我們才會對其給予關注。實際上,我們必須主動承擔責任,深入調查問題,不論它會引導我們走向何方。

遇到無法複現的 Bug 該怎麼辦?

雙管齊下解決 bug

解決 bug 需要采用雙管齊下的方法。首先,我們要設法在與使用者相同的環境中複現出可能隻在使用者電腦上才出現的問題。此外,我們還可能需要遠端調試或利用使用者計算機的日志,甚至可能請求他們替我們執行某些操作。

幾年前,我曾嘗試複現使用者報告的一個 bug ,但即便我采用了相同的 JVM 版本、作業系統、網絡連接配接等,仍未能找到該 bug。最終,使用者發來一段展示缺陷的視訊,我這才注意到了他在使用者界面中特殊的點選方式。這揭示了一點:出現 bug 的過程不僅與計算機硬體有關,有可能會涉及到使用者的具體操作。

遇到無法複現的 Bug 該怎麼辦?

使用者行為與溝通在解決 bug 中的作用

我們需要盡可能地還原使用者的操作行為,才能重制 bug 。通過視訊來記錄操作可以有助于我們實作這個目标。此外,了解複現環境中的細微差異及與能夠重制問題的人進行開放、明确溝通都是不可或缺的部分。

然而,溝通的過程可能會遇到障礙。有時候,報告問題的人可能是支援部門的員工,而我們卻是研發部門的。有時候,客戶的不滿情緒可能會導緻溝通中斷。是以,我認為将研發部門與支援部門整合是確定問題順利解決的關鍵所在。

遇到無法複現的 Bug 該怎麼辦?

解決 bug 的工具與方法

深入分析運作中應用程式的一些工具,例如 strace、dtrace 等,可以讓我們深入了解内部差異和異常行為。容器技術如 Docker 大大友善了統一環境的建立,進而消除了許多微小的差異。

我曾經調試過一個僅在客戶現場出現故障的系統,最終發現他們的網絡連接配接速度非常快,以至于與伺服器之間的通信時間甚至比本地代碼的執行時間還要短。我通過遠端登入到客戶的機器上并在那裡複現了問題,了解到有些問題的表現與地理位置有關。

網絡差異、資料源的不同和規模等因素可能會對環境産生重要影響。例如,在每秒收到 1,000 個請求的大型叢集中如何重制問題呢?可觀察性工具在這些情況的管理中可能極為有效。正如我在《針對故障建構 - 輕松進行生産調試的最佳實踐》中所讨論的那樣,在這種情況下,調試的重點不在于重制,而在于了解環境中的可觀察資訊。

理論上,我們不應遇到這些問題,因為測試應有适當的覆寫範圍。然而,現實總是複雜的。許多公司進行“長時間運作”的測試,一整夜持續運作,将系統壓力推至極限以便在現場問題出現前找出并發問題。故障通常由存儲不足造成(例如,日志将磁盤打滿),但這樣的問題通常很難複現。多次循環運作失敗的代碼常是有效的解決方案。還有一些值得使用的工具,例如我曾讨論過 “強制抛出異常”的 功能,它使我們能夠更靈活地模拟失敗情況。

遇到無法複現的 Bug 該怎麼辦?

日志記錄

日志記錄是許多應用程式的核心特性,它是我們調試此類邊緣情況的關鍵工具。我曾經寫過關于日志記錄的文章,讨論了它的價值。

日志記錄的工作需要像可觀察性一樣經過深入的思考和規劃。如果沒有适當的日志記錄,我們将無法有效地調試現有 bug 。合理地開始日志記錄并采用最佳實踐是一個好習慣。

遇到無法複現的 Bug 該怎麼辦?

并發

并發問題是軟體開發中極為棘手的 bug 之一。當遇到表現不一緻的問題時,首先需要确定涉及的線程,并確定每個線程都按預期執行操作。

在調試過程中,可以使用單線程斷點,進而隻暫停特定線程,以檢查特定方法中是否存在競态條件。建議使用跟蹤點代替斷點,因為阻塞可能會掩蓋或修改與并發有關的 bug 。

通過審查所有線程,并嘗試通過讓其他線程休眠來為每個線程提供“優勢”,我們可以偶然發現引發并發問題的特定條件。

嘗試使用自動化流程來重制問題非常有用。例如,當遇到這種情況時,可以建立一個循環來數百或數千次地運作測試用例,并通過日志記錄來尋找問題的根源。

值得注意的是,如果問題确實源自并發代碼中,額外的日志記錄可能會顯著改變結果。有一次,我将字元串清單存儲在記憶體中,然後在執行完成後一次性轉儲完整清單,以取代直接寫入日志。雖然使用記憶體進行記錄的調試方式并不理想,但這樣做可以避免記錄器或控制台輸出的開銷。特别是在沒有适當的過濾和管道的情況下,控制台輸出通常比記錄器更慢。

遇到無法複現的 Bug 該怎麼辦?

何時選擇“放棄”

盡管我們不主張輕易放棄,但有時必須承認某些問題在你的機器上可能始終無法重制。當遇到這種情況時,應該進入調試過程的下一個階段,對潛在原因進行假設并建立測試用例以驗證這些假設。

在難以解決 bug 的情況下,将日志和斷言內建到代碼中至關重要。這樣做可以確定當問題再次出現時,有更多的資訊可供分析和參考。

遇到無法複現的 Bug 該怎麼辦?

真實的案例

Codename One 就遇到過一個難以排查的問題,使用 App Engine 成本突然從幾美元飙升到幾百美元。這一突然的成本增加甚至有可能導緻我們一個月内破産。雖然我們竭盡全力進行了分析和修複,但我們還不能精确定位具體原因 ,隻能采用蠻力的方式解決問題。

最終,解決 bug 的過程是一個充滿堅持和不斷學習的挑戰。這不僅僅意味着把 bug 看作是開發過程中的一部分,同時也包含了了解如何從每次調試經驗中提高和成長。

遇到無法複現的 Bug 該怎麼辦?

總結

“ 在我的機器上可以運作”這一說法在軟體開發領域常常顯得沒有說服力。我們必須對 bug 負責,并盡可能準确地複現使用者的環境和行為。透明的溝通和研發支援部門的協同合作至關重要。

我們可以使用現代工具深入分析正在運作的應用程式,精确地定位問題所在。盡管容器技術(例如 Docker)簡化了統一環境的建立,但網絡、資料源和規模的差異仍可能對調試産生影響。

有時,即使付出了極大努力,某些 bug 也可能始終無法在我們的機器上重制。在這種情況下,我們需要根據潛在原因制定合理的假設,建立能驗證這些假設的測試用例,并在代碼中添加日志和斷言,以便未來的調試工作。

最後,調試不僅是一項堅持和适應的學習過程,更是對任何開發人員職業成長和技能提升的關鍵環節。

你是否曾經遇到過“在我的機器上可以運作”但是在使用者機器上有問題的情況?當面對無法複現的問題,你是怎麼解決的?歡迎在評論區分享你的經曆和解決方案。

參考連結

  1. 《針對故障建構 - 輕松進行生産調試的最佳實踐》:https://debugagent.com/building-for-failure-best-practices-for-easy-production-debugging
  2. 曾讨論過:https://debugagent.com/debugging-program-control-flow
  3. 寫過關于日志記錄的文章:https://debugagent.com/logging-best-practices-revisited
  4. Codename One:https://www.codenameone.com/

粉絲福利:

遇到無法複現的 Bug 該怎麼辦?