模組六|測試、效能與上線(Day 26–30)
昨天列了一張「有檢查/沒檢查」的四格表。今天把整個專案的數字重跑一次收在一張表上,然後花更長的篇幅講另一張表——我會重做的事。
免得你讀到一半以為這是成功故事:這個專案交付了一款能玩的小遊戲,同時交付了一份沒做完的驗證清單,兩者都是真的。
結論先講:這三十天最值得帶走的不是「我用 AI 一天做完一款遊戲」,而是——你設得出多少道自動檢查,就能放心交出去多少工作;而那些你設不出檢查的地方,最後會變成你事後說不清楚的地方。
遊戲在這裡,開了就能玩,不用註冊:https://save-the-dog-web.vercel.app/
原始碼在這裡,全部公開:https://github.com/HarryFan/save-the-dog-web
五個關卡,桌機與手機都能玩。量體數字全部在今天重跑一次:
| 項目 | 數字 | 怎麼得出的 |
|---|---|---|
| commit 數 | 31 | git rev-list --count HEAD,且與 --first-parent 相同——沒有任何 merge commit |
| 首末提交跨度 | 15 小時 33 分 | 2026-08-06 03:07:27 → 18:40:18(+0800) |
src/ |
44 檔 5,784 行 | find src -name '*.js' 計數與 cat 後 wc -l |
| 素材 | 19 個 SVG(存兩份,共 38 檔) | find 計數 |
| 單元測試 | 33 檔 292 個測試,3.24 秒全過 | npm run test:unit -- --run |
| e2e 測試 | 4 個 spec 檔 | find tests/e2e -type f |
PRD.md |
2,419 行 | wc -l |
| 驗證器 | 516 行、20 條規則 + 1 條警告 | wc -l scripts/validate-svg.js 與逐條實查 |
| openspec change | 歸檔 7、進行中 3 | ls openspec/changes/ |
| 建置產物 JS | 未壓縮 748 KB,gzip 後 215.6 KB,14 個檔 | 今天重跑 npm run build 後量測 |
最後那一列要標記:這是我第一次真的量它,原因寫在後面。

PRD.md:9 開頭那句話寫得很清楚:以一名開發者每週 40 小時計算,建議安排六週、約 240 小時完成可公開展示的 MVP。PRD.md:2377 的里程碑表把發布日訂在 2026-09-18。
實際上,首個 commit 到末個 commit 相距 15 小時 33 分,同一天之內。
這個落差很好看,也很容易被拿去當標題。所以我要在同一段裡把它拆開,四條限制少講任何一條,這就變成一則廣告:
| 限制 | 說明 |
|---|---|
| 跨度不是工時 | 15 小時 33 分是首末提交的時間差。實際投入人時我沒有紀錄,也不推估。 吃飯、離開、卡住發呆的時間全包在內 |
| 交付的是五關 MVP | 不是產品。沒有帳號、沒有排行榜、沒有商店、沒有多人 |
| 範圍極小 | 一條線、畫完不能改、五個關卡。這是刻意設計的,也是它做得完的主因 |
| 我全程在場 | 每一個決定都是我做的。AI 沒有在無人監督下跑過任何一段 |
還有第五件事,比前四條更重要:沒有對照組。 我沒有用傳統方式做過同一款遊戲,所以「快了幾倍」這種說法我沒有資格講。
可以講的是一個更小的因果:那份 2,419 行的 PRD 在開工前就存在,所以整個過程沒有一次「先做出來再說,做完發現方向不對」。歸檔規格裡有一行直接把柔性繩索防線這條路關掉了(Day 15 講過),那一行省下的不是幾小時,是一整條走進去才會發現是死路的岔路。
第一,先寫規格再開工。 當實作的執行者是 AI,規格從「給人看的說明」變成「驗收的依據」——viewBox 固定、允許色碼列舉、必須有這九個語意分組,這些句子可以被寫成一支會讓 CI 失敗的腳本。這件事 Day 8 開頭、Day 29 收尾,這裡只提一句。
第二,防線用單一複合剛體,不用柔性鏈條。 穩定度換真實感,因為約束震盪與線段穿透在小專案裡沒有便宜的解法。誠實邊界:我從沒實作過另一邊,這個結論是從 Matter 求解器的行為推論的,不是兩個版本比出來的。
第三,效能預算訂在寫程式之前——這一條要連著它的失敗一起講。
PRD.md:2044 那張預算表有 12 條,訂在任何一行遊戲邏輯之前,而它確實反過來決定了架構:蜜蜂同時數 16、硬上限 24 直接進了 src/config/game.js:63-64 變成物件池容量;「Constraint 數 MVP 近乎 0」就是第二點那個取捨的來源;「Matter Body 總數低於 100」則是節點抽稀策略存在的理由。預算不是驗收時才拿出來對的東西,它在寫程式之前就在做架構決定了。
但十二條裡,到今天只有兩條有數字:
| 預算條目 | 狀態 |
|---|---|
| Matter Body 總數 < 100 | ✅ 有自動斷言在守(tests/unit/determinism.test.js:141),每次 CI 都跑 |
| 初始核心傳輸量壓縮後 < 3 MB | 🟡 gzip 215.6 KB,遠低於預算——但這是我今天寫這篇文章時才第一次量的 |
| 桌機 FPS、中階手機 FPS、單幀 P95、Matter 更新 P95 | ❌ 零次量測。debug HUD 從未實作 |
| 蜜蜂同時數、Constraint 數、防線節點數 | ❌ 有設定值,沒有執行期量測 |
| 可互動時間、關卡切換、一小時 Soak Test | ❌ 零次量測 |
所以這一條同時是「決定對了」和「我會重做」。一個從來沒被量過的預算,作用只有一半——它能約束你怎麼設計,不能告訴你有沒有做到。
第一,證據留存機制建立得太晚。這是最大的一件。
docs/rejected/ 的 README 開頭寫著「存放未通過驗證的原始檔案,不是垃圾桶」。三十天後重跑 ls:還是只有那一個 935 bytes 的 README,零個實例,而它的建立時間晚於全部 31 個 commit。
dev-log.md 更明顯。這個檔案 149 行,第 24 到 33 行是一份效能記錄格式的模板,欄位訂得很仔細——數值、裝置型號、瀏覽器版本、蜜蜂數、節點數,缺一項該筆紀錄無效。填進去的數字:0 個。 全檔唯一一筆日誌標題是「2026-08-06(事後補登)」,內容全是可以從 git 回溯的計數。
代價是寫這個系列時才付的:驗證器實際擋下過哪些 AI 產出、素材風格怎麼從第一版收斂到第十九版,一個字都沒留。有好幾篇因此從「它擋下過什麼」被改寫成「這道閘門在防什麼」。
做完的東西不會自己說明它是怎麼做出來的。 你事後能講的,只有你當下有留的。
第二,效能與跨裝置實測拖到最後才做。
上一節那張表就是量化:12 條預算、1 條有自動檢查、1 條在寫文章時才量、10 條至今零次量測。整個開發過程我都不知道自己有沒有踩在預算內。沒踩線是運氣,不是驗證。
連帶的還有一件:4 個 e2e spec 檔寫好了,但 .github/workflows/deploy.yml 只跑四道——素材驗證、lint、單元測試、build。npm run test:e2e 不在裡面。 寫了不跑的測試,跟沒寫的差別只在於它給人一種寫過了的錯覺。
第三,關卡設計沒有早點找人試玩。
五個關卡的難度曲線全部是我自己排的,而我在排的時候已經玩過每一關幾十次。自己玩會失去判斷力——你知道洞口在哪、線該畫在哪,第三關對你很簡單,對第一次開這個網頁的人可能根本過不去。這件事沒有技術難度,我只是沒做。

