完整逐字稿

點一下可跳到該段

歡迎回到 PickTrip 產品建造筆記,我是 Kai。

大家好,我是 PIKA。 上一集我們才把開店的手縮回來,因為收銀台會把還訂得到的票、 飯店、eSIM,全部說成「已過期」。

對。 上一集的問題是,系統在不知道的時候,講了一句太肯定的話。 今天我們把鏡頭拉得更遠一點:如果不看某一張票、不看某一顆 commit,

而是把整台 PickTrip 真的當成旅客,從首頁一路走到搜尋、 行程、探索、購物、錢包、AI、建立行程、帳號與協作詳情——使用者到底會在哪裡卡住?

聽起來像是終於有人把工程師的鍵盤拿走,逼他真的用自己的 App。

差不多。 這次用 iPhone 17 Pro 的測試環境,實際操作 Build 56, 留下二十七張畫面證據;

再把 VoiceOver 結構、大字、深色模式、冷啟動、 build、兩百零七項單元測試和程式碼一起對照,最後變成一份四十五頁的產品體檢。

好,先不要溫柔。 幾分?

Nielsen 十項可用性啟發式,四十七分,一百分滿分。

四十七? 不是「還有進步空間」,是補考通知單吧。

先把事情講簡單:PickTrip 不是功能不夠。 它已經把找靈感、建行程、多人協作、買票、訂房、eSIM、 錢包與 AI 串成一條很完整的旅遊工作流。

真正的問題是,功能很多,但人在最需要確定感的時候,系統不一定能回答三件事: 現在發生什麼、我的資料真的安全嗎、下一步能做什麼。

所以這次不是在挑圓角,也不是嫌玻璃不夠漂亮。

完全不是。 報告整理出十三個 P1、十八個 P2、七個 P3。 最直接的使用者感受,先從「等」開始。

我有不好的預感。

探索頁,大約十四秒才出內容。 收藏,大約十二秒。 AI 對話清單,大約十一秒。 三個地方都有 spinner,但沒有告訴你為什麼等、還要等多久、 能不能取消、失敗後怎麼辦。

十四秒喔? 我不是在等旅遊靈感,我已經開始懷疑人生方向了。

更麻煩的是,搜尋行程時,介面曾先出現一個幾乎全空白的中間狀態。 搜尋欄其實存在於 accessibility tree 裡, 但視覺上看不到;

要點到那個看不見的欄位、開始輸入,結果才出現。

隱藏關卡。 恭喜找到搜尋框,獎品是終於能搜尋。

建立行程也有一個很誠實、但誠實錯地方的畫面。 推薦目的地 API 失敗後,使用者直接看到英文:Request failed with status 521。

我是來排台北三天兩夜,不是來值班 Cloudflare。

對。 系統知道的是 HTTP 狀態碼,使用者需要知道的是:「推薦目的地暫時載不到, 但你仍然可以搜尋城市繼續。

」有趣的是,這條替代路徑其實真的能走; App 只是沒有把它講出來。

所以不是沒有出口,是出口沒有掛牌。

這正是「不讓使用者卡住」的核心。 不是所有請求都必須一秒成功,而是等待時要有狀態、失敗時要有人話、 還能走時要把路指出來。

但真正關鍵的,不是十四秒 spinner。

還有比十四秒更嚴重的?

有。 資料可能沒有存下來,但 App 會回你成功。

等一下,這句要再講一次。

協作行程的寫入流程,設計上會先把更新存成本機可恢復狀態, 再送到線上。 問題是,本機儲存如果失敗,錯誤會被記錄、被吞掉,最外層最後仍然回傳 true。

所以畫面說「好了」,其實只是「我有試著存,但失敗那段我沒有告訴你」?

對。 人在旅途中最不能接受的,不是按鈕慢半秒,是他以為同行夥伴都看得到, 離開畫面後才發現剛才的修改根本沒有耐久保存。

這跟上一集的假過期是同一種病欸。 系統把不確定,包裝成確定。

而且還有第二層。 App 的本機資料庫 schema 版本改變時,目前策略是直接重建 store。

註解把它當成可從網路重抓的 cache,可是同一個 store 裡, 也放了還沒有同步出去的 OfflineUpdate。

把行李寄放櫃跟垃圾桶做成同一個,更新 App 時一起清空?

這個比喻很準。 可重建的圖片快取可以清; 使用者尚未同步的編輯,不可以。 這兩種生命週期必須拆開。

好,所以前兩個 release blocker 是「存失敗卻說成功」和「更新可能把待同步資料清掉」。

收銀台呢? 上一集不是才在修誠實?

收銀台這次抓到另一種狀態誤判。 加密付款輪詢把 PAID、COMPLETED、PROCESSING, 甚至 PARTIAL_SUCCESS,全部放進同一個成功集合。

PROCESSING 叫處理中,PARTIAL_SUCCESS 叫部分成功。 這兩個名字到底哪裡像完整成功?

程式一看到它們,就把 settlement 設成 settled, 導去訂單完成頁。 使用者可能看到「完成」,但訂單仍在處理,或購物車裡只有部分項目成功。

那不是完成頁,是薛丁格的收據。

修法不是加一個 if 而已,而是建立付款狀態機。 處理中就是處理中,可以離開、可以之後追蹤; 部分成功要逐項說明哪些完成、哪些需要重試或退款;

只有真正終態,才能進完整成功頁。

同一組高風險裡,還有帳號刪除非原子化。 現在是先把後端資料改成 Deleted User,再刪 Firebase 帳號。

