在程式開發的過程中,我們經常會遇到一項工作Debugging──有時中文譯為「除錯」,不過有時也譯為「偵錯」。Debugging的最終目的,當然是要把程式的臭蟲給除去,但是,想要除去臭蟲,得先偵察出臭蟲究竟在何處,而且,這個偵察的工作往往就是debugging的核心,找到臭蟲的位置之後,通常要提出對應解決方案就不難了。可偏偏難就難在找到惱人的臭蟲到底在那裡。

除錯的關鍵技巧
要想找出臭蟲究竟隱藏在系統的何處,一般來說,需要三方面的配合:(1)工具(2)技巧及經驗(3)克服心理障礙。

在除錯的時候,如果有好的工具,像是好的除錯器(debugger)、或是好的日誌程式庫(logging library)協助,的確可以提高除錯的工作效率。不過,光有好的工具還不夠,你還需要技巧,這才是貫穿除錯工作的靈魂主軸。

好的除錯技巧,往往是源自於豐富的除錯經驗。有著豐富經驗的除錯者,看了病癥,便能輕易推論出病因,而推論出正確的病因,接著便能有效的檢驗推論是否正確。而檢驗的工作,就必須倚賴好的工具來輔助。

除錯,基本上是一種不斷針對問題的真正導因提出假設,然後試著驗證假設的過程。在這個過程中,你會猜測可能的原因,然後試著從系統的行為及反應中,驗證自己的假設是否正確。足夠的經驗和技巧讓你建立準確的假設,雖不中亦不遠矣。好的工具,協助你更輕易檢驗所做的假設是否正確、進而驗證猜想。

例如,根據問題發生的癥狀,你猜想問題可能是在某個函式中某個變數的值計算錯誤,因此,利用相關的工具,觀察當問題發生時,在該函式中的變數值是否的確如所猜想的發生錯誤。倘若如此,那麼便驗證了假設,於是臭蟲也被找到了。

倘若並非如此,那麼代表假設錯誤,除錯者的思緒得退回一步,重新思考問題可能的所在,然後重新建立假設。

在這樣的模式底下,所建立的假設愈準確,所需要花費的時間愈少,除錯自然愈有效率。當然,能幫忙除錯者驗證假設的工具愈便利,驗證所花的時間愈少,也能幫助縮短除錯的時間。

為什麼有豐富經驗的人除錯特別快?這是因為他們所建立的假設更準確。經驗對於除錯真的十分重要,豐富的經驗通常意謂著遭遇過更多的錯誤,見多自然識廣。當腦中記載的錯誤原因愈多時,看到發生的錯誤狀況,自然很容易基於經驗推論出背後真正的原因。只有好的工具沒有用,因為老是猜錯原因,就得不斷地重新推論、甚至要進行更大範圍的檢測,除錯的效率當然就好不起來。

只要能建立正確的假設,即使沒有太好的工具輔助,除錯的速度一樣神速。而如何建立正確的假設,就的確有賴於足夠的經驗和卓越的技巧了。

不過,即使是有著足夠的經驗和卓越的技巧,有時也會被一些心理層面的因素所迷惑,因而影響了除錯的進行。這些心理層面的因素,會影響除錯者無法建立正確的假設,甚至始終無法逼近真正的臭蟲所在。而且,這些來自於心理層面的影響,往往是經驗愈多、技巧愈高的除錯者,所遭遇到的障礙愈大。怎麼說呢?

那些經驗愈多、技巧愈高的除錯者,通常對自己的推論都很有信心,而且有時候更容易受到一些先入為主的主觀判斷所影響,因而產生了偏見。而這些偏見則會阻擋了除錯者靠近真正的臭蟲所在。

沒想到的地方,有可能是問題的突破點
舉一個例子吧!

