用結構化思維解一切BUG(3):實際案例

知明所以發表於2023-11-02

背景

本文是系列文章《用結構化思維解一切BUG》的第 3 篇,也是最高潮篇!本系列文章主要介紹一種「無需掌握技術細節,只需結構化思維和常識即可解一切BUG的方法」。

在前序文章《用結構化思維解一切BUG(1):核心思路》中,我介紹了本方法的核心思路,即,基於結構化的「假設樹」,透過重複多次執行「做試驗→造現象→縮範圍」動作序列,逐級下鑽,縮小問題範圍,直到找到問題根因

在前序文章《用結構化思維解一切BUG(2):實踐原則》中,我介紹了本方法的實踐原則,「程式斷案三字經」,總結為 5 條 30 個字:

  1. 先診斷,後開藥。
  2. 信機器,慎信人。
  3. 做試驗,縮範圍。
  4. 找不同,看變化。
  5. 先脆弱,後穩定。

本文我將帶大家進入真實BUG場景,在場景中介紹「假設樹」如何生長、如何執行「做試驗→造現象→縮範圍」小閉環、如何運用實踐原則。同時,您也從中感受到該方法的強大!

_提醒:_本文中,假設樹的生長圖和試驗記錄表格是重點,建議點選圖片全屏預覽,如用手機建議橫屏觀看。

案例背景

這個客戶是創立了 20 年的國際貿易和海外工業製造公司,目前在籌備上市。為應對上市要求,需要搭建自己的質量管理系統。

這個應用由一個「導航應用」和多個「子應用」構成。導航應用中有多個子應用的連結。當使用者登入導航應用後,點選任何一個子應用的連結,即可快速進入這些子應用,無需再次登入。請記住這裡的「導航應用」和「子應用」,後文會多次提到。

有一天,客戶反饋,部分使用者有「跳轉到子應用後無法自動登入」的問題。

顯然,這僅有的資訊,我無法做出任何有效判斷。

大多數業務使用者,甚至是程式設計師,在反饋問題時都缺乏必要細節。作為問題解決者,我的第一個任務就是,問對問題,得到我想要的資訊。我一般會用 5W2H 的方法來問問題(請注意後續問題的中括號標註),以全面瞭解資訊。

提醒:如果您是程式設計師,強烈建議刻意培養自己「提出一個好技術問題」的能力,因為好的問題才有更大機率被快速回答。具體請參考我的另一篇文章《如何提出一個好的技術問題?》。

明確問題

首先,我需要明確問題[What]。即,問 3 個問題:

  1. 希望的現象是什麼?[To-Be]
  2. 實際的現象是什麼?[As-Is]
  3. 哪個點不滿足希望?[Gap]

在本場景中,三個問題的答案為:

  1. 希望使用者可以免登入地進入子應用。
  2. 實際現象是,用點選子應用連結後,應用自動在新標籤頁開啟一個登入頁面。且這個登入介面就算輸入正確密碼和賬號,也無法登入。
  3. 無法正常訪問子應用。

縮小範圍

根據上一篇文章的「假設樹」方法,我們第一層需判斷此問題是前端問題還是後端問題。

為了方便引用,我們把發生 BUG 和不發生 BUG 的使用者分為兩組,發生 BUG 的使用者成為 N (Negative)組,未發生 BUG 的使用者成為 P (Positive)組。

於是,我問了如下問題:

這個診斷過程,我踐行了如下原則:

  1. 「先診斷,後開藥」。在沒有弄清楚問題根因之前,不做任何正式的修改建議。
  2. 「找不同,看變化」。儘量從現有現象中,找到大家的不同點,看有什麼變化,變化就是線索。

有了這些資訊,我靠直覺猜測,大機率是前端問題,且是瀏覽器問題。因為,從後端來看,我很難想到這兩組使用者在程式碼和資料上有顯著的不同特徵。具體來說:

  1. 後端程式碼,兩組使用者肯定是一樣的。
  2. 後端資料,發生了 BUG 的使用者沒有任何明顯相似點,發生 BUG 的使用者與沒發生 BUG 的使用者也沒有任何明顯不同點。

直覺很有價值,可以更快找到正確路徑。但直覺未經過嚴格證明,不能把它直接當做結論,還需要做試驗證實。

另外,不用擔心自己直覺不準,它並不會影響最終結果,因為它只是猜測。只要你按照「假設樹」的路徑逐個遍歷,總會到達終點,只是要多做幾次試驗罷了。

???回顧假設樹-Step1???

本階段「假設樹」沒有任何確定性的進展,只能依靠直覺先做假設。具體進展如下(本文所有假設樹示意圖中,藍色字型表示是假設,紅色字型表示是已證實的結論):

設計試驗

為了驗證上述的猜想,我陸續做了如下試驗:

在這個過程中,我踐行了如下原則:

  1. 「做試驗,縮範圍」。透過不同的對比實驗,來驗證自己的猜想,縮小問題範圍。

  2. 「找不同,看變化」。在 1 和 2 兩步,我儘量控制單一變數,排除掉其他因素干擾,來看有什麼變化。

  3. 「信機器,慎信人」。我相信,BUG 沒有真隨機,任何 BUG 都有其底層規律,一定有某個地方的不同導致了 BUG。並且,我得到初步結論後,再次與所有觀測到的現象做意義印證,看是否能解釋觀測到的全部現象。

