前端系統設計面試:從一張 UI 推到最小狀態、資料流與 AI 工具鏈

文字解析 · 1 支影片 · 產生於 2026-10-01 00:54

🎧 語音解析📝 筆記✍️ 練習

🎧 語音解析 31m17s · TTS 講解與作者原聲交錯;點章節可跳。
邊聽邊看逐句講稿,點任一句從那裡開始
章節(16)

1. Outline

  1. 起點 · Real Senior Frontend System Design Interview 2026 (AI Coding Included)
    用一場真實的資深前端白板面試,把「從 UI 到架構」走成一條可重複的固定路線:需求 → 狀態 → 實作細節 → 非功能性需求 → AI 工具鏈。

2. YouTuber 的思維推導

Real Senior Frontend System Design Interview 2026 (AI Coding Included)

theSeniorDev · 40m31s · 字幕 en · vision=on (整支影片是螢幕分享+白板:作者不斷說「我們看這個 UI」「我把這個標成不在範圍」「我把這兩個型別合併」「這裡畫一條線」,指示語遠超過 3 次,型別定義、BFF 圖、SSE 事件流都畫在畫面上,不看圖無法理解他在指什麼。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 2s
segment 1m51s 7m00s
shot 1m35s 12s
analyze 17m30s 25m00s
render 5s –

作者要解決的不是「這個圖表元件怎麼寫」,而是「在白板前你怎麼不會卡住」。他的推導從一個觀察出發:面試會失敗,多半不是因為不會技術,而是沒有心智里程碑,不知道自己走到哪、還缺什麼。於是他把一場前端系統設計面試拆成一條固定路線:先把 UI 翻成功能性與非功能性需求(不照單全收設計稿),再從 UI 逐塊刪去、圈出真正的 state 並寫成型別(過程中積極合併與刪去衍生狀態),接著問「狀態怎麼變」——只有後端資料與使用者事件兩個來源——順勢決定狀態管理選型;有了狀態才談實作細節(框架、設計系統、CSS、無障礙、建置工具、程式碼品質),這時才有資格談非功能性需求:效能拆成載入、互動、版面穩定三個維度逐一探問,可擴展性把瓶頸推向後端於是引出 BFF 的穩定介面,即時性在 polling/WebSocket/SSE 之間用「是不是真的雙向」做選擇,最後用讀寫比決定各層要不要快取。

整條路線的兩個隱藏主軸是:一,狀態要壓到最小,能算出來的就不要存;二,把選項攤開讓面試官選,而不是替他做決定。AI 的部分被他當成同一套推理的延伸——AI 可以幫你精煉狀態結構,但它會膨脹細節、也缺乏視覺智能,所以你要先產出穩定的錨點產物(設計系統、狀態圖、循序圖)讓模型只做內插。結論落在一句話:把設計做完整、貼回你每天真的在做的前端業務系統,不要去解想像出來的系統。

推理鏈:每段留給下一段的線索

每一列是一段,箭頭後的字是這段留給下一段的線索。點段落標題跳到該段。

  1. 白板面試現場與「心智里程碑」 → 那組心智里程碑到底是什麼?第一個里程碑:不把設計稿照單全收,先把畫面翻成需求。
  2. 階段一:功能性與非功能性需求 → 既然要拆成「初始載入」與「即時更新」,就得先知道畫面上到底有哪些東西會變;下一步是回到 UI 圈出真正的 state。
  3. 階段二起手:從 UI 圈出真正的 state → 圈出來的都還只是畫面上的欄位;下一步要把它們寫成有名字、有型別的資料結構。
  4. 把畫面翻成資料模型 → 型別骨架有了,但作者是純手工推出來的;如果允許用 AI,這一步能不能外包?
  5. 用 AI 幫忙設計 state 的界線 → AI 版本漏掉的正是最底層那個型別——data point 還沒被完整寫出來,得補上。
  6. data point 與請求合併的取捨 → 資料的「形狀」定完了,但還沒回答它「怎麼變」——狀態轉移是下一個里程碑。
  7. 狀態轉移與狀態管理選型 → 狀態的形狀與轉移都定了,可以往下談「這東西實際上怎麼做出來」的實作細節。
  8. 最小可行前端:框架、設計系統、CSS、無障礙 → 清單走到第五項就是建置工具,而一旦談建置工具,就得回答「AI 在寫大部分程式碼時,品質靠什麼守住」。
  9. 建置工具與 AI 時代的程式碼品質 → 功能面與工程面都收乾淨了,接下來輪到被擱置最久的那一欄——非功能性需求裡的效能。
  10. Web 效能的三個維度 → 前端這側的手段講完了,但流量真的上來時瓶頸會落在後端——那該怎麼辦?
  11. BFF:讓介面穩定下來 → 資料怎麼來的路徑定了,但還沒回答那條路徑上「即時更新」要用什麼協定送。
  12. 即時更新:SSE,以及把狀態壓到最小 → 資料怎麼來、怎麼更新都定了;剩下的問題是哪些資料根本不必再拿一次。
  13. 快取:用讀寫比決定快取什麼 → 整套架構的技術面到此完備;剩下沒回答的是這一切要用什麼工具、什麼模型做出來。
  14. AI 開發工具鏈:模型、harness、審查代理 → 工具與模型也定了;回頭看這整份架構,還有哪些地方作者自己覺得沒挖夠?
  15. 回頭看:還會再深掘的地方 → 技術面能補的都列完了;剩下最後一個問題——同樣的題目,為什麼有人過有人不過?
  16. junior 與 senior 的差別,以及唯一的建議

3. 逐段說明

Real Senior Frontend System Design Interview 2026 (AI Coding Included)

1. 白板面試現場與「心智里程碑」 0:00–1:23

這是學員在某大型金融公司真實拿到 offer 的資深前端系統設計面試:現場、不能用任何數位工具,面試官把一張金融資產走勢圖印在紙上,要她在白板上走完整個設計流程。主持人指出這種面試最大的陷阱是「腦袋一片空白」——因為沒有一組心智里程碑,不知道自己走到哪、還缺什麼、下一步該去哪。本集就是把那組里程碑攤開來講,並額外插入「這一階段適不適合用 AI」的提問。

面試官給的那張金融資產走勢圖(印在紙上的原題),整支影片所有推導都從這張圖長出來
0:30 · 面試官給的那張金融資產走勢圖(印在紙上的原題),整支影片所有推導都從這張圖長出來
承上 前情提要裡的背景:系統設計面試通常被想成「畫架構圖」,這一段先把場景收窄成前端、現場、只有一張印在紙上的走勢圖,沒有任何數位工具。

推理因為要說服你「需要一套流程」,主持人先給了一個極端場景:學員被請到現場,不能用任何數位工具,面試官把一張金融資產走勢圖印在紙上,要她在白板前走完整個設計。接著他直接點名這種面試最大的陷阱——腦袋一片空白。他把原因歸給「缺少一組心智里程碑」:不知道自己在哪、還缺什麼、下一步去哪。所以整支影片的形式就定了:不是講某個技術,而是把那條路線攤開;並且每走到一個階段就額外插問「這一階段適不適合用 AI」。

AI 補充截圖裡那張圖其實不是傳統券商的股價圖,而是 Polymarket 的「BTC Up or Down 5m」市場頁:上方有 Price To Beat 與 Final price 兩個數字、中間一條橘色折線、一條虛線的 target、下方是可切換的時間區間按鈕。認出這個畫面很重要,因為之後每一個型別欄位都能在這張圖上指出對應的位置。另外要注意場景的限制條件:不能用電腦,代表你不能靠 IDE、不能靠 AI 補齊;你唯一能依賴的就是腦中那條路線——這正是為什麼「里程碑」比任何單項技術都值錢。

System Design Interview

系統設計面試

面試官給一個開放式的產品或功能,要你當場設計出可行的架構並解釋取捨。

後端版本的系統設計面試考的是分散式儲存、分片、佇列;前端版本考的是把 UI 翻成狀態、決定資料流與渲染策略、以及效能與無障礙這些非功能面向。這場面試的特殊之處是「白板、無電腦」,所以評分幾乎完全落在你的推理過程與提問品質,而不是你寫得出多漂亮的程式碼。

相關術語: Functional Requirements (第一個階段)

出處:第 1 段「白板面試現場與「心智里程碑」」

留給下一段 那組心智里程碑到底是什麼?第一個里程碑:不把設計稿照單全收,先把畫面翻成需求。

2. 階段一:功能性與非功能性需求 1:23–5:10

資深工程師不會把設計稿照單全收,而是把 UI 翻譯成具體需求。功能性需求=要做到什麼(要有圖表、要有這些按鈕、需要哪些畫面),非功能性需求=怎麼做到(跨瀏覽器、載入速度、無障礙、可測試、可維護)。他用車子比喻:功能性是「能不能把我從 A 載到 B」,非功能性是「要吃多少油」。接著他當場示範要問面試官的問題:這是放在自家 component framework 裡的可重用元件,還是要嵌到別的網站(那就得用 iframe)?效能有沒有 SLO(前端用 Core Web Vitals 與 RUM 量化)?金融機構受嚴格監管,無障礙與安全一定要在開頭先點名。最後他確認 UI 有即時更新,於是把問題切成「初始載入的靜態圖」與「之後持續刷新的即時部分」兩塊。

白板上寫下 functional / non-functional requirements 兩欄,這是整套流程的第一個里程碑
1:48 · 白板上寫下 functional / non-functional requirements 兩欄,這是整套流程的第一個里程碑
他在原始設計稿上逐項圈出功能性需求(標籤、數字、會一直刷新的欄位)
2:48 · 他在原始設計稿上逐項圈出功能性需求(標籤、數字、會一直刷新的欄位)
即時更新的實際畫面:圖在動、計時器在動、資料範圍是動態的,這是後面切成兩塊的依據
4:28 · 即時更新的實際畫面:圖在動、計時器在動、資料範圍是動態的,這是後面切成兩塊的依據
承上 承上:第一個里程碑就是不照單全收設計稿——這段示範怎麼把一張圖翻成兩類需求。

推理因為上一段說資深工程師不會把 UI 當成既定答案,作者第一步就在白板右側寫下兩欄:Functional Requirements 與 NonFunctional Requirements。他先用一句判準把兩者分開:功能性是「你要做到什麼」(要有圖表、要有這些按鈕、需要哪些畫面),非功能性是「你怎麼做到」(跨瀏覽器、載入夠不夠快、無障礙、可測試、可維護);車子的比喻是「能不能把我從 A 載到 B」對上「要吃多少油」。接著他把這兩欄當成提問清單一項項問:這是塞進 component framework 的可重用元件,還是要嵌到別的網站(那就得用 iframe)?效能有沒有 SLO——前端要用 Core Web Vitals 加 RUM 來量化?無障礙與安全在金融機構是法遵問題,所以一定要在開頭先點名,但不必展開。最後他問到即時更新,並在真實頁面上確認圖在動、計時器在動、資料範圍是動態的,於是把問題切成兩塊:初始載入的靜態圖,與之後持續刷新的即時部分。

AI 補充這一段真正的技巧不是「知道有非功能性需求」,而是「先掛號、不展開」。作者自己說了:無障礙與安全就在開頭提一句「我們會在後面擴大設計時把這些考慮進去」,你不需要當場講細節。這麼做有兩個效果:一是讓面試官知道你的雷達上有這些東西(很多 junior 就是整場沒提過無障礙),二是替自己在後面預留可以回來深挖的話題,避免中段沒話講。另外注意他的量化選擇:非功能性需求裡只有效能能給出真正的數字,所以他只在效能上追問 SLO;無障礙與安全他改用「有沒有法規要遵守」來逼出具體標準。最後那個「靜態載入 vs 即時更新」的二分是這整支影片的第一個結構性決定——後面資料模型、快取、傳輸協定的討論全都沿著這條裂縫走。

Functional Requirements

功能性需求

系統要做到什麼——在前端通常等同於把畫面與互動列成清單。

前端的功能性需求幾乎都能透過 wireframe 表達:需要哪些畫面、畫面上有哪些可互動元素、按下去會發生什麼。作者的做法是拿著設計稿逐項唸出來(靜態標籤、會刷新的數字、可點的時間區間),因為唸出來的過程本身就在逼出遺漏的問題。

相關術語: Non-Functional Requirements (對照組)

出處:第 2 段「階段一:功能性與非功能性需求」

Non-Functional Requirements

非功能性需求

系統要「怎麼做到」——速度、相容性、無障礙、安全、可測試、可維護這些品質面向。

常被誤會成「次要需求」,其實它決定架構長什麼樣:要 SEO 就得考慮 SSR,要無障礙就得從語意化標記開始,要合規就得限制資料能送去哪裡。作者的車子比喻很好用:功能性是「能不能載我從 A 到 B」,非功能性是「油耗多少」——不直接構成功能,卻直接決定使用者體驗。在這場面試裡它還是後半場所有話題的入口。

相關術語: SLO (用來量化)、Core Web Vitals (前端量化指標)

出處:第 2 段「階段一:功能性與非功能性需求」

SLO

服務水準目標

對某個品質指標訂下的明確目標值,例如「載入時間 95 百分位要低於 2.5 秒」。

SLO 的價值在於把「要快」變成可驗收的數字。前端談 SLO 時通常直接綁在 Core Web Vitals 上,並且要說清楚是實驗室數據還是真實使用者數據。面試中即使對方沒有現成的 SLO,主動問一句就已經表態:你打算把非功能性需求量化,而不是喊口號。

相關術語: RUM (資料來源)

出處:第 2 段「階段一:功能性與非功能性需求」

Core Web Vitals

核心網頁指標

Google 定義的一組使用者體驗指標,目前是 LCP(最大內容繪製)、INP(互動到下次繪製)、CLS(累積版面位移)。

這三個指標剛好對應作者後面會用的效能三維度:載入、互動反應、版面穩定。要注意 INP 從 2024 年 3 月起取代了舊的 FID,所以面試時講 FID 會顯得資訊過時。它們同時是 Google 搜尋排名的訊號之一,所以只要對方在意 SEO,這組指標就自動變成硬需求。

相關術語: RUM (在真實流量量測)

出處:第 2 段「階段一:功能性與非功能性需求」

RUM

真實使用者監測

從真實使用者的瀏覽器蒐集效能資料,而不是在實驗室環境跑合成測試。

Real User Monitoring 的重點是分布而非平均值:同一個頁面在旗艦機與低階 Android、在光纖與行動網路上的表現差好幾倍,只有真實流量能告訴你 75 百分位在哪。實務上會用 web-vitals 這類函式庫把 Core Web Vitals 回傳到自家端點或監測服務。它與合成測試(Lighthouse、CI 上的 performance budget)互補:合成測試抓回歸,RUM 定目標。

相關術語: Core Web Vitals (量測的對象)

出處:第 2 段「階段一:功能性與非功能性需求」

留給下一段 既然要拆成「初始載入」與「即時更新」,就得先知道畫面上到底有哪些東西會變;下一步是回到 UI 圈出真正的 state。

3. 階段二起手:從 UI 圈出真正的 state 5:10–7:00

第二階段是狀態架構,因為在新的 UI 裡 state 是功能的核心。做法是拿著 UI 逐塊刪去法:先把明確不在範圍的區塊一個個標掉,留下圖表功能;再判斷剩下區塊裡哪些是靜態、哪些會變。他標出會變的部分:重新載入會變的文字、final price、price to beat、還有所有資料點——這些都是初始載入時從後端來的。他也順手做了第一次去重:畫面上「current price」跟下面那條線的價格其實是同一個狀態,只要留一個;但 target price 是獨立的,要另外抓。

他用顏色把 UI 上「不在範圍」的區塊一個個標掉,只留下圖表——範圍界定的具體手法
5:40 · 他用顏色把 UI 上「不在範圍」的區塊一個個標掉,只留下圖表——範圍界定的具體手法
標出所有會變動的欄位(final price / price to beat / 資料點),這張圖就是後面資料模型的來源
6:30 · 標出所有會變動的欄位(final price / price to beat / 資料點),這張圖就是後面資料模型的來源
承上 承上:既然要分開「初始載入」與「即時更新」,就得先知道畫面上哪些東西會變——這段用刪去法把它們圈出來。

推理因為上一段把需求分成靜態與即時兩塊,作者接著宣告第二個里程碑:狀態架構,理由是「在新的 UI 裡 state 是功能的核心」。他的手法是刪去法而不是列舉法:拿著畫面,先把明確不在範圍的區塊一個個劃掉(截圖裡可以看到 Past 按鈕、右上角的分享圖示、右下角的圖表類型切換全被打叉),只留下圖表本身;再判斷剩下的區塊裡哪些是靜態、哪些會變。他標出四類會變的東西:重新載入才會變的標題文字、Price To Beat、Final price、以及所有資料點。然後他做了第一次去重:畫面上的 current price 跟折線末端其實是同一個值,只留一個就好;但那條虛線的 target price 是獨立的,得另外抓。

AI 補充刪去法比列舉法可靠,原因是它會逼你對每一塊畫面做出明確判斷(在範圍/不在範圍/靜態/動態),而列舉法很容易只寫下你想得到的那幾個。這裡也藏著一個實務提醒:「不在範圍」不等於「不存在」——你只是跟面試官達成共識先不做,這句共識本身就是加分項。另外,作者對 current price 與折線末端做的去重,其實已經預告了他整段的核心原則:兩個看起來不同的畫面元素,如果總是能從同一份資料算出來,它們就只該有一份狀態。這個原則在幾分鐘後會被推到極致。

State

狀態

前端在記憶體裡持有、會隨時間改變、並且改變後要重新渲染畫面的那份資料。

判斷某個東西是不是 state 有個簡單問法:它會變嗎?變了畫面要跟著變嗎?它能不能從別的 state 算出來?三個答案是「會、要、不能」時它才是 state。作者刪掉 current price 就是因為第三題答案是「能」。把 state 圈小是前端架構最有效的簡化手段:狀態越多,需要同步的路徑就越多,bug 也越多。

相關術語: Derived State (應被排除)

出處:第 3 段「階段二起手:從 UI 圈出真正的 state」

留給下一段 圈出來的都還只是畫面上的欄位;下一步要把它們寫成有名字、有型別的資料結構。

4. 把畫面翻成資料模型 7:00–9:29

他開始把剛才圈出來的動態欄位寫成型別。先是 date interval(start / end 兩個 date),對應畫面上的時間軸與那個區間條;再來是 price data(price to beat、final price、target price,先用 JavaScript number,並說明金融資料若要多位小數可考慮 BigInt);最後是 data series(string 型的 UUID id,加上一個 data point 陣列)。接著他做了關鍵的整併與刪減:date interval 的 start/end 跟 data series 是強相關、欄位互相依賴,合併成一個型別;final price 根本不必抓,它就是最後一個資料點,屬於衍生狀態(derived state),直接刪掉;price to beat 則像是獨立變數,值不值得合併要看後端怎麼存、要不要發兩次請求——這正是他會反問面試官的地方。

白板上第一版型別:date interval 的 start / end,看得到他怎麼把畫面元素對應成欄位
7:35 · 白板上第一版型別:date interval 的 start / end,看得到他怎麼把畫面元素對應成欄位
price data 型別成形(price to beat / final / target),以及 number vs BigInt 的取捨
8:20 · price data 型別成形(price to beat / final / target),以及 number vs BigInt 的取捨
data series → data point 陣列的結構,是整個資料模型的骨架
8:50 · data series → data point 陣列的結構,是整個資料模型的骨架
整併後的最終型別:合併 date interval、刪掉衍生的 final price——刪去的痕跡才看得出推理
9:20 · 整併後的最終型別:合併 date interval、刪掉衍生的 final price——刪去的痕跡才看得出推理
承上 承上:圈出來的欄位還只是畫面上的位置,這段把它們寫成有名字、有型別的結構。

推理因為上一段已經把會變的東西標出來,作者直接在畫面右側敲出 TypeScript 型別。第一個是 DateInterval(start: Date、end: Date),對應時間軸與那個區間條;第二個是 PriceData(price_to_beat、price_final、price_target,先用 JavaScript 的 number);第三個是 DataSeries(string 型的 id,加上一個 data_points 陣列)。接著他開始做減法與合併,這才是這段的重點:DateInterval 的 start/end 跟 DataSeries 是強相關、欄位互相依賴(那些點就是從 start 走到 end),所以合併成一個型別;price_final 根本不需要抓,它就是最後一個資料點,屬於衍生狀態,直接刪掉;price_to_beat 看起來是獨立變數,值不值得跟 DataSeries 併成一次請求則取決於後端怎麼存——這正是他會反問面試官的地方。

AI 補充留意截圖裡型別演進的痕跡:s04_455 還是 DateInterval 與 PriceData 兩個獨立型別,到 s04_560 已經變成 DataSeries 裡直接長出 start、end、price_to_beat、price_target,而 price_final 消失了。這種「先寫出來再刪掉」的過程本身就是面試要看的東西——刪掉的理由(它是衍生的)比留下來的欄位更能證明你懂。另外補一個作者略過的細節:他把 timestamp 定成 string 是對的(JSON 沒有日期型別,網路上一律是 ISO 8601 字串),但 DateInterval 用 Date 型別代表這是「解析後」的前端模型;實務上這兩者要分開——API 回應型別用 string,前端狀態型別用 Date,中間有一層 parse。他沒說出這一步,但那是所有「timestamp 是字串、之後要 parse」的話真正的落點。

Derived State

衍生狀態

可以從既有狀態算出來、因此不該另外儲存的值。

price_final 是教科書級的例子:它永遠等於 data_points 的最後一筆,多存一份就多一條同步路徑,一旦忘了更新畫面就會出現兩個互相矛盾的數字。前端框架裡這通常用「渲染時直接算」或 useMemo 解決,而不是再開一個 state。反過來說,只有在計算成本高到會拖慢渲染時,才值得把衍生值快取起來——那時它仍然不是狀態,只是快取。

相關術語: State (應從中排除)

出處:第 4 段「把畫面翻成資料模型」

BigInt

大整數

JavaScript 的內建型別,能表示任意大小的整數,寫法是 123n。

它解決的是「整數超過 Number.MAX_SAFE_INTEGER(2^53-1)後會失準」的問題,常見於雪花 ID、鏈上金額、資料庫 bigint 主鍵。但它只處理整數,沒有小數;而且不能跟 number 直接混算,也不能被 JSON.stringify 序列化。金融場景真正的做法是把金額存成最小單位的整數(分、聰),或改用 decimal.js 這類任意精度十進位函式庫。

相關術語: UUID (同為 id 選項)

出處:第 4 段「把畫面翻成資料模型」

UUID

通用唯一識別碼

128 位元的識別碼,通常寫成 36 字元的字串,不需要中央協調就能保證幾乎不重複。

作者選 UUID 而不是遞增數字,理由是可以在客戶端先產生 id(樂觀更新時很有用),也不會洩漏「你有多少筆資料」這種資訊。代價是佔用空間較大、隨機的 UUIDv4 當資料庫索引時局部性差;如果在意這點,現在通常用 UUIDv7 或 ULID,它們把時間戳放在前綴,既唯一又可排序。

相關術語: Referential Integrity (用於建立關聯)

出處:第 4 段「把畫面翻成資料模型」

確定錯誤/已過時 7:45
「you want a lot of decimals, then those numbers can store a lot more than a plain integer」
BigInt 不能存小數。它是任意精度的「整數」型別,寫 1.5n 直接語法錯誤。金融資料要精確小數,正確做法是存最小貨幣單位的整數(例如以「分」為單位存 8190242),或用 decimal.js / big.js 這類十進位函式庫;JavaScript 的 number 是 IEEE 754 雙精度浮點數,0.1 + 0.2 !== 0.3 的問題就出在這裡。
依據: ECMAScript 規範 BigInt 型別定義:BigInt values represent integer values;TC39 decimal 提案仍在 stage 1(2026)
留給下一段 型別骨架有了,但作者是純手工推出來的;如果允許用 AI,這一步能不能外包?

5. 用 AI 幫忙設計 state 的界線 9:29–10:35

主持人追問:這段你是手工一個一個做的,如果允許,你會怎麼用 AI?他說 AI 可以拿來精煉或腦力激盪狀態架構——他錄影前就把 UI 丟給 Claude,第一版給了一個過度複雜的資料結構,他回「把它簡化」才得到接近的版本,還可以指定輸出成 diagrams.net 能吃的格式。但結果有落差:AI 把 target price 併進 chart data,也漏掉一些資料點。他的結論是 AI 不太算幻覺,而是「傾向膨脹」——會自己加上不必要的細節,也分不出畫面上哪些是靜態的;所以它能幫你迭代,但你自己要夠好才用得動它。

AI 產出的資料結構圖與他手推的版本並排,看得出「膨脹」與遺漏在哪
10:10 · AI 產出的資料結構圖與他手推的版本並排,看得出「膨脹」與遺漏在哪
承上 承上:型別是純手工推出來的,主持人接著問——如果允許,這一步能不能交給 AI?

推理因為上一段的推導完全靠手,主持人直接追問可不可以外包給 AI。作者的答案是「可以拿來精煉與腦力激盪,但不能拿來定稿」,而且他有實測:錄影前他把這張 UI 丟給 Claude,第一版回來是一個過度複雜的資料結構,他回了一句「把它簡化」才收斂到接近的版本;他也提到可以直接指定輸出成 diagrams.net 吃得下的格式,截圖裡那份 chart_data / price_ticks 的 DBML 就是這樣來的。但結果跟他手推的版本有落差:AI 把 target_price 併進 chart_data,也漏掉一些欄位。他因此下了一個很精準的判斷——AI 在這裡不太算幻覺,而是「傾向膨脹」:會自己加上不必要的細節,也分不出畫面上哪些是靜態的。

AI 補充值得注意的是 AI 產出的其實是資料庫層的 schema(Table chart_data、Table price_ticks,還帶 decimal(18,2) 與索引),而作者要的是前端的狀態型別。這個落差本身就說明了「膨脹」是怎麼發生的:模型看到金融時間序列,就把整套後端最佳實務都倒出來,而不是回答「這個元件在瀏覽器記憶體裡需要記住什麼」。順帶一提,AI 用 decimal(18,2) 反而比作者手寫的 number 更貼近金融精度需求——所以正確的用法不是「誰對誰錯」,而是把 AI 當成會提出你沒想到的選項的同事,然後由你來砍。作者那句「你自己要夠好才用得動它」講的就是這件事:你得先有能力判斷哪些細節是必要的,膨脹才會變成資產而不是雜訊。

Hallucination

幻覺

語言模型輸出看似合理、實際上沒有依據的內容。

作者刻意把這裡的失敗跟幻覺區分開:模型沒有捏造不存在的事實,它是把「合理但沒被要求」的東西加進來——多了資料庫索引、多了嚴格的精度、少了畫面上真正需要的欄位。這種「過度補全」在設計任務上比幻覺更難察覺,因為每一項單獨看都是好建議。實務上的解法就是作者做的:先要求簡化,再拿實際畫面逐項對照。

相關術語: Stable Artifacts (用來約束模型)

出處:第 5 段「用 AI 幫忙設計 state 的界線」

留給下一段 AI 版本漏掉的正是最底層那個型別——data point 還沒被完整寫出來,得補上。

6. data point 與請求合併的取捨 10:35–11:55

最後補完 data point 這個型別:id(一樣用 UUID)、timestamp(走網路時是字串,之後要 parse)、value(示範用 number,金融場景其實更適合 BigInt),並說明 data series 會裝著一個 data point 陣列——這在資料庫層叫 referential integrity,在前端就是「這批點是跟著這個序列一起來的」。收尾時他再次把選擇丟回給面試官:能不能把 price data 和 data series 併成單一請求?如果對方說隨你,他就併起來,理由是「簡單永遠優於複雜」。

data point 完整型別與它跟 data series 的關聯線,資料模型到此收斂
11:10 · data point 完整型別與它跟 data series 的關聯線,資料模型到此收斂
承上 承上:AI 版本漏掉的最底層型別,這段由作者親手補完。

推理因為上一段指出 AI 的版本缺了資料點的細節,作者回頭把 DataPoint 寫完:id(一樣用 UUID)、timestamp(走網路時是字串,之後要 parse)、value(示範用 number,並再次提到金融場景可能需要更高精度)。接著他說明 DataSeries 裡那個 data_points 陣列在資料庫層叫做 referential integrity,但在前端只需要知道「這批點是跟著這個序列一起送來的」。收尾時他把選擇丟回給面試官:能不能把 price data 與 data series 併成單一請求?如果對方說隨你,他就併——理由只有一句「簡單永遠優於複雜」。截圖 s07_760 就是併完之後的最終型別:DataSeries 裡同時裝著 start、end、label、price_to_beat、price_target 與 data_points。

AI 補充「一次請求還是兩次請求」看起來是小事,實際上是這場面試裡少數會被追問到底的地方,因為它同時牽涉三件事:後端資料是不是存在同一張表(影響能不能一次撈)、兩份資料的更新頻率是否相同(影響能不能共用快取策略)、以及前端要不要處理「部分載入成功」的狀態。作者選擇合併是為了讓 loading / error 只有一組,這會讓後面的狀態形狀乾淨很多。另外補一個型別上的細節:他寫的 id: uuid 在 TypeScript 裡並不存在這個型別,實務上要嘛就寫 string,要嘛用 branded type(type UUID = string & { __brand: 'uuid' })拿到編譯期保護。白板上這樣寫沒問題,因為意圖清楚;但如果面試官追問,能講出 branded type 會是加分。

Referential Integrity

參照完整性

資料庫層的約束,保證外鍵指到的那筆資料一定存在。

截圖裡 AI 產的 DBML 就寫了 chart_id varchar [ref: > chart_data.id],那就是參照完整性的宣告。作者的重點是提醒你分清楚層次:這是後端的保證,前端拿到的只是一個已經組好的巢狀物件。前端真正對應的問題是「正規化還是巢狀」——像 Redux 那種扁平化正規化 store 適合多處共用同一實體,而這種一次請求、一個元件用的資料留成巢狀更簡單。

相關術語: UUID (常作為外鍵)

出處:第 6 段「data point 與請求合併的取捨」

留給下一段 資料的「形狀」定完了,但還沒回答它「怎麼變」——狀態轉移是下一個里程碑。

7. 狀態轉移與狀態管理選型 11:55–14:45

資料的「形狀」定完,接著是狀態轉移。他給了一條掃描規則:前端改變狀態只有兩個原因——後端來的資料,或使用者事件;他固定先做後端那條,因為最單純。落地頁要 fetch data series,於是狀態變成 data / loading / error 三件套。使用者這邊是點選不同時間區間,會改動 start date 與 end date,而且改完要重新觸發 fetch,圖才會跟著換。最終狀態就是「有初始值的 start/end date」加上「與後端同步的 data series + loading + error」。選型上他判斷這些狀態都在元件層級,用 useState 就夠,不需要全域狀態;唯一值得引進的是 TanStack 這類外部函式庫,直接拿現成的資料抓取 hook,不必自己重造輪子。框架則假設用 React,因為最普遍、也是對方的技術棧。

白板上寫下 data / loading / error 三態,這是所有後端同步狀態的固定形狀
12:40 · 白板上寫下 data / loading / error 三態,這是所有後端同步狀態的固定形狀
最終狀態清單成形:start/end date 加上三態,看得到狀態轉移箭頭
13:50 · 最終狀態清單成形:start/end date 加上三態,看得到狀態轉移箭頭
承上 承上:資料的形狀定完了,這段回答它怎麼變。

推理因為上一段只交出了靜態的型別,作者接著給出一條掃描規則:前端會改變狀態只有兩個原因——後端送來資料,或使用者做了事情。他固定先掃後端那條,因為最單純:落地頁要 fetch data series,於是狀態變成 data / loading / error 三件套(截圖 s07_830 上那行 [data: DataSeries, loading, error] 就是這個)。再掃使用者事件:可以點的時間區間會改動 start_date 與 end_date,而且改完必須重新觸發 fetch,圖才會跟著換。最終狀態因此只有兩組:一組是有初始值的 {start_date, end_date},一組是跟後端同步的三件套。選型上他判斷這些狀態都在元件層級,useState 就夠,不需要全域狀態;唯一值得引進的是 TanStack 這類函式庫,直接用現成的資料抓取 hook,不必自己重造輪子。框架則假設 React——最普遍,也是對方的技術棧。

AI 補充「先掃後端、再掃使用者事件」這條規則之所以有效,是因為它把狀態來源窮舉了:任何一個你想不出屬於哪一類的變數,八成就是衍生狀態。另外請注意作者在這裡跳過了一步:他說使用者點區間會「觸發 fetch」,但沒說這代表 start_date / end_date 其實是查詢的參數,而 data / loading / error 是那個查詢的結果——兩者是因果關係,不是並列的兩份狀態。認清這點,TanStack Query 的角色就自然了:你把 [start_date, end_date] 當成 queryKey,其餘的載入、錯誤、重試、快取全部由它托管,你自己一份狀態都不用寫。這也直接解釋了後面談快取時為什麼他還會回頭找 TanStack——因為 queryKey 一旦定好,快取就是免費的。

State Transition

狀態轉移

狀態從一個值變成另一個值的那個動作,以及觸發它的事件。

作者的窮舉法很實用:前端的狀態轉移來源只有「後端同步」與「使用者事件」兩類(嚴格說還有第三類:計時器等時間驅動的事件,這支影片裡就是 SSE 推來的新資料點)。把轉移畫成圖不只是為了溝通——他後面會說,狀態圖是餵給 coding agent 的穩定錨點之一。

相關術語: State (作用的對象)

出處:第 7 段「狀態轉移與狀態管理選型」

useState

React 的狀態 Hook

React 內建的 Hook,在函式元件裡宣告一份屬於該元件的狀態。

作者的選型判準是「狀態的作用範圍」:只有這個元件與它的子樹會用到,就留在元件裡;跨頁面、跨模組共用才需要 Context 或全域狀態庫。面試中很容易犯的錯是反射性地說 Redux/Zustand,卻說不出為什麼——把作用範圍講出來就贏了。

相關術語: TanStack Query (補足伺服器狀態)

出處:第 7 段「狀態轉移與狀態管理選型」

TanStack Query

TanStack 查詢函式庫

管理「伺服器狀態」的函式庫,把抓取、載入與錯誤狀態、重試、快取、失效重抓包成一組 hook。

它的核心觀念是把資料分成兩種:你自己擁有的客戶端狀態(表單輸入、開關)和你只是暫存一份副本的伺服器狀態。伺服器狀態不該用 useState 手寫同步,因為你會被迫自己處理過期、重試、競態、快取。原名 React Query,改名後同時支援 Vue、Svelte、Solid、Angular,所以作者才說它在各家框架都有。

相關術語: useState (分工不同)、HTTP Caching (客戶端對應層)

出處:第 7 段「狀態轉移與狀態管理選型」

留給下一段 狀態的形狀與轉移都定了,可以往下談「這東西實際上怎麼做出來」的實作細節。

8. 最小可行前端:框架、設計系統、CSS、無障礙 14:45–17:00

有了狀態就能往實作細節走。他先問怎麼交付:這是塞進現有 SPA 的元件,還是要進設計系統?如果要重用,就得問「不同實例之間會變的是什麼」——他判斷是資產本身,所以 props 至少要能收 asset name,再據此抓對應的 data series。接著他一條條記下最小可行前端:框架用 React;問對方有沒有設計系統與 design token(顏色、字體這類最小設計單位),沒有就自己定;CSS 用 CSS Modules 避免全域衝突,但要先問他們是不是用 Tailwind 這類 atomic CSS;無障礙則以語意化 HTML 為主,並確保畫面上的順序就是 JSX 標記裡的順序。

白板上「最小可行前端」的四條清單(框架 / 設計系統 / CSS / a11y),是這階段的交付物
16:15 · 白板上「最小可行前端」的四條清單(框架 / 設計系統 / CSS / a11y),是這階段的交付物
承上 承上:狀態的形狀與轉移定了,這段開始談「實際上怎麼做出來」。

推理因為狀態已經穩定,作者才允許自己往實作細節走。他先問交付形式:這是塞進現有 SPA 的元件,還是要進設計系統?這個問題會決定 API 設計——如果要重用,就得問「不同實例之間會變的是什麼」,他判斷是資產本身(BTC、ETH…),所以 props 至少要能收 asset name,再據此抓對應的 data series。接著他在白板左下角列出一張編號清單(截圖 s08_975 與 s09_1070 可以看到它逐條長出來):1. React.js;2. 有沒有設計系統與 design token,沒有就自己定;3. CSS 用 CSS Modules 避免全域衝突,但要先問對方是不是用 Tailwind 這類 atomic CSS;4. 無障礙以語意化 HTML 為主,並確保畫面上的視覺順序就是 JSX 標記裡的順序。他把這張清單稱為「最小可行前端」。

AI 補充「畫面順序等於標記順序」這句話值得展開,因為它是無障礙裡最常被違反、也最容易在面試中講出深度的一點:螢幕閱讀器與鍵盤 Tab 走的是 DOM 順序,而 CSS(flex 的 order、grid 的定位、絕對定位)可以讓視覺順序跟 DOM 順序不一致,於是視覺上「下一個」按鈕在鍵盤上可能要 Tab 十次才到得了。對這支影片的圖表元件來說還有第二層:折線圖對螢幕閱讀器等於一張空白圖片,正確做法是提供一個等價的資料表格,或至少用 aria-label 播報當前價與變化幅度——這是作者提到無障礙卻沒展開的部分。另外「最小可行前端」這個框架的用意是替自己止血:把技術選型一次講完、標記為已決定,才不會在後半場被拉回來爭論 Tailwind 好不好。

Design System

設計系統

一組共用的元件、樣式與規範,讓不同團隊做出來的介面長得一致、行為一致。

在系統設計面試裡它有雙重身分:一是決定你要不要把這個圖表包成可重用元件(會牽出版本管理、Storybook、跨專案發佈),二是它的 CSS 比應用程式本身穩定得多,這個性質稍後在快取那段會被直接利用。作者後面還會把它列為餵給 coding agent 的穩定錨點之一。

相關術語: Design Token (最小構成單位)

出處:第 8 段「最小可行前端:框架、設計系統、CSS、無障礙」

Design Token

設計代幣

設計系統裡最小的具名單位——顏色、字級、間距、圓角等,以變數形式被程式碼引用。

它的價值是把「換主題」「符合品牌」「支援深色模式」變成改一組變數而不是改幾百個元件。落地形式通常是 CSS 自訂屬性或建置期產生的常數。面試中提到 design token 等於表態:你打算讓樣式可被集中治理,而不是每個元件各寫各的色碼。

相關術語: Design System (隸屬於)

出處:第 8 段「最小可行前端:框架、設計系統、CSS、無障礙」

CSS Modules

CSS 模組

在建置期把 class 名稱加上雜湊、讓每個檔案的樣式自動具備區域作用域的機制。

它解決的是全域命名衝突,做法是編譯期改名,執行期沒有任何額外成本,產出的仍是一般的 .css 檔——這一點在後面談快取時很關鍵,因為它能被獨立快取。它跟 CSS-in-JS(styled-components、Emotion)的差別就在這裡:後者在執行期把樣式注入文件。跟 Tailwind 這類 atomic CSS 的差別則是命名哲學:CSS Modules 仍然是你自己寫語意化 class,Tailwind 是把樣式拆成工具類寫在標記裡。

相關術語: Design Token (常一起使用)

出處:第 8 段「最小可行前端:框架、設計系統、CSS、無障礙」

Semantic HTML

語意化 HTML

用具有語意的標籤(button、nav、table、h1)表達內容的角色,而不是一律用 div。

語意化標籤自帶鍵盤操作、焦點管理與無障礙角色,等於免費拿到一大半的可及性;用 div 加 onClick 模擬按鈕則要自己補 role、tabindex、Enter/Space 處理,而且很少有人補齊。作者說的「畫面順序等於 JSX 順序」跟它是同一件事的兩面:語意正確 + 順序正確,螢幕閱讀器才走得通。

相關術語: Non-Functional Requirements (落實無障礙)

出處:第 8 段「最小可行前端:框架、設計系統、CSS、無障礙」

留給下一段 清單走到第五項就是建置工具,而一旦談建置工具,就得回答「AI 在寫大部分程式碼時,品質靠什麼守住」。

9. 建置工具與 AI 時代的程式碼品質 17:00–19:35

建置工具他會先問對方現在用什麼:傳統是 webpack,但現在多半用 Vite(最好上手又快)或 esbuild;如果對方有既有 webpack 設定又想要速度,可以換 Rspack(用 Rust 重寫的 webpack)。CSS 也要有對應的建置管線(SASS?CSS Modules?styled-components?)。程式碼品質他分兩層:靜態品質是 TypeScript(型別檢查不容妥協)、linter(相容性最好是 ESLint,但 oxlint 快非常多)、以及 Prettier——他強調 Prettier 在 agent 寫程式的時代特別重要,因為 agent 產的 PR 動輒六千行,大家格式與寫法一致,PR 才會小、才 review 得動。動態品質就是把程式跑起來,也就是測試:先讓 agent 列計畫、分析邊界情況,再寫元件測試,然後補端到端測試——coding agent 寫這些很快。

建置工具與程式碼品質的清單(Vite / TS / lint / Prettier / 測試)畫在白板上
17:50 · 建置工具與程式碼品質的清單(Vite / TS / lint / Prettier / 測試)畫在白板上
承上 承上:最小可行前端的清單走到建置工具,而這一項直接連著「AI 寫程式時品質靠什麼守住」。

推理因為清單的第五項就是建置工具,作者先問對方現在用什麼:傳統是 webpack,現在多半是 Vite(最好上手又快)或 esbuild;如果對方有既有的 webpack 設定又想要速度,可以換 Rspack,也就是用 Rust 重寫的 webpack。CSS 也要有對應的建置管線。接著主持人把問題導向「既然假設用 AI 寫這個專案,品質怎麼守」,作者把答案分成兩層。靜態品質是不執行程式就能查的:TypeScript 型別檢查沒得商量;linter 相容性最好的是 ESLint,但 oxlint 快非常多;Prettier 則被他特別強調——因為 agent 產的 PR 動輒六千行,唯有格式與寫法一致,diff 才會小到 review 得動。動態品質就是把程式跑起來,也就是測試:先讓 agent 列計畫、分析邊界情況,再寫元件測試,然後補端到端測試,而 coding agent 寫這些特別快。截圖 s10_1225 上那份「6. Code Quality → Static / Dynamic」就是這段的成果。

AI 補充這段最值得帶走的是它把 Prettier 的價值重新定位了。過去 Prettier 被當成品味問題(少吵架、省時間),在 agent 寫程式的情境下它變成 review 的可行性問題:人類 review 的瓶頸是 diff 的行數,而風格不一致會讓實質改動被格式噪音淹沒。同樣的邏輯也適用於 lint 規則與檔案結構——你不是在管束人類,而是在替模型設定一個窄的輸出空間。作者沒有明說但邏輯上緊接著的是:這正是他後面「穩定錨點產物」那套主張的前身,兩者都在做同一件事——把模型可以自由發揮的維度壓小。另外補一點他跳過的:靜態品質還缺一個 CI 閘門,型別檢查與 lint 只有在 pull request 上強制執行時才真的有效,否則 agent 可以直接繞過。

Vite

Vite 建置工具

現代前端建置工具,開發時用原生 ES modules 免打包、正式建置時走打包流程。

它快的原因是開發階段不預先打包整個應用,瀏覽器要哪個模組才即時轉譯(底層用 esbuild),所以冷啟動幾乎是常數時間。作者推薦它的理由是「最容易上手」——這在面試裡是好答案,因為建置工具的選擇本來就該用團隊成本而不是效能數字來論證。

相關術語: Rspack (另一條升級路)

出處:第 9 段「建置工具與 AI 時代的程式碼品質」

Rspack

Rspack 打包器

用 Rust 重寫、刻意相容 webpack 設定與 loader/plugin 生態的打包器。

它存在的理由很單純:既有的大型 webpack 設定遷移到 Vite 成本高,而 Rspack 讓你幾乎不改設定就拿到數倍速度。作者在影片裡把名字唸得含糊(聽起來像 espack),但白板上寫的是 rspack。選型判準因此很清楚:新專案 Vite,舊 webpack 專案想要速度就 Rspack。

相關術語: Vite (對照組)

出處:第 9 段「建置工具與 AI 時代的程式碼品質」

oxlint

oxlint 檢查工具

Oxc 專案用 Rust 寫的 JavaScript/TypeScript linter,強調速度。

它比 ESLint 快一到兩個數量級,代價是規則覆蓋率與插件生態還不及 ESLint,所以常見做法是兩者並用:oxlint 跑在存檔與 pre-commit(要即時),ESLint 跑在 CI(要完整)。作者在影片裡也是憑印象講出名字的,但推薦理由(快很多)是站得住的。

相關術語: Prettier (分工:品質 vs 格式)

出處:第 9 段「建置工具與 AI 時代的程式碼品質」

Prettier

Prettier 格式化工具

有主見的程式碼格式化工具,直接重寫排版,不提供太多可調選項。

它跟 linter 的分工是:linter 管「這樣寫對不對」,Prettier 管「長什麼樣」。刻意不給太多選項就是它的設計目的——把爭論成本降為零。在 agent 寫程式的情境下它的角色升級了:統一格式讓 diff 只剩下實質改動,是六千行 PR 還 review 得動的前提。

相關術語: oxlint (分工:格式 vs 品質)

出處:第 9 段「建置工具與 AI 時代的程式碼品質」

End-to-End Test

端到端測試

用真實瀏覽器操作整個應用,驗證從使用者動作到畫面結果的完整流程。

跟元件測試的差別是覆蓋範圍與成本:元件測試快、定位精準,但測不到路由、真實網路與跨頁流程;端到端測試慢又脆弱,但它是唯一能證明「整條路真的走得通」的東西。實務比例通常是大量元件測試加少量關鍵路徑的 E2E。作者強調的順序也很重要:先讓 agent 列計畫、窮舉邊界情況,再寫測試——直接叫模型「寫測試」通常只會得到重複斷言的樣板。

相關術語: Code Review Agent (互補的品質關卡)

出處:第 9 段「建置工具與 AI 時代的程式碼品質」

留給下一段 功能面與工程面都收乾淨了,接下來輪到被擱置最久的那一欄——非功能性需求裡的效能。

10. Web 效能的三個維度 19:35–21:55

確認面試官買單後,他主動把話題帶到非功能性需求,先攻 web 效能與可擴展性,並點出資淺與資深的差別就在「顆粒度」:junior 會丟一句「那就 code splitting」或「架個 CDN」就沒了;senior 會先攤開三個維度——載入速度、對使用者輸入的反應速度、版面穩定性——再逐一探問它們各有多重要。以載入速度為例,他問這是不是公開頁面、SEO 重不重要、流量會不會很大;判斷會很大之後才進到手段:先做 bundle splitting 只載入需要的 JavaScript;再看 UI 周邊有大量靜態內容,適合 SSR,只動態渲染圖表與數字,其餘預先渲染——這同時也把 CLS(累積版面位移)壓下來,因為東西已經先渲染好了,甚至可以把預設區間也一起預渲染,讓初始畫面很快出現、只是還不能互動。

白板寫出效能三維度(loading / interaction / layout stability),這是 senior 式回答的骨架
20:25 · 白板寫出效能三維度(loading / interaction / layout stability),這是 senior 式回答的骨架
SSR 與預渲染範圍圈在 UI 上:哪塊靜態預渲染、哪塊動態,直接對應 CLS
21:35 · SSR 與預渲染範圍圈在 UI 上:哪塊靜態預渲染、哪塊動態,直接對應 CLS
承上 承上:工程面收乾淨後,輪到開頭就掛號、一直沒展開的非功能性需求——效能。

推理因為前面已經取得面試官對功能面的認可,作者主動把話題帶去效能與可擴展性,並先點出資淺與資深的差別在於顆粒度:junior 丟一句「那就 code splitting」或「架個 CDN」就沒了;senior 會先攤開三個維度——載入速度、對使用者輸入的反應速度、版面穩定性——再逐一探問它們各有多重要。他以載入速度示範這種探問:這是公開頁面嗎?SEO 重要嗎?流量會很大嗎?判斷「這種小工具會出現在很多地方、流量很大」之後才進到手段:第一是 bundle splitting,只載入需要的 JavaScript;第二是既然元件周圍有大量靜態內容,適合用 SSR,只動態渲染圖表與數字,其餘預先渲染,而這同時把 CLS 壓下來;甚至可以連預設時間區間也一起預渲染,讓初始畫面很快出現,只是還不能互動。

AI 補充這三個維度不是隨口列的,它們一一對應 Core Web Vitals:載入速度是 LCP,對輸入的反應是 INP,版面穩定是 CLS。把這件事講出來,你的回答就從「我知道幾個名詞」變成「我有一個可量測的框架」。作者的提問順序也值得學:先問使用情境(公開?SEO?流量?),再選手段——因為同樣是效能,公開頁面在意首屏與 SEO,而登入後的內部儀表板在意的是互動延遲,手段完全不同。至於「先出現、還不能互動」那句,指的是 SSR 與 hydration 之間的空窗:HTML 已經在畫面上,但 JavaScript 還沒接手,這段期間點擊沒有反應——這正是 INP 與 TTI 這類指標要抓的東西,也是 React Server Components 與 streaming SSR 想縮短的區間。

Bundle Splitting

打包切分

把打包產物切成多個檔案,讓瀏覽器只載入當前畫面真正需要的那幾塊。

常見切法有三種:依路由切(進哪一頁載哪一頁)、依元件切(動態 import 昂貴的圖表或編輯器)、把很少變動的第三方函式庫獨立成 vendor chunk 以提高快取命中。對這支影片的圖表元件來說,第二種最相關:圖表函式庫通常又大又只在這一塊用到。切太碎也有代價——請求數變多、共用模組重複,所以要看實際的載入瀑布圖決定。

相關術語: CDN (配送這些檔案)

出處:第 10 段「Web 效能的三個維度」

SSR

伺服器端渲染

在伺服器先把 HTML 產生好送給瀏覽器,而不是送空殼再由 JavaScript 生成畫面。

它主要買到兩件事:首屏內容更早出現(LCP 變好)、爬蟲不用執行 JavaScript 就能讀到內容(SEO)。代價是伺服器成本、以及 hydration 期間畫面已經在但還不能互動。跟 SSG 的差別在時機:SSG 是建置時就產生好靜態 HTML,適合不常變的內容;SSR 是每次請求現產,適合像這種每次數字都不同的頁面。

相關術語: CLS (可一併改善)

出處:第 10 段「Web 效能的三個維度」

CLS

累積版面位移

Core Web Vitals 之一,量測頁面載入過程中內容非預期跳動的累積程度。

常見肇因是沒有預留高度的圖片與廣告、晚載入的字體造成重排、以及資料回來後才長出來的區塊——最後這項正是圖表元件的典型問題。真正的解法是替容器保留固定尺寸(aspect-ratio 或明確高寬),SSR 只是把內容提早放上去,並不保證不跳動。

相關術語: Core Web Vitals (屬於其中)

出處:第 10 段「Web 效能的三個維度」

見仁見智 21:31
「There will be no layout shifts because we already preloaded this」
SSR 能減少版面位移,但不等於「不會有」。hydration 前後的差異、晚載入的網頁字體造成的重排、以及圖表函式庫在客戶端算完尺寸後才調整容器,都還是會產生 CLS。真正的保證來自替容器預留固定尺寸(明確的高度或 aspect-ratio)與 font-display 策略,SSR 只是讓內容更早就位。
依據: web.dev CLS 最佳實務:Always include size attributes on images and video elements, or reserve space with CSS aspect-ratio
留給下一段 前端這側的手段講完了,但流量真的上來時瓶頸會落在後端——那該怎麼辦?

11. BFF:讓介面穩定下來 21:55–23:55

主持人指出前端的可擴展性其實單純(CDN、靜態資產、bundle 一發就到使用者手上),瓶頸會在後端,於是問 BFF 該不該上。他的判準是:看資料來源、以及拿到的形狀跟想要的形狀差多少;如果落差很大,或那個服務不是我們擁有、又常改 API,就用 BFF 當前端的穩定介面——服務改了只要改 BFF,前端不用動。他再補一個現代理由:用 coding agent 時,穩定介面讓大規模的根因分析可行,出事能靠 AI 快速定位;反之如果每次改動都橫跨所有系統、每個 PR 都在動所有東西,就會非常混亂不穩。主持人為觀眾補充定義:BFF 是加在 API 與前端之間、用來吸收變動的中介層;作者補充它可以是 REST 或獨立的 GraphQL,往下游取資料再回傳,也就是反向代理。

前端 →BFF→ 資料服務的方框圖,看得到「哪一條介面保持穩定」
22:50 · 前端 →BFF→ 資料服務的方框圖,看得到「哪一條介面保持穩定」
承上 承上:前端這側的效能手段講完,剩下的瓶頸在後端——這段回答那一半。

推理因為主持人指出前端的可擴展性其實單純(CDN、靜態資產、bundle 一發就到使用者手上),真正的瓶頸會在後端,於是問 BFF 該不該上。作者的判準有兩條:一是拿到的資料形狀跟想要的形狀差多少,二是那個服務是不是我們擁有、會不會常改 API。落差大或不受控時就用 BFF 當前端的穩定介面——資料服務改了只要改 BFF,前端不用動(截圖 s11_1370 那張 FE → BFF → 資料服務的方框圖畫的就是這個)。他接著補了一個現代理由:用 coding agent 時,穩定介面讓大規模的根因分析變得可行,出事能靠 AI 快速定位;反之如果每次改動都橫跨所有系統、每個 PR 都在動所有東西,就會非常混亂不穩。主持人替觀眾補上定義(加在 API 與前端之間、吸收變動的中介層),作者補充它可以是 REST 或獨立的 GraphQL,往下游取資料再回傳,也就是反向代理。

AI 補充把 BFF 的理由講成「形狀落差 + 變更頻率 + 所有權」是這段最有用的部分,因為它讓你能回答反方向的問題:什麼時候不該上 BFF?答案是資料形狀本來就貼合、服務由自己團隊擁有時——那時多一層只是多一個要部署、要監控、要在 on-call 時被叫醒的東西。作者沒提到但實務上同樣重要的兩個 BFF 好處是:把 API 金鑰與權杖留在伺服器端(前端不必持有機密),以及把多次下游請求收斂成一次(省掉行動網路上的往返延遲)。至於「穩定介面讓 AI 好除錯」那個論點,本質上跟他前面說的 Prettier 是同一招——都是在替模型縮小需要理解與改動的範圍。

BFF

為前端而生的後端

專為某個前端應用而存在的後端層,負責把下游服務的資料轉換成該前端最好用的形狀。

Backend For Frontend 的核心是所有權:這一層由前端團隊擁有與部署,所以能跟著 UI 的節奏改,不必排進下游服務的排程。典型用途是聚合多個服務的回應、裁掉用不到的欄位、隱藏機密、以及在下游 API 改版時充當緩衝。代價是多一個部署單元與一段延遲,所以只有在形狀落差大或下游不受控時才划算。

相關術語: Reverse Proxy (實作型態之一)、GraphQL (可能的實作)

出處:第 11 段「BFF:讓介面穩定下來」

Reverse Proxy

反向代理

代替後端接收客戶端請求、再轉發到真正的服務並把回應帶回來的中介伺服器。

跟正向代理(幫客戶端出去)方向相反:反向代理站在伺服器那一側,客戶端根本不知道背後有幾台機器。除了轉發,它通常還兼做 TLS 終止、負載平衡、快取與限流。作者說 BFF「就是一種反向代理」是在強調它的位置,但兩者職責不同:反向代理多半只轉發不改內容,BFF 的價值恰恰在於改變資料形狀。

相關術語: CDN (同屬邊緣層)

出處:第 11 段「BFF:讓介面穩定下來」

GraphQL

GraphQL 查詢語言

由客戶端在單一端點宣告需要哪些欄位,伺服器只回傳那些欄位的 API 查詢語言。

它天然解決 BFF 想解決的兩個問題:過度取得(多回一堆用不到的欄位)與取得不足(要打三次 API 才湊齊一個畫面)。代價是伺服器端複雜度、快取比 REST 難做(因為都是同一個 POST 端點),以及要防範惡意的深度巢狀查詢。在這場面試裡,用 REST 或 GraphQL 實作 BFF 都可以,判準是團隊熟悉度與下游服務數量。

相關術語: BFF (常用於實作)

出處:第 11 段「BFF:讓介面穩定下來」

留給下一段 資料怎麼來的路徑定了,但還沒回答那條路徑上「即時更新」要用什麼協定送。

12. 即時更新:SSE,以及把狀態壓到最小 23:55–27:25

回到即時更新,他先問通訊是不是真的雙向,再比三種做法。輪詢(polling)最穩健,但擴展性極差:大量客戶端一起輪詢等同於對自家後端發動 DDoS,一個畫面上有十個這種元件、每兩秒更新一次,單一使用者就是每兩秒十個請求。WebSocket 實作複雜且是雙向的,適合聊天那種客戶端也要送資料回去的場景,但這裡前端只需要重繪,不需要把資料反映給其他客戶端。所以他選 Server-Sent Events——現在多數 LLM 應用都在用的原生 API,監聽一個 URL、持續收事件塊,事件的形狀就是 data point。收到新點之後在應用層做狀態更新:把點推進 data series。接著他處理畫面上看似很多事同時發生的部分(圖在動、區間在移、當前價在跳、還有一堆增減數字),逐一拆解後發現全都能從那一個新資料點推出來:用新點的 timestamp 更新區間、更新當前價、差值只要記住「你進頁面時的起點」再相減、時間也是進頁面的時間。結論是他不需要額外狀態,一個新資料點就能重繪整塊——狀態要保持越小越好。

polling 的請求流向圖,配合「等於自己 DDoS 自己」的說明
24:25 · polling 的請求流向圖,配合「等於自己 DDoS 自己」的說明
SSE 的事件流與事件形狀(就是 data point),三選一的結論落在這張圖
25:20 · SSE 的事件流與事件形狀(就是 data point),三選一的結論落在這張圖
把畫面上多個動態元素逐一標回同一個新資料點——最小狀態推導的關鍵畫面
26:30 · 把畫面上多個動態元素逐一標回同一個新資料點——最小狀態推導的關鍵畫面
承上 承上:資料路徑定了,這段回答那條路徑上的即時更新該用什麼協定送。

推理因為上一段留下的問題是即時更新,作者先把判準立起來——通訊是不是真的雙向——再比三種做法。輪詢最穩健,但擴展性極差:大量客戶端一起輪詢等於對自家後端發動阻斷服務攻擊,一個畫面上放十個這種元件、每兩秒更新一次,單一使用者就是每兩秒十個請求。WebSocket 實作複雜而且是雙向的,適合聊天那種客戶端也要送資料回去、還要反映給其他客戶端的場景;但這裡前端只需要重繪,沒有要送任何東西回去。所以答案落在 Server-Sent Events——現在多數 LLM 應用都在用的原生 API,監聽一個 URL、持續收事件塊,事件的形狀就是 DataPoint,收到後在應用層把它推進 data series。接著他處理畫面上看似同時發生的一堆事(折線在長、區間在移、當前價在跳、左側還有一疊 +$35、+$99 的增減數字),逐一拆解後發現全都能從那一個新資料點推出來:用新點的 timestamp 更新區間、更新當前價,差值只要記住「你進頁面時的起點」再相減,時間也是你進頁面的時間。結論是他不需要任何額外狀態。

AI 補充SSE 在這裡是正確答案,但值得補上它的實際限制,因為面試官很可能追問:HTTP/1.1 下每個網域同時只有六個連線,而一個 SSE 連線會一直佔著,所以「一頁十個圖表各開一條 SSE」會直接卡死——真正的解法是共用一條連線並在事件裡帶 asset id 分流,或走 HTTP/2 讓多條流共用同一個 TCP 連線。另外 SSE 只能傳文字(要傳二進位得先編碼)、瀏覽器會自動重連並用 Last-Event-ID 續傳,這個自動重連正是它比手寫輪詢好的地方。至於最後那段狀態最小化的推理,可以總結成一句可以帶走的規則:如果一個畫面元素能從「一份基準」加「當前值」算出來,那就只存基準與當前值。這也解釋了他為什麼要把「你進頁面的那一刻」單獨記下來——那就是基準,而不是把每一筆差值都存成陣列。

Polling

輪詢

客戶端每隔一段固定時間就主動向伺服器問一次「有沒有新資料」。

它的優點是實作簡單、走一般的 HTTP、任何基礎設施都支援;缺點是延遲與負載互相拉扯——間隔短則負載爆炸,間隔長則資料過時,而且絕大多數請求的回應是「沒有新東西」,等於白花。介於輪詢與推送之間還有長輪詢(long polling):伺服器把請求掛住直到有資料才回應,SSE 普及前的即時方案多半是這樣做的。

相關術語: Server-Sent Events (被取代)、DDoS (規模化後的效果)

出處:第 12 段「即時更新:SSE,以及把狀態壓到最小」

WebSocket

WebSocket 協定

在單一 TCP 連線上建立的全雙工通訊協定,雙方都能隨時主動送訊息。

它從一個 HTTP 升級請求開始,之後就脫離 HTTP 的請求/回應模型,所以也失去了 HTTP 的快取、狀態碼與大部分中介設施支援;斷線重連、心跳、訊息順序都要自己處理。判準很單純:客戶端需不需要主動推送。聊天、協作編輯、多人遊戲需要;儀表板、股價、AI 串流回應不需要——那些用 SSE 就夠。

相關術語: Server-Sent Events (單向的替代)

出處:第 12 段「即時更新:SSE,以及把狀態壓到最小」

Server-Sent Events

伺服器推送事件

瀏覽器原生的單向推送機制:客戶端用 EventSource 監聽一個 URL,伺服器持續送出文字事件。

它走的仍是一般 HTTP(Content-Type 是 text/event-stream),所以代理、認證、壓縮這些既有設施都能用;瀏覽器還會自動重連,並用 Last-Event-ID 標頭告訴伺服器該從哪裡續傳。限制是只能單向、只能傳文字,而且 HTTP/1.1 下會佔用網域的連線額度。ChatGPT、Claude 這類逐字串流的介面用的就是它——這也是作者說「多數 LLM 應用都在用」的意思。

相關術語: WebSocket (雙向的替代)、Polling (取代對象)

出處:第 12 段「即時更新:SSE,以及把狀態壓到最小」

DDoS

分散式阻斷服務攻擊

從大量來源同時對同一個目標送出請求,把它的資源耗盡而無法服務正常使用者。

作者這裡是借用它來形容自家客戶端造成的效果:行為模式跟攻擊一樣(大量來源、同時、高頻),只是沒有惡意。這種「自己打自己」在同步輪詢時特別嚴重,因為所有客戶端的計時器容易對齊而形成尖峰——常見的緩解是加隨機抖動(jitter)與指數退避,但真正的解法還是改用推送。

相關術語: Polling (由此引發)

出處:第 12 段「即時更新:SSE,以及把狀態壓到最小」

留給下一段 資料怎麼來、怎麼更新都定了;剩下的問題是哪些資料根本不必再拿一次。

13. 快取:用讀寫比決定快取什麼 27:25–31:00

主持人補問快取,他先給判準:看資源的讀寫比(read/write ratio)——讀遠多於寫就值得快取,而且這條規則要套用到系統裡的每一樣東西。靜態資產(JS、CSS)用 CDN 推到邊緣節點,再配合有效的快取政策。設計系統的 CSS 比應用其他部分穩定得多,讀多寫少,所以值得把它從 bundle 裡拆出來獨立成檔——這時就得深入建置工具,因為 CSS-in-JS 那類做法會把 style 標籤塞進 HTML,跟文件耦合在一起,根本沒辦法快取。動態資料這邊,他指出圖表資料有個很好用的性質:過去的資料是唯讀的,昨天的股價沒有人會回頭改寫,所以所有已成為過去的資料點都能套很積極的快取政策。他因此做 HTTP 快取(大家共用同一份、也快取在客戶端),再加上客戶端狀態快取——TanStack 可以針對特定請求自訂快取政策,把已經拿過的區間或資料點存在客戶端,切換區間時完全不必回伺服器。唯一不能快取的就是 SSE 送來的未來資料。最後補上框架層級的 use cache、useMemo 這類優化避免重繪。

讀寫比與快取層級的清單(CDN / 設計系統 CSS / HTTP / client state)
28:20 · 讀寫比與快取層級的清單(CDN / 設計系統 CSS / HTTP / client state)
在時間軸上把「過去=唯讀可快取」與「未來=SSE 不可快取」切開的那張圖
29:50 · 在時間軸上把「過去=唯讀可快取」與「未來=SSE 不可快取」切開的那張圖
承上 承上:資料怎麼來、怎麼更新都定了,剩下的問題是哪些資料根本不必再拿一次。

推理因為主持人補問快取,作者先立一條判準再往下套:看資源的讀寫比——被讀的次數遠多於被寫的次數就值得快取,而且這條規則要套用到系統裡的每一樣東西。他分兩層走。靜態資產(JS、CSS)用 CDN 推到邊緣節點,配上有效的快取政策;其中設計系統的 CSS 又比應用其他部分穩定得多,讀多寫少,所以值得從 bundle 裡拆出來獨立成檔——這時就得深入建置工具,因為把樣式塞進 HTML 的 style 標籤等於跟文件耦合,根本沒辦法獨立快取。動態資料這層他抓到一個很漂亮的性質:過去的資料是唯讀的,昨天的股價沒人會回頭改寫,所以所有已成為過去的資料點都能套很積極的快取政策。他因此做 HTTP 快取(大家共用同一份、也快取在客戶端),再加上客戶端狀態快取——TanStack 可以針對特定請求自訂快取政策,把已經拿過的區間存在客戶端,切換區間時完全不必回伺服器。唯一不能快取的是 SSE 送來的未來資料。最後補上框架層級的 use cache、useMemo 這類優化避免重繪。

AI 補充「過去唯讀、未來不可快取」這個切法之所以強,是因為它把快取問題從「要快取多久」變成「這筆資料在時間軸的哪一側」——而後者有明確答案。落實成 HTTP 標頭大概是:已結束區間的資料回 Cache-Control: public, max-age=31536000, immutable;包含當下的區間回 no-store 或極短的 max-age。這裡也要補一個作者略過的難點:包含「現在」的那個區間會不斷變動,最乾淨的做法是把請求依區間邊界對齊(例如一律以整分鐘切段),讓 URL 本身就決定了它是不是已完結——否則每個使用者的 URL 都不一樣,共用快取形同虛設。另外 HTTP 快取與 TanStack 的客戶端快取是兩層不同的東西:前者由瀏覽器與 CDN 執行、跨分頁與重新整理都有效,後者活在記憶體裡、換頁就沒了但可以做樂觀更新與背景重抓,兩者互補而不是二選一。

Read/Write Ratio

讀寫比

一份資源被讀取的次數與被寫入次數的比值,用來判斷快取值不值得。

讀寫比高代表快取命中率高、失效成本低,所以划算;讀寫比低則快取幾乎每次都過期,反而多了失效邏輯的複雜度與資料不一致的風險。作者把它當成通用篩子逐層套用(靜態資產、設計系統 CSS、歷史資料點、未來資料點),這種「一條判準掃全系統」的打法正是他說的資深式回答。

相關術語: HTTP Caching (落實手段)、CDN (落實手段)

出處:第 13 段「快取:用讀寫比決定快取什麼」

CDN

內容傳遞網路

分布在世界各地的邊緣伺服器網路,把靜態內容快取在離使用者近的節點。

它同時買到低延遲(實體距離短、TCP/TLS 握手快)與源站卸載(大部分請求打不到你的伺服器)。要真的發揮效果,檔名必須帶內容雜湊(例如 app.9f2c1b.js)——這樣才能同時設定極長的 max-age 與 immutable,又能在改版時因為 URL 改變而自動失效。這也是為什麼把設計系統的 CSS 獨立成檔會有意義:它的雜湊很少改變,快取幾乎永遠命中。

相關術語: Bundle Splitting (配送其產物)

出處:第 13 段「快取:用讀寫比決定快取什麼」

HTTP Caching

HTTP 快取

用 Cache-Control、ETag、Last-Modified 等標頭,讓瀏覽器與中介節點決定能不能重用先前的回應。

兩種模式要分清楚:max-age 期間內是「新鮮」,完全不發請求;過期後靠 ETag 或 Last-Modified 發條件請求,伺服器回 304 就繼續用舊的(省頻寬但仍有一次往返)。public 與 private 決定 CDN 能不能共用同一份——歷史資料點該用 public,跟使用者有關的資料一律 private。作者說的「大家用同一個版本」指的就是 public 這一半。

相關術語: TanStack Query (另一層快取)

出處:第 13 段「快取:用讀寫比決定快取什麼」

見仁見智 28:37
「they add a style tag in your HTML file」
這個描述適用於 styled-components、Emotion 這類執行期的 CSS-in-JS,不適用於 CSS Modules。CSS Modules 是建置期把 class 名稱雜湊化,產出的仍是獨立的 .css 檔案,完全可以獨立快取——作者的結論(把設計系統的 CSS 拆出來單獨快取)是對的,但他把兩種技術混在同一句話裡講,字面上會誤導。
依據: css-loader / Vite 的 CSS Modules 產出獨立樣式表;styled-components v6 執行期以 <style> 注入
留給下一段 整套架構的技術面到此完備;剩下沒回答的是這一切要用什麼工具、什麼模型做出來。

14. AI 開發工具鏈:模型、harness、審查代理 31:00–35:50

兩個 AI 提問:用什麼模型與工具開發、以及若要整合 AI 應用該怎麼做。他常用 Anthropic 的模型,提到 Opus 4.7 在部分任務相對 4.6 有些退步,Codex 搭 GPT-5.5 也可比較,各有強項。但他強調的重點是:不論用哪個,這些模型都缺乏視覺智能,所以進場前要在程式庫裡準備穩定的「錨點產物」,讓模型只做這些產物之間的內插——設計系統(建構區塊)、狀態圖、以及跟後端往來時的循序圖,等於讓模型 program to interfaces。harness 他建議用原生的:用 Anthropic 模型就用 Claude Code,或用 OpenCode 搭不同模型(通常較便宜、效果差不多且能換模型);但終端介面做進階 code review 很受限,開發與重構時 Cursor 的 agent mode 與 Composer 好用得多,代價是定價較差。成本敏感時他提到 Kimi 2.6 搭 Kimi Code 這類選項;但既然是金融機構,資料限制多,他反而會問對方有沒有本地 AI 的計畫——自架、用 Ollama 跑 Qwen 之類的模型,本機跑 15B 有堪用的效能,只是跟數千億參數的雲端模型差距很大。最後是 code review agent,搭配 Chrome MCP 讓 agent 能自己測自己寫的東西,並用審查代理來摘要 PR、專門掃安全問題與無障礙這類瑣事;審查代理找到 bug 可以把提示直接餵回 coding agent 修好再推回 PR,但要大量監督,否則兩個 agent 會互相修改進入無窮迴圈。

「穩定錨點產物」的三項清單(設計系統 / 狀態圖 / 循序圖),這是他對 AI 缺乏視覺智能的解法
32:35 · 「穩定錨點產物」的三項清單(設計系統 / 狀態圖 / 循序圖),這是他對 AI 缺乏視覺智能的解法
code review agent 與 coding agent 的回饋迴圈,包含會互改的無窮迴圈風險
34:40 · code review agent 與 coding agent 的回饋迴圈,包含會互改的無窮迴圈風險
承上 承上:架構的技術面完備了,這段回答這一切要用什麼工具與模型做出來。

推理因為技術面已經收完,主持人丟出兩個 AI 提問:用什麼模型與工具開發、以及要整合 AI 應用該怎麼做。作者先講模型偏好(他自己主要用 Anthropic 的模型),但立刻把重點轉開——真正的關鍵是這些模型都缺乏視覺智能,所以進場前要在程式庫裡準備穩定的錨點產物,讓模型只做這些產物之間的內插。截圖 s14_1955 上寫得清清楚楚:Stable Artifacts → Design System、State Diagram,接著是 Sequence Diagram(跟後端往來時用)。這就是他說的「program to interfaces」。harness 他建議用原生的:Anthropic 模型就用 Claude Code,或用 OpenCode 搭 OpenRouter 換模型(通常較便宜、效果差不多);但終端介面做進階 code review 很受限,開發與重構時 Cursor 的 agent mode 與 Composer 好用得多,代價是定價較差。成本敏感時他提到 Kimi 這類選項;但既然是金融機構,資料限制多,他反而會問對方有沒有本地 AI 計畫——自架、用 Ollama 跑 Qwen 之類的模型,本機跑 15B 有堪用效能,只是跟雲端大模型差距明顯。最後是 code review agent:搭配 Chrome MCP 讓 agent 能自己測自己寫的東西,並用審查代理摘要 PR、專門掃安全與無障礙這類瑣事;審查代理找到 bug 可以把提示直接餵回 coding agent 修好再推回 PR,但要大量監督,否則兩個 agent 會互相修改進入無窮迴圈。

AI 補充「穩定錨點 + 內插」這個說法值得認真對待,因為它把前面所有段落串成同一件事:設計系統來自最小可行前端那一段,狀態圖來自狀態轉移那一段,循序圖對應資料路徑與 SSE 那幾段——換句話說,這場面試走完的那條路線,產出的正好就是餵給 coding agent 的那組錨點。這也是整支影片最有價值的隱藏論點:系統設計不是「AI 會寫程式後就不用學的東西」,反而是你在 AI 時代唯一需要親自產出的東西。至於他對模型的具體推薦,是 2026 年 5 月當下的快照,換一季就會過時(見下方勘誤);但判準不會過時——資料能不能出境、預算、以及 harness 適不適合做 review,這三個問題永遠都要問。

Stable Artifacts

穩定錨點產物

在程式庫裡刻意保持穩定、供 AI 依循的具體產出,例如設計系統、狀態圖、循序圖。

它的作用是把模型的自由度壓小:兩端固定,模型只需要做中間的內插,而不是從零想像整個架構。這跟前面 Prettier 與 BFF 穩定介面是同一個思路的三種應用——縮小模型(或人類)需要理解與改動的範圍。實務上還可以加上 API schema(OpenAPI/GraphQL SDL)與型別定義,它們同樣是機器可讀的錨點。

相關術語: Sequence Diagram (其中一種)、Design System (其中一種)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

Harness

代理外殼

包住語言模型、負責提供工具、讀寫檔案、執行指令與管理上下文的那層程式,例如 Claude Code、Cursor、OpenCode。

同一個模型換一個 harness,實際表現可以差很多,因為決定成敗的是它怎麼檢索程式碼、怎麼壓縮上下文、允許執行哪些工具。作者的取捨很實際:終端型 harness 適合讓 agent 自己跑指令與測試,圖形化的 Cursor 適合人類要逐段審閱 diff 的場景;而模型公司自家的 harness 通常比第三方便宜,因為第三方要照 API 價格加成。

相關術語: MCP (擴充工具的方式)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

MCP

模型上下文協定

Model Context Protocol,讓 AI 應用以統一介面連接外部工具與資料來源的開放協定。

它的意義是把「每個工具各寫一套整合」變成「工具實作一次、任何支援 MCP 的 harness 都能用」。作者提到的 Chrome MCP 就是讓 agent 能開瀏覽器、點畫面、看結果,於是它可以自己驗證剛寫的 UI——這對缺乏視覺智能的模型是重要補償。他那句「要小心」也是對的:能操作瀏覽器與檔案系統的工具權限很大,該限制可存取的範圍。

相關術語: Harness (被其載入)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

Sequence Diagram

循序圖

UML 的一種圖,用時間軸表達多個參與者之間訊息往返的先後順序。

它特別適合描述這支影片裡的資料路徑:瀏覽器 → BFF → 資料服務的初始載入,以及 SSE 連線建立後事件持續推送的過程。作為給 AI 的錨點它有個實際優勢——用 Mermaid 這類文字語法寫出來就能直接進版本控制,模型讀得懂,人類也 review 得動。

相關術語: Stable Artifacts (屬於其中)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

Ollama

Ollama 本地模型執行器

在自己的機器上下載並執行開源大型語言模型的工具。

作者在影片裡把名字唸成近似「Yama」,指的就是 Ollama;他說的「Queen」則是 Qwen(阿里的開源模型系列)。本地模型的價值不在效能而在合規:金融、醫療這類產業的程式碼與資料常常根本不允許送出企業網路。代價是能力落差明顯,且 15B 等級的模型在長上下文的 agent 任務上會頻繁出錯,通常只適合補全與局部重構,而不是端到端的功能開發。

相關術語: Harness (可搭配使用)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

Code Review Agent

程式碼審查代理

自動讀取 pull request、產生摘要與問題清單的 AI 工具,例如 CodeRabbit。

它最有效的地方正是人類最容易疲乏的地方:安全弱點、無障礙缺失、重複邏輯、命名不一致。作者提到的迴圈風險很真實——審查代理提出修改、coding agent 照做、審查代理又覺得新寫法有問題,兩邊來回不收斂;實務上的止血方式是限制自動修復的輪數,並且要求最後一定要有人類簽核。

相關術語: End-to-End Test (互補的品質關卡)

出處:第 14 段「AI 開發工具鏈:模型、harness、審查代理」

見仁見智 31:53
「probably everybody talks about about Opus 4.7」
這是 2026 年 5 月錄影當下的快照,現在已經換代:Anthropic 最新的是 Claude 5 系列(Opus 5、Sonnet 5、Fable 5.1)加上 Haiku 4.5。任何講具體模型版本的建議都有極短的保存期限,該帶走的是他的選型判準(資料能不能出境、預算、harness 適不適合做 review),而不是型號。
依據: 影片上傳日 2026-05-11;截至 2026-09 Anthropic 現行旗艦為 Claude Opus 5
確定錯誤/已過時 34:34
「I think was it 800 billion parameters」
Anthropic 從未公開 Claude 任何一代的參數量,OpenAI、Google 同樣不公開,所以「800B」是沒有來源的猜測。另外他的推論方向也反了:大型雲端模型贏在能力與上下文長度,而不是比本地小模型「快」——同樣的硬體上,參數越多每個 token 越慢,雲端之所以感覺快是因為推論硬體與批次處理,不是因為模型大。
依據: Anthropic 官方模型說明頁未揭露任何參數量數據
留給下一段 工具與模型也定了;回頭看這整份架構,還有哪些地方作者自己覺得沒挖夠?

15. 回頭看:還會再深掘的地方 35:50–37:10

被問到這份架構回頭看還會補什麼,他點出三塊。一是重用性:這個元件到底要不要當成設計系統的一部分出貨,若要就會談到 Storybook 這類工具;如果是 SPA,還會追問渲染策略——SSR、SSG(這裡大概不適用)、增量或部分預渲染,這是更深一層的取捨。二是整體前端架構:他們現在是什麼架構、有沒有在看微前端、CSS 架構走的是 Tailwind 那種 atomic CSS 還是 styled-components。三是他自承漏掉的行動裝置響應式:用相對單位而不是寫死像素、多用 flexbox 與 media query。

承上 承上:工具與模型也定了,這段是作者自己回頭審視這份架構的缺口。

推理因為被問到「回頭看會補什麼」,作者點出三塊他刻意沒展開的地方。一是重用性:這個元件到底要不要當成設計系統的一部分出貨,若要就會牽出 Storybook 這類工具;而如果它活在 SPA 裡,他會追問渲染策略——SSR、SSG(他判斷這裡大概不適用)、或是增量與部分預渲染。二是整體前端架構:對方現在是什麼架構、有沒有在看微前端、CSS 架構走的是 Tailwind 那種 atomic CSS 還是 styled-components。三是他自承整場漏掉的行動裝置響應式:用相對單位而不是寫死像素、多用 flexbox 與 media query。

AI 補充這一段的形式比內容更值得學:主動列出自己沒挖夠的地方,等於把「還能聊什麼」的清單交給面試官,而這正好治好開場提到的那個病——沒話講。注意他列的三項都是「有明確取捨、可以聊十分鐘」的題目,不是隨口的補充。至於 SSG 為什麼不適用,他沒說理由,補上很簡單:SSG 在建置時就把 HTML 產好,而這個頁面每秒都有新價格,建置時的內容一秒後就過期了;有意義的變體是把不會變的外框做成靜態、只把圖表那塊留給客戶端或 SSR——也就是他提到的部分預渲染。響應式那塊他給的建議偏基礎,對圖表元件真正的難點其實是容器查詢(container query)與 SVG 的 viewBox 縮放,因為圖表要跟著容器而不是視窗變形。

Storybook

Storybook 元件工作台

把 UI 元件抽離應用、獨立開發與展示各種狀態的工具。

它是設計系統的標準配備,因為元件的邊界狀態(載入中、錯誤、空資料、超長文字)在真實應用裡很難重現,但在 Storybook 裡可以一個 story 一個。它同時是文件、是視覺回歸測試的素材來源,也是設計師與工程師對照的共同介面。對這支影片的圖表元件來說,最該建的 story 就是「沒有資料點」「只有一個點」「資料橫跨很長區間」這幾種。

相關術語: Design System (配套工具)

出處:第 15 段「回頭看:還會再深掘的地方」

SSG

靜態網站生成

在建置時就把頁面產生成靜態 HTML,請求進來直接送檔案。

它的極致優勢是可以整份丟上 CDN、幾乎零伺服器成本;限制是內容在建置那一刻就固定了。ISR(增量靜態再生)與部分預渲染就是為了突破這個限制而生的中間態:靜態外框先送出,動態區塊留白或串流補上。判準很簡單:內容多久變一次、以及每個使用者看到的是不是同一份。

相關術語: SSR (對照組)

出處:第 15 段「回頭看:還會再深掘的地方」

Micro Frontend

微前端

把一個前端應用切成多個可獨立開發、獨立部署的片段,執行期再組合起來。

它解決的是組織問題而不是技術問題:多個團隊要各自出貨、不想被同一條發佈流水線綁死。代價相當大——重複的框架載入、跨片段的樣式與狀態隔離、版本漂移、整體效能難以掌控。所以在面試裡問「你們有沒有在看微前端」是聰明的:它會直接暴露對方團隊的規模與痛點。

相關術語: Design System (跨片段一致性靠它)

出處:第 15 段「回頭看:還會再深掘的地方」

Atomic CSS

原子化 CSS

把樣式拆成單一用途的工具類(例如 flex、pt-4),直接寫在標記上組合出畫面。

Tailwind 是最普及的實作。優點是樣式表大小趨於收斂(同一個類別全站共用)、不必替每個元素想名字、刪掉標記就等於刪掉樣式;缺點是標記變得冗長,而且跟「語意化 class 名稱」的傳統做法在團隊裡常引發爭論。跟 CSS Modules 的差別不在作用域(兩者都不會全域衝突),而在你是寫自己的 class 還是組合現成的工具類。

相關術語: CSS Modules (對照組)

出處:第 15 段「回頭看:還會再深掘的地方」

留給下一段 技術面能補的都列完了;剩下最後一個問題——同樣的題目,為什麼有人過有人不過?

16. junior 與 senior 的差別,以及唯一的建議 37:10–40:31

最大的地雷是「沒話講了」。理想上這種題目可以聊五小時、提出好幾種方案,而你要主導那場討論,心裡有張地圖知道要走去哪、什麼叫可接受的最終結果,並帶著面試官走過每一步。junior 是工具導向(「我們應該用 styled-components」),senior 則是先講決策因素(要顧 web 效能,那就得考慮 bundle size),而且不是替對方做決定,而是攤開選項:A 方案、B 方案、C 方案,就這個問題情境我選 B。senior 也不被動——不必別人說「這要跑得快」,他自己會先問使用者是誰、再判斷效能重不重要,然後帶著對方走完決策。一句話總結:senior 能預判卡點與限制、提出選項並顧問對方,這不是在建造,是在諮詢;當 AI 已經在寫一半的程式碼,這點更明顯。最後的唯一建議:把設計做完整比被一堆選項搞混更重要;市面上的系統設計材料多半偏後端,而且大家都在練「怎麼設計 Uber、怎麼設計 Instagram」,但一般 SaaS 公司考的是這種有大量資料、大量表單的商業功能——把學到的東西帶回前端、帶回你每天真的在做的企業軟體,不要去解想像出來的系統。

承上 承上:技術面能補的都列完了,這段回答同樣的題目為什麼有人過有人不過。

推理因為前面已經把整條路線走完,作者最後把它折回到人身上。他說最大的地雷是「沒話講了」——理想上這種題目可以聊五小時、提出好幾種方案,而你要主導那場討論,心裡有張地圖知道要走去哪、什麼叫可接受的最終結果。junior 是工具導向(「我們應該用 styled-components」),senior 則先講決策因素(要顧 web 效能,那就得考慮 bundle size),而且不是替對方做決定,而是攤開選項:A、B、C,就這個情境我選 B。senior 也不被動——不必別人說「這要跑得快」,他自己會先問使用者是誰、再判斷效能重不重要,然後帶對方走完決策。一句話總結:senior 能預判卡點與限制、提出選項並顧問對方,這不是在建造,是在諮詢;當 AI 已經在寫一半的程式碼,這點更明顯。最後的唯一建議是:把設計做完整比被一堆選項搞混更重要;市面上的系統設計材料多半偏後端,而且大家都在練「怎麼設計 Uber、怎麼設計 Instagram」,但一般 SaaS 公司考的是這種有大量資料、大量表單的商業功能——把學到的東西帶回前端、帶回你每天真的在做的企業軟體,不要去解想像出來的系統。

AI 補充「提出選項而不是做決定」聽起來像溝通技巧,其實是資訊的問題:面試官知道你不知道的約束(既有技術棧、團隊規模、合規要求、時程),所以你單方面下的決定有一半機率踩到隱藏條件,而攤開選項讓對方能用他手上的資訊補完最後一步。要注意這不是含糊其辭——正確形式是「A、B、C,就我目前掌握的情境我選 B,因為 X」,你仍然要表態,只是把推導過程留在桌上。這也回頭解釋了整支影片為什麼每個階段都以提問開場:那些問題不是禮貌,而是在把隱藏約束一個個逼出來。至於「不要解想像出來的系統」這句,對照前面的內容就更清楚了:這支影片裡真正稀有的不是 SSE 或 BFF 這些名詞,而是「從一張 UI 推到最小狀態」的那段——那正是設計 Uber 這類題目永遠練不到的東西。

SaaS

軟體即服務

以訂閱方式透過網路提供的軟體,使用者不必自行安裝與維運。

作者用它來界定面試題目的分布:絕大多數工程師會待的公司是在做商業 SaaS,題目長得像「大量資料的儀表板」「複雜表單流程」「權限與多租戶」,而不是「設計 Instagram 的動態牆」。這也是他建議的核心——把練習題換成你每天真的會遇到的形狀,練到的東西才用得上。

相關術語: System Design Interview (決定題型)

出處:第 16 段「junior 與 senior 的差別,以及唯一的建議」

留給下一段 總結收束。

4. 總結

整支影片是一條單向推進的鏈。作者先指出面試失敗的真因不是技術而是「沒有心智里程碑」,於是把路線的第一站定為需求:不照單全收設計稿,把畫面翻成功能性與非功能性兩欄,並在此處只掛號不展開(無障礙、安全先點名,效能用 Core Web Vitals 與 SLO 量化),同時確認 UI 有即時更新,把問題劈成「初始載入」與「持續刷新」兩塊。這個劈法逼出第二站:既然要分靜態與即時,就得知道畫面上什麼會變——他用刪去法圈出動態欄位,再寫成 TypeScript 型別,過程中積極合併強相關的型別、刪掉能算出來的衍生狀態(price_final 就是最後一個資料點)。型別定完,AI 的第一次登場只是配角:它能幫你精煉狀態結構,但會膨脹細節、分不出畫面上哪些是靜態的。狀態有了形狀還缺變化規則,於是第三站給出窮舉法——前端改變狀態只有後端資料與使用者事件兩個來源——推出 data/loading/error 三件套加 {start_date, end_date},並據此判定用 useState 加 TanStack 就夠,不需要全域狀態。狀態穩定才有資格談實作,第四站列出「最小可行前端」(React、設計系統與 design token、CSS Modules、語意化 HTML)並延伸到建置工具與程式碼品質,這裡出現第一個 AI 時代的轉折:Prettier 不再是品味問題,而是六千行 agent PR 還 review 得動的前提。工程面收乾淨後才回頭處理一直掛在那裡的非功能性需求:效能拆成載入、互動、版面穩定三個維度逐一探問(對應 LCP、INP、CLS),手段落在 bundle splitting 與 SSR;可擴展性把瓶頸推向後端,引出 BFF 當前端的穩定介面;即時性用「是不是真的雙向」一刀砍掉 polling 與 WebSocket,選定 SSE,並在此把整支影片的隱藏主軸推到極致——畫面上四個同時在動的東西,全部能從一個新資料點算出來,所以不需要任何額外狀態;最後用讀寫比這條單一判準掃過所有層級決定快取什麼(CDN、獨立的設計系統 CSS、過去唯讀的資料點、TanStack 的客戶端快取)。全部收完後 AI 才第二次登場,而且是以同一套邏輯的延伸出現:模型缺乏視覺智能,所以要準備穩定的錨點產物讓它只做內插——而那組錨點(設計系統、狀態圖、循序圖)正好就是這條路線一路產出的東西。結論因此不是「AI 會寫程式所以不用學架構」,而是相反:系統設計成了你在 AI 時代唯一必須親自產出的東西,而評分標準是你能不能攤開選項顧問對方,而不是替他做決定。

勘誤總整理

確定錯誤/已過時見仁見智(取決於版本或情境)

段落原話(transcript 逐字)說明
4. 把畫面翻成資料模型
7:45
「you want a lot of decimals, then those numbers can store a lot more than a plain integer」BigInt 不能存小數。它是任意精度的「整數」型別,寫 1.5n 直接語法錯誤。金融資料要精確小數,正確做法是存最小貨幣單位的整數(例如以「分」為單位存 8190242),或用 decimal.js / big.js 這類十進位函式庫;JavaScript 的 number 是 IEEE 754 雙精度浮點數,0.1 + 0.2 !== 0.3 的問題就出在這裡。
依據: ECMAScript 規範 BigInt 型別定義:BigInt values represent integer values;TC39 decimal 提案仍在 stage 1(2026)
14. AI 開發工具鏈:模型、harness、審查代理
34:34
「I think was it 800 billion parameters」Anthropic 從未公開 Claude 任何一代的參數量,OpenAI、Google 同樣不公開,所以「800B」是沒有來源的猜測。另外他的推論方向也反了:大型雲端模型贏在能力與上下文長度,而不是比本地小模型「快」——同樣的硬體上,參數越多每個 token 越慢,雲端之所以感覺快是因為推論硬體與批次處理,不是因為模型大。
依據: Anthropic 官方模型說明頁未揭露任何參數量數據
10. Web 效能的三個維度
21:31
「There will be no layout shifts because we already preloaded this」SSR 能減少版面位移,但不等於「不會有」。hydration 前後的差異、晚載入的網頁字體造成的重排、以及圖表函式庫在客戶端算完尺寸後才調整容器,都還是會產生 CLS。真正的保證來自替容器預留固定尺寸(明確的高度或 aspect-ratio)與 font-display 策略,SSR 只是讓內容更早就位。
依據: web.dev CLS 最佳實務:Always include size attributes on images and video elements, or reserve space with CSS aspect-ratio
13. 快取:用讀寫比決定快取什麼
28:37
「they add a style tag in your HTML file」這個描述適用於 styled-components、Emotion 這類執行期的 CSS-in-JS,不適用於 CSS Modules。CSS Modules 是建置期把 class 名稱雜湊化,產出的仍是獨立的 .css 檔案,完全可以獨立快取——作者的結論(把設計系統的 CSS 拆出來單獨快取)是對的,但他把兩種技術混在同一句話裡講,字面上會誤導。
依據: css-loader / Vite 的 CSS Modules 產出獨立樣式表;styled-components v6 執行期以 <style> 注入
14. AI 開發工具鏈:模型、harness、審查代理
31:53
「probably everybody talks about about Opus 4.7」這是 2026 年 5 月錄影當下的快照,現在已經換代:Anthropic 最新的是 Claude 5 系列(Opus 5、Sonnet 5、Fable 5.1)加上 Haiku 4.5。任何講具體模型版本的建議都有極短的保存期限,該帶走的是他的選型判準(資料能不能出境、預算、harness 適不適合做 review),而不是型號。
依據: 影片上傳日 2026-05-11;截至 2026-09 Anthropic 現行旗艦為 Claude Opus 5

5. 推薦三個下一步

1. 往下挖深:把 SSE 與即時圖表真的實作出來

影片在協定選擇(SSE)與狀態最小化就收手了,沒有講連線數限制、斷線重連、背壓、以及新資料點進來時圖表怎麼平滑重繪——這是從白板走到真實程式碼之間最大的一段缺口。

YouTube 搜尋:Server-Sent Events EventSource tutorial real-time chart React streaming data SSE vs WebSocket scaling HTTP/2

2. 往旁邊對照:後端版本的系統設計怎麼談同一個問題

作者刻意把後端當黑盒(BFF 之後就不談了),但即時金融資料在後端是完全不同的題目——時間序列儲存、扇出、訊息佇列。看過後端版本才知道 BFF 兩側各自的難處在哪。

YouTube 搜尋:system design real-time stock price feed time series database design interview fan-out message queue system design

3. 往上應用:把這條路線套到你自己的專案並產出錨點產物

影片最後的主張是設計文件(設計系統、狀態圖、循序圖)就是餵給 coding agent 的錨點。與其再看一支面試影片,不如學會用 Mermaid 把狀態圖與循序圖寫進版本控制,直接驗證這個主張。

YouTube 搜尋:Mermaid state diagram sequence diagram tutorial spec driven development AI coding agent frontend architecture decision record

📄 全部影片 · 主題區: 前端底層與系統設計