我們以前曾被一個問題困擾了很久,那是一個會從某網頁下載取得的ActiveX元件,為了免於受到IE瀏覽器安全性控管機制的影響,我們購買了憑證並且簽署了這個ActiveX元件。在Windows XP上運作起來沒有任何的問題,但是很遺憾的,在Windows Vista上卻始終無法於IE載入這個ActiveX元件。

接觸過Windows Vista的程式設計者都知道,Windows Vista的UAC(User Account Control)對整個作業系統的安全性有極為嚴格的管制。因此,當我們遭遇到這個問題時,首先一定是懷疑這是因為Windows Vista的UAC所造成的,畢竟這問題在Windows XP上並不存在,只有在Windows Vista上才會發生,而這中間最大的差別就是Windows Vista上的UAC。

因此,整個除錯的過程,便一直鎖定是因為安全性的因素而造成ActiveX無法載入。但是,無論如何進行安全性的調整或控制,就是無法成功的載入該ActiveX元件,這使得我們除錯的進度始終停留在原地,問題持續無法解決,日子也一天天的過去。除錯的重心還是擺在IE的安全性政策控制問題,從來沒有想過這個推論的方向完全是錯誤的。一群人像是拼命的往牛角尖裡鑽,卻始終看不到出口。

終於有一天,我們決定全部清空重來,放棄之前的假設。重新再做一個最單純的ActiveX元件,什麼都不做,看看在Vista上是否依舊無法正確地載入,結果竟然神奇地成功載入。這意謂著,我們原先的ActiveX元件做了一些特殊的事情,或者有著一些特殊的性質,使得Vista在載入它時,不允許它被載入。而這個特殊的事情或特殊的性質,在Windows XP上是被允許的。

我們首先猜想是因為元件相依性的關係,也許遇到問題的ActiveX所連結的DLL或其他COM元件被UAC阻擋了,所以一個元件一個元件地加到那個最單純的ActiveX中,結果皆能正確載入。

通常,愈是邏輯上難以思索的問題,其原因愈是簡單,也愈不是你想像的那樣。

經過反覆檢查,後來發現是包裝ActiveX的CAB檔中所記錄的Class ID值,和ActiveX本身的Class ID不相符。在XP上會以ActiveX的為主,向OS註冊,Vista卻是以CAB檔中的Class ID為主,向OS註冊,導致載入ActiveX時找不到註冊的元件,因而造成了載入失敗。

成見會影響你思考的方向,因此要保持開放的心態
如果不是因為之前遇到的狀況,像是Windows Vista上的UAC導致ActiveX元件載入失敗的經驗,我們在除錯的時候,也就不會一味地朝向這個方向去思考。

沒有類似經驗的除錯者,反而不會受到這件事影響,也就不會白白浪費了許多時間。

這就是除錯時的心理障礙之一,也就是既定的成見。因為已經先入為主的受過去的經驗影響,所以,除錯時一直鎖定這個方向,殊不知,這樣完全是背道而馳。

也有些時候,除錯者會一直相信,程式中的某某部份一定不會出錯,出錯的地方肯定在其他位置,因此,即使翻遍了程式中其他所有的部份,也不願意針對他所認為不會出錯的地方進行檢查。結果,始終無法找到臭蟲的所在。

這道理其實很簡單,如果你的邏輯推演沒有錯,照道理程式應該不會出錯,結果卻有臭蟲,那麼肯定是你的邏輯推演在某個環節出了差錯。

回歸到根本,重新假設
做一些基礎的假設,有助於縮小檢查的範圍,這是必要的。但是,當你發現在這些基礎的假設上,無論如何都找不到問題時,就必須適度考量,究竟要重置、放棄那一些假設。

當我們百思不得其解程式為什麼會出錯時,我們很有可能是被自己的一些既定成見所迷惑了。你可能有好的經驗、好的技巧、也有好的工具,可是,如果你不能時時刻刻提醒自己,在除錯的過程中可能存有既定成見,那麼這些既定的成見就有可能阻擋你靠近真正的答案。

專欄作者

熱門新聞

Advertisement