2021年6月2日

Debug 不再鬼打牆 ,追根究底的除錯技巧

工程師:「我剛剛測試明明可以啊!」

用戶:「可是網頁打不開啊???」

⋯⋯

工程師:「我昨天測了一整天,還是找不到問題耶,不然你電腦借我看一下。」

工程師:「欸,你是不是開飛航模式= =」

用戶:「真的耶!」

⋯⋯

不知道大家有沒有遇過這樣的情況,花了一整天的鬼打牆後,卻發現只是簡單的小問題。

其實這樣的情況並不少見,而且每次遇到了,除了浪費很多時間以外,也或多或少會影響情緒。

那有沒有辦法可以避免這樣的情況呢?其實有的。

這次我就想要來聊聊,要怎麼利用一些技巧來避免這樣的情況。

 

本篇是開發系列文章,更多開發相關文章請參考→這裡

 

Debug的流程

談技巧之前,我們首先來拆解debug的流程,

debug的流程是1. 釐清問題2. 尋找原因,然後3. 找解決的方法

看起來很像廢話對嗎?我也覺得。

但其實把debug分成這三個步驟來看很重要,對釐清問題有很大的幫助,

舉例來說,當使用者跟你說網頁有東西出不來時,你會怎麼做?

⋯⋯

(1. 釐清問題)

首先你會不耐煩地走過去他的位置,或是請他截圖給你看,看看到底發生什麼事了。

然後發現原來是會員的資料沒有正常的顯示。

(2. 尋找原因)

接著你會直覺地去看瀏覽器的開發者工具,看有沒有錯誤訊息,

或者看看API有沒有通,如果沒有,是怎樣的錯。

然後你看到API回了500 Internal Server Error,和一些額外的錯誤訊息。

(3. 找解決的方法)

一看到500,你知道是八成是後端工程師把API搞壞了,所以你把問題丟給後端工程師去解決。

然後繼續回到自己的座位上耍廢。

⋯⋯

以上這個簡單的debug案例,

不知道你有沒有想過,為什麼你會直覺地去看開發者工具?

為什麼你知道要看console、知道要看Network檢查API?

因為你知道網頁有些內容的渲染,需要透過JavaScript的協助,

如果JavaScript執行的過程中有錯誤,那就沒辦法正常地顯示畫面;

同時,你也知道,網頁的內容是透過API跟網頁伺服器取得資訊,

若是API沒有正常回傳資料,那畫面自然是沒有辦法正確顯示的。

所以重點來了,因為你知道「結果」是怎麼發生的

因為你知道要達成某種結果,需要透過某種流程,

因此你才有辦法做合理的推理,進而找到原因。

 

很多人會卡關的原因,正是因為沒有發現自己跳過了第二個步驟,

或是沒有完成第二個步驟,就一知半解地往下走了。

然後花一大堆的時間嘗試各種可能的解法,但根本也不知道這些解法到底在解決什麼問題。

像這種在沒有釐清原因之前,就開始嘗試解法的行為,

其實就像病急亂投醫,並不是對症下藥,通常會嘗試了半天都沒有效,只能一直卡關。

 

我們再次回到前面提到的Debug三步驟,1. 釐清問題2. 尋找原因,然後3. 找解決的方法

我認為還是應該一步一步來,如果還沒有找到原因,就先不要往下走,

但是如果真的找不到原因怎麼辦?這其實就是本篇的主題,

本篇要想要討論的debug技巧,其實就是為了避免你在第二步卡關,也就是「找原因的技巧」。

Debug 的技巧

找原因的技巧」就是仔細地思考所有環節,然後一個一個環節確認有沒有問題

那問題來了,要怎樣才算是思考所有的環節?

那我們先回到前面「網頁有東西出不來耶」的例子,

一般來說,網頁的資料都會正常呈現,所以網頁有東西出不來,一定就是某個環節出錯了。

所以我們就要來想想,到底是哪個環節出問題了,