回顧這組試驗,「假設樹」前進了兩步:

???回顧假設樹-Step2???

Step2 中,我們雖然判斷大機率是瀏覽器原因,但不能 100% 確定,因為沒有排除後端原因。所以,我們只能沿著假設的方向進一步探索。如下圖所示:

???回顧假設樹-Step3???

Step3 中,我們確定了此問題是 Chrome 瀏覽器版本所致,則整條路徑的所有原因都可以確認了。即,可以確認是前端原因,且是瀏覽器原因。同時,可以排除後端原因。如下圖所示:

初步結論

從上述一系列實驗中,我們得到初步結論:本 BUG 跟瀏覽器版本密切相關

接下來,我給了客戶兩個修改建議,並囑咐,如果還未找到根因再來找我。

  1. 查閱 Chrome 的近期更新日誌,試圖從中找到跟本 BUG 相關的更新條目。
  2. 仔細閱讀跟自動登入相關的「前端」程式碼(只有大約 30 行),檢查哪些程式碼最有可能伴隨瀏覽器版本升級而發生變化。

請注意,這兩個建議,都是低成本修改建議,主要目的是做試驗,參考「先診斷,後開藥」的原則。

第二次設計試驗

第二天,反饋來了:

  1. Chrome 每個版本的更新日誌內容太多了,有上千條,一條條去查詢不現實。(我錯誤地估計了 Chrome 的更新量)
  2. 看了登入相關的前端程式碼,嘗試了所有可能伴隨瀏覽器升級而發生不一樣行為的地方,結果都一樣。

這說明,我們雖然縮小範圍到了那 30 行程式碼的範圍,但還是達不到讓執行者能修改的地步,還需要進一步縮小範圍,找到根因。

於是,我讓客戶講解這 30 行程式碼做了什麼。透過講解,我瞭解到這 30 行程式碼主要是傳送非同步請求完成子應用的自動登入,然後跳轉到子應用的 home 頁面。

根據 Web 應用的常識,我知道,登入不成功,要麼是登入請求執行失敗,要麼是 Cookie 裡 SessionID 未寫入成功。為了驗證上述猜想,我又設計瞭如下試驗:

基本確定完根因後,我又拿這個根因,跟前面所有的現象作比對,發現全部能解釋。

???回顧假設樹-Step4???

回顧這組試驗,「假設樹」繼續生長,最終找到根因是連結未加密。如下圖所示:

最終結論

最終發現根因是:

  1. Chrome 新版本寫入 Cookie 的規則發生變化,加密請求建立的 cookie 不能被非加密請求改寫。
  2. 導航應用與子應用的 schema 不一致,一個是 http,一個是 https。

最終的修改建議是:

為每個子應用配置加密訪問證書,並更改環境配置中子應用的域名的 schema 為 https。

客戶更改完後,BUG 完美修復!

本案例總結

這個案例,我們精準還原瞭解決一個 BUG 的完整過程。過程中,我們不停地調整「假設樹」,不停地「做實驗→造現象→縮範圍」,最終到達終點,找到根因。

除了前述 5 個原則以外,我還想說一點精神層面的事。任何一個 BUG 的解決過程都是崎嶇坎坷的,特別是當你面對一組現象,完全找不到任何聯絡的時候,任何人都會心情低落。但越是這樣,越要沉著冷靜。不要想一步登天,直接找到根因;而是要從「假設樹」根部逐步往下鑽,一層一層抽絲剝繭。每一層下鑽,每一次試驗,你都會得到新反饋,用來排除其它假設。這些反饋是支撐你繼續往下鑽的動力。所謂「慢慢來,比較快」,就是這個意思。

全系列文章總結

至此,《用結構化思維解一切BUG》的方法的核心思想、實踐原則和實踐案例都已經講完。後續,我會不定期更新更多實際案例,以幫助您加深理解。

如果您完整讀完本系列的三篇文章(《用結構化思維解一切BUG(1):核心思路》、《用結構化思維解一切BUG(2):實踐原則》和本文),並基本理解所有段落,那麼恭喜您,您的解 BUG 功力已經顯著提高!如果您還願意在實際工作中踐行那麼幾次,您一定會成為頂級解 BUG 高手!

最後,重溫下本系列文章最開頭的那句話:

面對萬“卷”世界,有人選擇拼命學習新技術,解決眼前的、點狀問題;有人提升思維層級,解決未來的、面狀問題。您選擇什麼?

關於作者

您好,朋友。我現就職於西門子工業軟體,擔任高階諮詢顧問。成功領導 10 多個世界 500 強企業的數字化轉型專案,跨越政府、零售、金融、汽車製造、生物醫藥等多個行業,創造巨大商業價值。

如有任何與「數字化轉型」有關的問題,歡迎用以下方式與我交流:

  1. 新增我的個人微信「zjh1943」。新增時請註明姓名、行業、交流的問題。
  2. 關注我的微信公眾號「知明所以」。
  3. 關注我的知乎專欄:https://www.zhihu.com/people/zhu-jin-heng

相關文章