如果 Firebase 要求重新登入,流程會停在半路:資料已被 scrub, 帳號卻還活著。

刪除帳號不該像拆房子拆到一半,突然說「請重新驗證身分」。

沒錯。 要先重新驗證,再讓後端持有一個可重試、可追蹤、具 idempotency 的刪除工作。

到這裡我懂為什麼分數只有四十七。 可是畫面本身呢? PickTrip 明明很有自己的風格。

視覺野心是優點。 問題不是客製化,而是把平台行為也一起重做了。 底部 tab、sheet、context menu、calendar、

swipe action、loading,很多都有自己的版本。

品牌可以自己畫,但「怎麼返回、怎麼選、怎麼取消」最好不要逼 iPhone 使用者重學。

正是。 實測中,浮動 tab bar 會遮住 Trips、Explore、 Saved 最下面的卡片;

modal 開啟後,VoiceOver 還能聚焦到底下的內容; 探索卡片把標籤、標題、描述、分數,甚至每一顆星星都拆成按鈕, 星星只有大約十二乘十二點,還會讀出系統圖示名稱。

聽眾如果開 VoiceOver,想知道這個地方四點五星, 結果要先穿越五星迷宮。

日期選擇器看起來能按,但在 accessibility tree 裡只是 StaticText。

結帳的選取控制只有三十五乘三十五點、用 tap gesture, 沒有「已選」狀態。 這些都不是美術 polish,是有人真的無法完成任務。

大字呢?

把系統字級調到 Accessibility Extra Extra Extra Large, 行程詳情的日期、標題、狀態與浮動元件嚴重重疊。

程式裡大約有三千兩百六十三個固定字級呼叫,語意 text style 只有大約兩百四十個。

也就是說,這不是修三個畫面,是整套字體地基要重做。

對。 建立 typography token,用 semantic text style, 再讓 AX 字級時水平排列改成垂直、固定高度改最小高度。

Debug 與 Release 現在也都強制 Light; 如果要像原生 iOS,就要回到 semantic colors, 讓 Dark Mode 真正成立。

可是你剛剛說,兩百零七項測試全部通過?

全部通過,零失敗。 這正是今天最值得講的一個矛盾:測試可以全綠,產品仍然有十三個 P1。

因為考卷問的是「資料轉換對不對」,沒有問「磁碟滿了還會不會假裝存成功」。

很精準。 現有測試沒有真正覆蓋首載 API 失敗後會不會永遠 skeleton、 離線 outbox 寫入失敗、資料庫 migration、

付款處理中與部分成功、異常 JWT、帳號刪除中段失敗、AX 大字、 VoiceOver modal focus,還有一百筆訂單帶來的請求風暴。

所以測試數量不是 release confidence。 高成本失敗有沒有考,才是。

報告最後沒有丟一張「以後再改善」的願望清單,而是排成四個階段。

第一階段先做什麼?

本週只守資料與金流。 第一,協作更新必須在 durable write 成功後才可以說成功。 第二,把待同步 outbox 從可清除 cache 拆出去,

停止版本不符就整庫 wipe。 第三,修付款狀態機。 第四,JWT 格式不對不能 crash。 第五,帳號刪除先 reauth,再走後端原子流程。

第六,Trips 首載失敗立刻離開 shimmer,給明確 retry。 第七,所有 HTTP 錯誤改成人話。

聽起來這週不加新功能。

對。 下一階段才是建立全 App 共用的 Loading、Content、 Empty、Failed、Offline、Stale 狀態系統。

等待超過兩秒要說明,八秒還沒完成要有 retry、cancel 或離線替代; 不准再有沒有終止條件的 spinner。

再下一階段,把 tab、sheet、alert、search、 swipe action 交還給 iOS。

最後才是制度化:AX5 與深淺色 snapshot、VoiceOver smoke test、 migration 與 disk-full fault injection、

實機 Instruments baseline,還有 Release archive 的 debug 字串掃描。

我發現今天其實沒有否定 PickTrip。 反而是因為功能真的已經串起來了,才開始要求它像一個可以託付旅程的產品。

沒錯。 早期產品最容易把「做得到」當成完成。 可是旅行不是 demo:網路會慢、手機會更新、同行的人會同時編輯、 付款會停在中間、使用者會需要大字。

真正的完成,是這些不完美同時出現時,產品仍然不說謊、不丟資料, 也不把人留在沒有出口的畫面。

所以今天的結論不是「四十七分很慘」。

而是第一次把「不要讓使用者卡住」拆成可以驗收的 release gate。 每一次操作,都要回答:現在發生什麼、資料是否真的安全、下一步可以做什麼。

上一集,團隊因為收銀台說謊,把上線往後延。 這一集,整台 App 被走了一遍,發現說謊的不只收銀台——spinner、 儲存、更新、付款完成頁,都可能把不確定講成確定。

下一個問題就很具體了:這十三個 P1,會只是另一張很完整的報告, 還是真的變成上線前一條都不能跳過的門?

我們下一集看。

明天同一時間,PickTrip 產品建造筆記,每日更新。

掰掰!

PickTrip建造術:把整台 App 當旅客走一遍的那一天——四十五頁體檢只拿四十七分,十三個 P1 把『不讓使用者卡住』變成上線前不能跳過的門

第 26 集 · 2026/7/29
0:00 10:00

把你在乎的主題,做成持續更新的 Podcast

NewsTune 幫你研究、整理並製作;你只需要決定下一個想追的問題。

前往 NewsTune Studio