public/assets/hazards/ 這個目錄裡有一個 1 byte 的 .gitkeep,建立於 866d153,2026-08-06 03:36——第一個 commit 之後 29 分鐘。
它到今天還是空的。
第二階段的清單就住在這個目錄的名字裡:危險區(水、岩漿、尖刺)、柔性防線、更多障礙物、粒子效果、關卡編輯器。開工半小時內我就知道自己想做這些,三十天過去一個都沒做。
這不是失敗,是範圍控制在運作。但那個空目錄比任何 roadmap 都誠實:你在第一天就建好的目錄,如果三十天後還是空的,它反映的不是你的計畫,是你真正的優先序。
Day 1 押的那句話是「AI 產出的品質,取決於你設得出幾道它過不去的自動檢查」。三十天下來我要為它加一個補語。
素材那一層是我交出去最多、也最放心的部分——19 個 SVG 幾乎全是 AI 產的,因為那一層的規則幾乎全部可以自動檢查:viewBox、色碼、語意分組、命名,每一條都有一個可以被程式解析的目標。核心系統交得少,是因為那一層的規則長得像「重試時該重置哪些狀態」——這種句子寫不成斷言。
補語是這個:你設不出檢查的地方,不只是你必須親自出席的地方,也是你事後會說不清楚的地方。 docs/rejected/ 空著、dev-log.md 的效能欄位空著,都不是因為我懶——是因為那些東西沒有一個會在你沒做時變紅的機制。沒有檢查在守的紀律只靠記性維持,而記性在時間與人數這兩個變數上都是負相關。
範圍越小,越能做完;而做完的東西才會逼你面對你沒驗證的部分。一款做完的小遊戲,價值遠高於三款做一半的。
如果你要做網頁小遊戲,三句話:
如果你要用 AI 寫程式,一句話:你設得出多少道自動檢查,就能放心交出去多少工作。 那份設不出檢查的清單,就是你的出席名單。
三十天日更的心得是同一件事:即使專案已經做完,重新寫一遍仍然不輕鬆,因為寫作要求你重新理解自己做過的事。 而這個過程找出了幾個當時沒發現的問題——utils/ 那條沒人守的紀律、PRD.md 裡那張跟現況不符的色票表、12 條預算裡 10 條從沒量過、e2e 寫了不跑。沒有一件是開發時發現的,全部是寫文章時被逼出來的。
寫作是一種很慢的檢查器,但它會抓到你所有自動檢查漏掉的東西。
謝謝讀到這裡的人。遊戲還在那個網址上,歡迎開 issue 告訴我第幾關卡住了——那正好是我最缺的那份資料。
本篇數字的快照時間:2026-08-07 23:55(+0800),對應 commit
120ceb3;建置產物數字為當日重跑npm run build後量測。專案仍在開發中,量體數字會變動。
可玩網址:https://save-the-dog-web.vercel.app/|原始碼:https://github.com/HarryFan/save-the-dog-web
如果你卡在語法
深入原理