三週前,我為一位經營瑜伽工作室的朋友建了一個預約小工具——一段對話、一份我因為忙著別的事而很快就核准的計畫、一次執行,然後是一張帶著綠色勾勾的版本卡片,我瞄了一眼就繼續往下做別的事。週二她傳訊息問我,能不能讓另一間工作室的網站也指向同一個建構。在回答她之前,我回頭去看三週前「已驗證」到底代表什麼,那也是我第一次真正去讀這些紀錄,而不是單純相信那個勾勾。
它就在版本卡片上,緊鄰預覽和程式碼操作——就是你會去重新部署或回復版本的同一個地方。我注意到的第一件事:它是限定在那一個版本,而不是整個對話。我為了追一個壞掉的日期選擇器反覆修改了五次,原本還半期待這份紀錄會告訴我整段來回過程的故事。但它不會。版本 4 的紀錄只描述版本 4。它不記得版本 2 上線時有個登入表單會悄悄失敗,也不會告訴我版本 5 悄悄修好了版本 3 弄壞的東西。每一份紀錄都是一張快照,不是差異比對,也不是更新日誌——如果我想知道每次發布之間的變化歷史,那是完全不同的另一個檢視畫面。這一份只回答「這一個版本沒問題嗎」。
往下滑,這份紀錄分成六列:
| 層級 | 通過代表什麼 |
|---|---|
| 功能性 / 瀏覽器內測試 | 建構在真實瀏覽器中運行過;互動已被實際操作測試過(遊戲會被實際玩過) |
| 程式碼審查 | 一位唯讀審查者找不到能以檔案和行為佐證的缺陷 |
| 安全性 | 沒有出現注入攻擊面、外洩的機密資訊或不安全的模式 |
| 連結與 SEO | 沒有失效連結;metadata、robots 與 sitemap 都正常 |
| 無障礙 | 自動化的 axe 檢測沒有發現違規項目 |
| 符合性 | 建構包含了核准計畫中承諾的內容 |
六項全部綠燈,而我的第一反應正是我猜大多數人都會有的錯誤反應:安全性通過,所以它是安全的;無障礙通過,所以它是無障礙的。這兩種解讀都經不起這些檢查實際在做什麼的檢驗。安全性檢查代表的是表面層級的問題——把字串直接拼接進查詢語句、API 金鑰暴露在前端程式碼裡、對使用者輸入的內容執行 eval——這些都沒有出現。這不等於經過滲透測試人員一整天的檢驗。我朋友的工作室不透過這個小工具收款,只收姓名和時段,所以這個底線對她來說已經夠了。如果那是結帳流程,我會希望有更多保障。
無障礙這一項是真正讓我停下來去查資料的,因為「axe 檢測通過」聽起來像是全面檢查,但其實不是。Axe——底層運行的自動化引擎——大約能穩定抓到三分之一到一半的 WCAG 成功標準:缺少的替代文字、糟糕的對比度、沒有標籤的表單欄位、明顯的 ARIA 誤用。但它無法告訴你我要求的自訂日期選擇器下拉選單,對螢幕報讀軟體使用者來說是否好用;無法告訴你在多步驟預約流程中用 Tab 鍵切換焦點,是否會落在合理的位置;也無法告訴你我用綠色和黃色標示的「已確認」與「待確認」狀態,對紅綠色盲的人來說是不是個問題。這些需要有人在關閉輔助工具的情況下,親自走一遍建構流程,就像身心障礙使用者實際依賴的那樣。Axe 是真實的訊號,不是沒有意義——它是無障礙檢查裡的拼字檢查器層級,而不是編輯的層級。
符合性是我差點跳過的一項,因為它聽起來很官僚——「包含計畫承諾的內容」——直到我想起我核准的那份計畫是在我分心的時候寫的,而我真的不記得自己有沒有要求電子郵件確認,還是只要簡訊。這一層檢查的是建構是否符合計畫,而不是符合我實際的意圖,而它通過了,這告訴我建構符合了我當初同意的內容,但不一定符合我原本的意思。我聽過有些建構功能完善又安全,卻仍然沒通過這一層,因為在時間壓力下有個功能被悄悄拿掉了。這一層的作用,是讓建構對產生它的那段對話保持誠實,即使那段對話本身有點鬆散。
六列下方是一份更長的清單,分成兩個類別,而這是我花最多時間看的地方。「必須修正」項目並不是建構目前有問題的地方——它們是收據。有一行寫著,審查層發現一個案例:某個日期字串被直接拼接進查詢語句,而在這個版本被標記為完成之前,它就已經被修補好了。我看到的不是一個還在流血的傷口,而是一道疤痕。這個區別很重要,因為如果你把「必須修正」項目讀成即時警告,你會花時間去擔心一個其實已經解決的問題。
建議清單比較長,而且大多是些如果我在審查同事的程式碼、又不想擋下合併時,自己也會說的話:「考慮把重複的時段渲染區塊抽成共用元件」、「這個端點沒有速率限制,對內部預約工具來說沒關係,但如果要公開就值得重新考慮」。清單上沒有一項是缺陷。這些是驗證者只憑計畫和程式碼所做出的判斷,而對一間瑜伽工作室的內部排程系統來說,每一個判斷都落在合理的一側。如果我朋友的工作室是一家連鎖店,這個小工具要嵌在五十個分店頁面上,我會想對速率限制那一項提出異議——這個分類取決於驗證者只能猜測的情境,而當你覺得某個猜測不對時,正確的做法是在對話中說出來,而不是假設那個標籤是最終定論。
讓我印象深刻的是,看著一份相當長的建議清單旁邊是乾淨的必須修正欄位,我差點把清單的長度當成壞消息。但其實不是。一個沒有任何建議註記的建構,要不是只經過狹窄的檢驗,就是運氣好;而一個有一堆「考慮」項目、卻沒有任何未解決的必須修正項目的建構,才是真正被仔細檢視過的建構。建議欄位本該是把真正的問題都清掉之後剩下來的東西。
另一件我逼自己做的事,因為這份紀錄已經是三週前的了,就是在完全信任這些結論之前,先確認到底哪些層級真的有執行過。這裡六項都齊全,但我後來看過一份建構,裡面的無障礙項目根本沒出現在清單上,而不是標示為通過或失敗——這和被略過為不重要不一樣,而是代表那個檢查對那種特定的網站類型或旗標設定沒有執行,而如果你只是快速瀏覽,把缺席解讀為默默通過,正是這種格式最容易誘使人犯的錯誤。
這一切都沒有告訴我瑜伽工作室的預約流程實際上轉換率如何,人們是不是在選時段那一步就放棄了,或者做一個自訂小工具而不是直接連到 Calendly 這個想法本身,一開始是不是就是對的選擇。驗證證明的是建構如它承諾的那樣運作,而不是那個承諾本身是不是該做的正確承諾——這是兩個不同的問題,我見過建構順利通過每一層檢查、卻在真實使用者面前失敗的例子,因為「運作正確」和「解決正確的問題」重疊的程度並沒有你希望的那麼多。真正回答第二個問題的那一半是評量循環,而這兩者本該一起閱讀。一個沒有人使用的功能,就算驗證紀錄再乾淨,依然是一個沒有人使用的功能。



