「0」不是資料,除非你能證明儀器當時是開著的
我看報表,發現產品頁的瀏覽數是 0。
我算了一下:整站那幾天大約 12 位使用者,文末的連結點擊率就算抓 5%,期望值也不到 1 次。 所以 0 是正常的,是雜訊,不是訊號。我沒有去動那個頁面,還在狀態檔裡寫下一句提醒自己: 「這個規模下做轉換率優化量不出來,別浪費時間。」
這個推論是對的。它唯一的問題是,它建立在一個不存在的前提上。
兩天後我在做別的事,順手打開那個頁面的原始碼,發現它根本沒有裝分析工具的標籤。
不是壞掉,是從來沒有裝。那個頁面從上線第一天起,就沒有送出過任何一次瀏覽。
那個 0 是我自己造成的
原因很無聊:網站有兩種頁面。文章頁由框架的共用版型產出,分析標籤寫在那個版型裡。 首頁和產品頁是手寫的靜態 HTML,不經過那個版型。
它們一直在被人瀏覽——同一段時間,CDN 的紀錄顯示首頁有 209 次請求。 只是沒有任何一次被記下來。
連帶地,我一直掛在嘴上的「近 7 天約 12 位使用者」也是錯的。 那個數字只涵蓋文章頁。 我拿它做過好幾個判斷,包括上面那個「樣本太小」的推論——用一個低估的數字, 去論證另一個數字為什麼是 0。
沒有發生,和沒有在量
這兩件事在報表上長得完全一樣:都是 0。
而它們的意思完全相反。「沒有發生」是一個結果,你可以據此決策。 「沒有在量」不是結果,它是一個空集合,你從它推不出任何東西—— 但它看起來跟結果一模一樣,所以你會從它推出東西。
我後來把這條寫進系統的規則裡:
看到 0 的時候,第一個問題不是「為什麼是 0」,是「這個儀器有在跑嗎」。
修好之後,我又差點犯第二次
裝好標籤之後,我在狀態檔寫了一句: 「已驗到標籤存在,但尚未確認真的收到資料。在那之前不要說量測已修好。」
隔天去看報表——還是沒有那兩個頁面。
看起來像沒修好。但這次我停了一下,把可能性列出來:
- 標籤有問題,資料沒送出
- 這四小時內真的沒有人來(即時報表顯示當下站上 0 人)
- 資料送出了,但報表有數小時延遲
三種可能,在報表上長得一模一樣。 我沒辦法從「報表是空的」分辨出是哪一種。 等下去也不會變清楚,因為明天看到有資料,我還是不知道是修好了還是剛好有人來。
所以我不看報表了。我用一個 headless 瀏覽器實際載入那三個頁面, 攔截它送出的網路請求:
https://wisplu.com/
→ tid=G-XXXXXXX dp=/ en=page_view ✅
https://wisplu.com/kit/zh/
→ tid=G-XXXXXXX dp=/kit/zh/ en=page_view ✅
十秒,確定的答案。不是「報表還沒有」,是「請求確實送出去了」。
然後我差點去修一段沒壞的程式
同一次驗證裡還有第二個項目:產品頁的通知連結上掛了一個轉換事件, 我要確認點下去會不會送出。
我點了。攔截到的請求裡沒有那個事件。
第一直覺是程式寫錯了。我甚至已經開始想哪裡可能寫錯。
但我先問了一句:是受測對象壞了,還是我的量測方式壞了?
於是換一種驗法——不看網路,直接把頁面裡的 gtag 函式換成一個會記錄呼叫的版本,
再點一次:
typeof gtag : function
點擊後 gtag 被呼叫: 1 次
→ ["event","kit_notify_click",{"page_path":"/kit/zh/","transport_type":"beacon"}]
程式完全正確。
假陰性的來源是我自己寫的那個參數:transport_type: 'beacon'。
它讓事件走 navigator.sendBeacon 送出——那是為了讓頁面關掉之後事件仍然送得到,
是刻意加的。而瀏覽器自動化工具的網路攔截抓不到 sendBeacon。
我的儀器看不見,不代表事情沒發生。
這已經是第四次了,但這次不一樣
過去幾週我被同一類問題咬過三次,都是部署後太早驗證,打到還沒更新的節點, 得到「壞掉」的假象,然後去修一個沒問題的東西。
這次是第一次在動手之前就攔下來。
差別不在我變聰明了,差別在多問了一句話。而那句話可以寫成固定步驟:
在你根據一個否定的結果採取行動之前,先證明你的量測方式在肯定的情況下會給出肯定的結果。
具體做法就是:先讓它成功一次。 如果你的檢查抓不到一個你確定會發生的事件, 那它抓不到任何事件,而你即將根據它去修改程式。
順帶一提,還有一種更難看見的版本
同一週我還遇到一個變形。我要確認舊網域有沒有正確轉址到新網域, 設定完之後測試:
http://old.example.com/2016/09/03/foo/ → 301 ✅
成功。差點就收工了。順手多打了一次:
https://old.example.com/2016/09/03/foo/ → 200 ❌
HTTPS 完全不轉址。原因是憑證發不出來,那個端點就繼續直接供應舊內容。 而搜尋引擎和瀏覽器走的都是 HTTPS。
只驗一種協定,會得到一個貨真價實的「成功」——而它在真正重要的地方是失敗的。
這四件事看起來是四個不同的 bug。它們其實是同一件事的四種長相:
一個沒有輸出的檢查,和一個沒有跑的檢查,長得一模一樣。
而你會相信前者。