消滅bug秘籍 如何處理大型軟件中的錯誤和異常
譯文【51CTO.com快譯】 "我在測試中沒有發現任何bug,這就意味著沒有bug……對嗎?"千萬不要這樣認為。由于大型軟件的復雜程度很高,不管你做了多少測試,都不可能達到零bug的程度。因為你并不能揣測出用戶的所有使用方式,因此,了解應用程序中錯誤和異常之間的差異,是非常重要的。為此,你要選擇正確的方式來處理這些錯誤和異常,以積極的態度來確保應用的正常運行,對你的開發團隊和最終用戶負責。
測試的本身亦是個問題
即便你的測試是最徹底的,你依然只是在測試特定的情況,而且自己的偏好也在測試過程中發揮著作用,使得測試本身的客觀性有失偏頗。
想象一下,數以千記的用戶同時使用你的應用程序,同時也是以數以千計的方式來進行操作,這當中一定會遇到你沒有測試過的狀況。
如何正確處理應用程序中的錯誤
簡單的說,bug會導致錯誤和異常,這些錯誤和異常在不同的條件下有不同的意義,這要看你更看中哪一方面的問題。最主要的問題當然是如何更好的處理這些錯誤和異常,這樣才不會帶來消極的后果。
首先,讓我們來看一些定義,以及為什么這些差異很重要。
錯誤和例外有什么區別?
一些編程語言對錯誤和異常有自己的定義,但我想定義這種差異。
先說錯誤。編程錯誤,通常無法繼續和恢復,需要程序員進入程序并且修改代碼來修復。有時候錯誤會轉化為異常,以便它們可以在代碼中被處理。錯誤可以通過簡單的檢查來避免,如果一些簡單的檢查不夠,錯誤也可以轉換為異常來處理,這樣一來,應用程序就可以解決問題和保持起碼的運行。
再說異常。當異常發生時,要考慮到不同編程語言的特性。異常可以被忽略或者捕獲,所以代碼可以恢復和處理這些情況,而不會令應用程序進入"錯誤"的狀態。由于異常可以被忽略,所以應用程序在這種時候依然可以保持運行,未處理異常(這是錯誤的)也可以登錄,所以,是否處理這些潛在異常就要看開發者了。來看看一些事例。
事例1:一個用戶錯誤
當用戶輸入了錯誤的數據,可能暫時不需要太去處理,但這仍然可能導致程序出現錯誤和不可恢復的狀態。毫無疑問,這時代碼應該進行簡單的檢查來阻止錯誤狀態的發生,你應該進行前端和后端的驗證,拋出一個異常作為"***的防御"。
事例2:文件打不開/下載異常
這是一種特殊情況,不至于破壞你的整個應用程序。你的應用程序應該能夠處理這個問題。造成下載失敗的原因很多,所以在程序設定的過程中,要做充足的預料和準備。Ok,以上就是我定義的錯誤與異常的區別了,這是易于遵循的過程,幫助你更好的處理錯誤。
重視每一個異常
"如果我捕獲了每個異常,我的代碼就是零差錯了,對嗎?"
就像我在前文中提到的,不是所有的錯誤都會導致異常。這個結論的主要問題是,你不知道什么是錯的。你的代碼可能有一些問題,通過捕捉異常而不做任何事情,您將丟失這些信息。不要只是查找異常,然后就一切如常。查找異常的目的是處理它們,并創造更適合運行的環境。
如何對應用程序進行代碼自行恢復
拋出和捕獲異常是讓應用程序自行恢復,并防止它運行到錯誤狀態的一個好方法。如果你知道哪種異常可能被拋出,***明確被捕獲的各種異常都會導致哪種應用程序的停滯。(我們談了一點關于軟件構架錯誤報告的問題)
說到具體的異常類型,你可以向用戶搜集反饋信息,這樣你就知道具體導致程序出錯的原因,就可以更好的處理這些情況了。
為什么說指定捕獲的異常類型很重要
隨著程序的運行,某些異常會損壞數據或以非正常的的方式運行。這會導致應用程序出錯。如果你確切知道發生了哪些異常,您應該知道要遵循哪些步驟來恢復。或者,如果你無法恢復,你應該知道如何很好的處理這個情況。
那么,這能夠恢復嗎?很多時候,異常有足夠的信息來知道出錯了,在被捕獲的異常中,有時可以從錯誤狀態中恢復。你可以通過修復一些數據,數據重新獲取,甚至要求用戶再試一次來實現這一點。
你可以捕捉異常,但有時程序仍然無法運行,因為你依賴的數據已經以一種不可恢復的形式損壞,或者這些異常需要以不同的方式來解決。
比如,一個超出范圍的數組異常,程序如何從中恢復?這是一個將錯誤轉化為異常的示例。你的應用程序希望數據以某種方式存在,但這并沒有發生。雖然恢復并不總是可能的,但現在有可能不進入錯誤狀態和流暢的處理情況。如果在登錄時出現異常,開發人員可以通過添加一些簡單的檢測來修復異常,在數組被訪問或者改變它被訪問之前。
如何處理未處理的異常
有些異常是你不希望出現的,比如代碼中的錯誤。你可以登錄未被代碼捕獲的那些異常,許多語言都提供這種處理異常的方法。(例如.NET的application_error和javascripts全球的on_errorhandler)。任何未被處理的異常都會顯示為錯誤,而錯誤是無法依靠代碼自行修復的。所以,記錄下這些錯誤,能便于你能找出其中的原因。這樣一來,錯誤就不會被當做異常被忽略了。一旦這些異常出現,你就可以很快的解決掉它們。
錯誤日志
錯誤日志可以幫助我們捕獲錯誤。有了錯誤日志,你可以查看這些記錄的錯誤和異常,這也是調試的關鍵,同時你還可以優先考慮什么時間修復哪些錯誤。你不必太依賴用戶發來的截圖和描述,更何況不是所有用戶都會有興趣來報錯。錯誤日志可以讓你的團隊保持積極的行動力,一旦錯誤被發現,他們能夠及時聯系到用戶,使其免受侵害。用戶也會樂意接到你們的提醒,這還可以提升你的客戶關系。當然,在用戶使用到之前解決這些問題才是最關鍵的。
舉例來說,一個導致計費有誤的代碼錯誤比不能顯示特定詳細頁面這樣的錯誤嚴重得多,即使不能顯示詳細頁面這樣的錯誤更容易出現。當你的應用程序出現異常時,你想要想辦法去修復它,但是僅有1%的用戶會主動報錯,還有好多你不知道的錯誤存在潛在的隱患。
一些解決方案
寫些代碼來保存異常和堆疊追蹤,把它們存在文件里或者通過電子郵件發送,可以提示你這些錯誤的發生,這是一種可行的辦法。舉例來說,一個用戶在運行中遇到許多異常,一百個用戶可能遇到一些不太頻繁出現的錯誤,哪一個比較重要呢?在不知道具體錯誤情況的條件下,影響更多用戶的錯誤更為重要。
使用異常中的堆疊追蹤可以幫助你找出錯誤所在的位置,并且你應該能夠復制或讀取代碼以了解出錯的原因。有時候這還不夠,問題還需要進一步的追蹤。如果發生這種情況,在登錄之前向異常添加更多信息,包括上下文特定的詳細信息(如帳戶ID或特定對象狀態),這些信息將允許你在本地復制錯誤。現在你應該能發現所有的錯誤和異常,并且記錄未處理的了吧。
根據你應用程序的大小,錯誤提示的噪音也是個問題。你可以通過郵件過濾做些聰明的事情,比如幫助你把錯誤分組,這也只是部分的解決辦法。幾年前我這樣做過,但很快意識到出現的問題太多,而這只是部分的解決辦法。
問題在于,我依然不知道哪些錯誤對用戶的影響***。我專注于拋出最多的錯誤而不是用戶體驗中最麻煩的錯誤。正因如此,我從來沒有真正摸清過哪些錯誤更為嚴重。我沒有可視化的表示正在發生什么,但必須運行手動查詢來計算出來,這是相當耗時的。
大型軟件中的錯誤和異常非常常見,正確的處理錯誤將作為評判一個團隊的依據,也是一個突破錯誤和異常,創造美好運行環境的過程。好的應用程序包含在可能時從異常中恢復的代碼。處理和記錄異常對您的軟件的健康非常重要!
劉妮娜譯
原文鏈接:https://dzone.com/articles/how-to-handle-errors-and-exceptions-in-large-scale
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】