首先我們必須要來回想一下「網頁如何呈現資料」的流程,

我們先不要搞得太複雜,先把視角拉遠一點來看的話,那大致上的流程就是:

1. [瀏覽器]發送request到伺服器 →

2. [伺服器]把request轉到對應的後端程式 →

3. [後端程式]處理完成後回傳response →

4. [伺服器]把response回傳給瀏覽器 →

5. [瀏覽器]進行畫面的渲染

所以當你聽到「網頁有東西出不來耶」的問題,腦中就應該要浮現這樣的大流程,

接著把這個流程當作checklist,按照順序一項一項去確認。

直到你發現某個環節斷掉了,

舉例來說,你確認1.[瀏覽器]發送request到伺服器這個步驟正常,你就繼續往下看,

2.[伺服器]把request轉到對應的後端程式也正常,繼續往下,

然後到了3.[後端程式]處理完成後回傳response,你發現這個步驟並沒有正常的回傳response,

那你就知道問題出在這裡了,

接著那我們把這個環節繼續往下拆解,

3. [後端程式]處理完成後回傳response→
	3-1. 解析Request →
	3-2. 根據Request內包含的資訊,去database取得資料 →
	3-3. 根據從database回傳的資料,整理成約定好的資料格式 →
	3-4. 將資料放入Response中交給伺服器

一樣,一個一個去檢查,看問題到底斷在哪裡。

使用這種top-down的方法,可以讓你不遺漏掉所有環節,精準的鎖定問題發生的地方。

也不會每次發生問題的時候,都只是瞎猜。

當然對有經驗的人來說,很多問題都遇過,可以直接鎖定目標,

但再怎麼有經驗的人,都有可能遇到未知的問題,

面對未知的問題,只能用這樣的方法,不斷地縮小範圍。

我要怎麼知道完整的環節?

要能夠把環節完整的想完,就是知識層面的問題了,

具備充足的知識,自然可以把環節拆的越細,也可以讓腦中的流程越清晰。

但是,每個人的腦容量都有限,所以就現實層面來講,不可能知道一切。

好消息是,在團隊中通常是分工合作,前後端工程師各司其職,

所以每個人可以不用懂那麼多,只要抓到大流程就好,再從大流程中找到自己的守備範圍就好,

一樣以前面的大流程為例,

1. [瀏覽器]發送request到伺服器 →

-----

2. [伺服器]把request轉到對應的後端程式 →

3. [後端程式]處理完成後回傳response →

4. [伺服器]把response回傳給瀏覽器 →

------

5. [瀏覽器]進行畫面的渲染

前端工程師要檢查的項目就是1跟5,後端工程師要檢查的項目就是2至4,

只要確認1、5都沒問題,前端工程師其實就可以直接放心的把問題丟給後端工程師去解決了XD(通常啦),

就像前面的例子,前端工程師發現是500 Error,就把問題丟給了後端工程師處理了。

所以,前端工程師可以專注在瀏覽器這邊的流程,而後端工程師可以專注在伺服器端的流程。

也就是說,大流程一定要知道是誰,至於細流程則依據每個人不同的專門領域去補完即可。

結論

回歸主題,追根究底的除錯技巧 ,就是,先抓住大方向,然後由大方向不斷地往下拆分,直到不行為止,

在拆分的過程中,仔細檢查每個項目,一個一個排除,直到找到問題點。

 

雖然大部分的問題,可能無腦把錯誤訊息丟到Google,就有解答了

但是隨著處理的問題越來越複雜,解答也會越來越難google的到,

自己必須養成一套解決問題的邏輯跟流程,不用一定是這篇提到的,

這樣才有辦法靠自己把問題解掉。

 

最後,雖然大家都不喜歡bug,

但往好處想,要是沒有那麼多bug要de的話,工程師大概有一半要失業了吧!

 

本篇是開發系列文章,更多開發相關文章請參考這裡