前端工程師轉全端:沿著分層架構把資料層、商業邏輯層、持久層一層層走完

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

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

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

1. Outline

  1. 起點 · How Frontend Engineers can master the Full-stack
    先畫出前端 → 資料層 → 商業邏輯層 → 持久層 → 基礎設施層的分層地圖,再沿著地圖從離前端最近的那一層開始,一層一層往下走完。

2. YouTuber 的思維推導

How Frontend Engineers can master the Full-stack

theSeniorDev · 39m18s · 字幕 en · vision=on (整支影片是白板/示意圖導覽,transcript 大量出現「as you see here」「I added a mathematical example」「this is one of the best representations I could find」「As you see in my case, I have a max age」等指示語,超過 3 次,畫面上的分層架構圖、HTTP 報文結構、快取 headers、CAP 三角、B-tree 與分片圖都是理解推理的關鍵。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 2s
segment 1m49s –
shot 1m35s 5s
analyze 16m15s –
render 5s –

作者的出發點是一個市場觀察:前端職缺的門檻已經往上移,只會刻 UI 元件不再是資深的證明。他沒有列一份雜亂的清單,而是先在白板上畫出一張分層架構圖——前端 → 資料層 → 商業邏輯層 → 持久層 → 基礎設施層——然後宣告「這支影片就是沿著這張圖,從離前端最近的那一層開始,一層一層往下走」。這張圖是整支影片的推理骨架:每一個概念都被放回圖上的某個位置,而不是孤立地被介紹。

往下走的順序本身也有論證。他先攻資料層,因為那是前端每天已經在碰的東西(你早就在打 REST API),只是你站在消費端;把 HTTP 這個協定本身弄懂,你就從「消費者」變成「能查、能除錯、甚至能改端點的人」,他稱這是前端能做的最大一次躍進。接著資料層內部再細分成三種取資料的模式:請求/回應的 REST、給前端更多選擇權的 GraphQL、以及需要即時性時的資料串流;GraphQL 之所以出現在 REST 之後,是因為它的動機正是 REST 的限制,而 BFF 又是 GraphQL 的自然產物——也是前端最容易貢獻的第一塊後端。

穿過資料層之後才進到商業邏輯層(大腦)與持久層(記憶),最後停在基礎設施層並宣告留給下一支影片。在資料庫這一層,他用 CAP 定理當統一的心智模型,讓讀寫分離、索引、分片這三個擴展手段不再是三個記憶點,而是同一個取捨框架下的三種選擇。

貫穿全片的第二條線是「該學多深」。他反覆用自己的失敗經驗回答:買厚書硬啃會失敗(他讀了 15 頁就放棄),不用就會忘;正確的深度是能講出一條連貫的故事,並且盡量把新知識綁在你每天會碰到的東西上(回自己的 codebase 找 Swagger、打開 network tab 找 cache header)。結論落在能力圈:不要一次跳進陌生領域,而是待在自己已經穩的地方,把邊界慢慢往外推。

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

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

  1. 開場:只會 React 已經不夠 → 既然目標是端到端,第一個問題就是:這條「端到端」的路上到底有哪幾站?作者接下來要先畫出整張地圖。
  2. 分層架構的全貌 → 地圖畫好了,第一站是資料層。但前端每天都在打 API,「深入資料層」到底是深入什麼?作者接著要把 REST 底下那個更基礎的東西拆開。
  3. HTTP:REST 底下的請求與回應 → 知道 HTTP 是一封純文字信之後,下一個問題是:REST 憑什麼被稱為一種「標準」?這些請求是照什麼規則被設計出來的?
  4. REST 端點設計與怎麼實際上手 → 會用、會查、甚至會改一個端點之後,下一個門檻是被追問「為什麼 REST 更容易擴展」——這需要一組更抽象的概念。
  5. 冪等性、網路分層與 TCP/IP → 作者自己也承認這一層可以講三小時。那麼問題就變成:這些東西到底該讀到多深才夠?
  6. 該讀多深:把網路當歷史讀 → 說完該讀多深,作者要示範一個「綁得住」的例子——一個前端每天都在受益、卻幾乎沒人真的看過的機制。
  7. HTTP 快取:Cache-Control 與 ETag → REST 加上快取已經能覆蓋日常大部分工作,但它有一個結構性的限制還沒被解決——那正是下一個技術出現的理由。
  8. GraphQL 為何出現:under-fetching → 如果前端可以自己決定查詢形狀,那這層查詢介面該由誰來建、放在哪裡?答案指向一個前端最容易切入的架構位置。
  9. BFF:後端為前端 → 既然 GraphQL 給了前端自由選擇的能力,那個「後端失去查詢成本控制權」的代價,會以什麼具體形式爆炸?
  10. 圖的彈性與 N+1 問題 → REST 與 GraphQL 加起來覆蓋了絕大多數日常工作,但兩者都是「你問、它答」。當資料需要主動推過來時呢?
  11. 資料串流:WebSocket 與 SSE → 資料層的三種模式到這裡走完了。沿著架構圖往右,下一層是決定「資料進來之後要做什麼」的地方。
  12. 商業邏輯層:後端的大腦 → 大腦要做的第一件事是確認來的人是誰。確認完之後,緊接著的問題是——送來的東西可信嗎?
  13. 清洗驗證與 DTO → 資料被清洗、被打包,接下來要真的寫下去。那個「寫下去」的地方,本身就是一整個需要選型的世界。
  14. 持久層:NoSQL 與 SQL 怎麼選 → 選好了存在哪裡,下一個問題是量變大之後怎麼辦——而這在系統設計面試裡是必考題。
  15. CAP 定理與讀寫分離 → 讀寫分離處理的是讀取的併發量。但如果問題不是人多,而是單一張表本身太大呢?
  16. 索引與分片 → 資料庫講完,架構圖上就只剩最後一格還沒點名——那些讓所有服務真的跑起來的東西。
  17. 基礎設施層與先找出自己的缺口 → 方法論說完,剩下最後一個實際問題:一個現在就在做前端的人,第一步到底該踏在哪裡?
  18. 從能力圈開始往外擴

3. 逐段說明

How Frontend Engineers can master the Full-stack

1. 開場:只會 React 已經不夠 0:00–0:24

作者開宗明義指出,前端工程師只會 React 或 Angular、只會刻 UI 元件的時代結束了,公司期待你能端到端交付、也能碰後端。這支影片要講的是 10 個前端轉全端必須掌握的概念。

承上 前情提要裡「前端職缺門檻正在上移」這個市場背景,是這支影片存在的理由——作者直接從這個共同體感出發,不再論證它成不成立。

推理因為觀眾多半已經感覺到「會 React 卻在面試被問後端」的落差,作者不花時間說服你這件事,而是直接把它變成前提,並承諾用 10 個概念把落差補上。他刻意用「端到端交付」而不是「學後端」來描述目標,暗示接下來要講的不是一堆技術名詞,而是一條從前端往後延伸的路徑。

AI 補充作者沒有說破的是:「端到端交付」在公司裡通常不是要你去寫核心後端服務,而是要你在一張票(ticket)上不會卡在交界處——需要改一個 API 欄位時你自己能改,需要判斷慢在哪一層時你自己能判斷。這決定了後面所有內容的取捨標準:不是要你變成後端工程師,而是要你在每一層都有足夠的語言可以對話與除錯。這也解釋了為什麼後面的建議幾乎都是「回你自己的 codebase 找某個東西」,而不是「去修一門課」。

full-stack

全端

同時能在前端與後端交付功能的工程師定位。

在這支影片裡,full-stack 不是「前端 + 後端兩份技能」的加總,而是「能獨立把一個功能從畫面做到資料庫」的能力。作者刻意把它跟「後端工程師」區分開:你不需要能設計整個後端架構,但你需要能在既有架構裡安全地移動。常見誤解是以為要先精通某個後端語言才算 full-stack;作者後面會示範,理解協定與分層通常比多學一個語言更關鍵。

相關術語: layered architecture (以此為地圖)

出處:第 1 段「開場:只會 React 已經不夠」

留給下一段 既然目標是端到端,第一個問題就是:這條「端到端」的路上到底有哪幾站?作者接下來要先畫出整張地圖。

2. 分層架構的全貌 0:24–0:52

他先畫出整體地圖:前端做元件與狀態管理,向後端要資料、送出更新,資料最後落到 data layer。用分層架構(layered architecture)的觀點看,這是第一個要征服的領域。整支影片就是沿著這張圖從資料層往下走。

白板上的分層架構圖,是整支影片的骨架;後面每個概念都會回到這張圖上的某一層
0:40 · 白板上的分層架構圖,是整支影片的骨架;後面每個概念都會回到這張圖上的某一層
承上 承上:上一段留下的問題是「端到端的路上有哪幾站」,作者的回答就是先把整張地圖畫出來。

推理因為要避免變成流水帳式的名詞清單,作者先用分層架構把整個系統攤開:左邊是前端應用(Angular/Vue/React)與它的狀態管理,往右是 1. Data Layer,再往右是 2. Business Logic Layer,最後是 3. Persistence Layer。前端跟資料層之間的箭頭是雙向的——你送出動作、你收回資料——這條雙向箭頭正是前端唯一已經站著的位置。他因此宣告:第一個要征服的領域就是離你最近的資料層。

AI 補充畫面上這張圖有一個細節值得注意:資料層的圖示是一束纏在一起的網路線,商業邏輯層是一個大腦,持久層是一疊硬碟。這不是裝飾,而是三個層各自的職責隱喻——傳輸、決策、記憶。後面每次講到一個新概念,作者都會回到這張圖指出它落在哪一格;如果你在看的時候感覺散亂,回頭問「這個東西在哪一層」通常就能定位。 另外要補上作者跳過的一步:分層架構的價值不只是分類,而是「每一層只能跟相鄰層對話」。這條約束正是後面很多設計(例如為什麼要多一層專門服務前端的後端)之所以成立的原因。

layered architecture

分層架構

把系統切成職責分明、只跟相鄰層對話的水平層次。

分層架構是這支影片的敘事骨架:資料層負責傳輸、商業邏輯層負責決策、持久層負責記憶。它的核心約束是「只跟相鄰層說話」——前端不直接碰資料庫,商業邏輯不直接處理 HTTP 細節。這條約束帶來的好處是任何一層都能被抽換或獨立擴展,代價是每穿過一層都要多一次轉換(後面會看到專門做這件事的物件)。它跟微服務、六角架構這類切法的差別在於:分層是水平切,微服務是垂直切。

相關術語: data layer (包含)

出處:第 2 段「分層架構的全貌」

data layer

資料層

負責在前端與後端之間傳輸資料的那一層,前端每天實際接觸的邊界。

作者把資料層當成前端轉全端的第一站,理由是「你已經站在這裡了,只是站在消費端」。這一層裡有三種主要模式:請求/回應式的 REST、由客戶端決定形狀的 GraphQL、以及需要即時性時的串流。要注意的是,資料層在這裡指的是「資料怎麼流動」,不是「資料存在哪裡」——後者屬於持久層,是完全不同的一層。

相關術語: layered architecture (屬於)

出處:第 2 段「分層架構的全貌」

留給下一段 地圖畫好了,第一站是資料層。但前端每天都在打 API,「深入資料層」到底是深入什麼?作者接著要把 REST 底下那個更基礎的東西拆開。

3. HTTP:REST 底下的請求與回應 0:52–2:17

要往資料層深入,第一步是真的懂 REST 背後的協定 HTTP。作者用「一封 email」比喻:客戶端送出一段文字,伺服器拆出 method、path、protocol 和 headers(描述資料的資料),再組出結構幾乎相同的回應,多了 status code 與 status message,body 可能是 JSON 或 HTML。

畫面上拆解 HTTP request 的文字結構(method / path / protocol / headers),「像一張紙」的比喻只有看圖才成立
1:35 · 畫面上拆解 HTTP request 的文字結構(method / path / protocol / headers),「像一張紙」的比喻只有看圖才成立
對照的 HTTP response 結構,含 status code 與 headers,用來看出請求與回應的對稱性
2:00 · 對照的 HTTP response 結構,含 status code 與 headers,用來看出請求與回應的對稱性
承上 承上:上一段問「深入資料層是深入什麼」,作者的第一個答案是——先懂 REST 底下的那個協定,HTTP。

推理因為前端對 REST 的熟悉停在「呼叫它、拿到 JSON」,作者用一個降維的比喻把它變回可讀的東西:HTTP 請求就是一張紙、一封 email,是純文字。畫面上他把一行 `GET / HTTP/1.1` 拆成 method、path、protocol version,下面接 `Host:` 與 `Accept-Language:` 兩個 header,並標注「headers 是關於資料的資料」。接著他把回應並排放上來——結構幾乎一模一樣,只是第一行換成 `HTTP/1.1 200 OK`(protocol version、status code、status message),下面同樣是 headers。這個對稱是這一段真正的重點:請求與回應不是兩種東西,是同一種格式的兩個方向。

AI 補充作者說 body「我這裡沒有畫進去」,但沒有補上為什麼可以省略——因為 HTTP 訊息的結構是「起始行 + headers + 空行 + body」,body 是可選的,GET 請求通常根本沒有 body。理解這個結構有一個直接的實用價值:當你在 network tab 看到問題時,你會知道要往哪裡看——狀態不對看 status code,快取或編碼不對看 headers,內容不對才看 body。 畫面上的回應範例還藏了一個下文的伏筆:headers 裡已經出現 `cache-control: public, max-age=3600`。作者這時只說「headers 是關於資料的資料」,暫時沒有展開它的意思。

HTTP

超文本傳輸協定

以純文字的請求與回應在客戶端與伺服器之間交換資料的協定。

HTTP 的精神是無狀態(stateless):每個請求都自帶所有必要資訊,伺服器不需要記得你上一次做了什麼。這一點是後面很多性質的根源——因為伺服器不必保存會話狀態,任何一台機器都能處理任何一個請求,這才讓水平擴展變得容易。作者用「一封 email」比喻是準確的:起始行像信封上的收件資訊,headers 像附註,body 才是信的內容。

相關術語: REST (作為基礎)

出處:第 3 段「HTTP:REST 底下的請求與回應」

header

標頭

附在請求或回應上、描述這份資料本身性質的鍵值對。

作者的定義「data about the data」很到位:header 不是內容,而是關於內容的說明——內容是什麼型別、多長、用什麼編碼、能不能被快取、要不要驗證。前端能從 header 讀到的資訊遠比多數人以為的多,這也是為什麼作者反覆要你打開 network tab。常見誤解是把 header 當成「後端的事」,但快取、CORS、內容協商這幾件影響前端最深的行為,全都寫在 header 裡。

相關術語: HTTP (組成部分)

出處:第 3 段「HTTP:REST 底下的請求與回應」

status code

狀態碼

回應第一行的三位數字,表示這次請求的結果類別。

狀態碼分成五類:1xx 資訊、2xx 成功、3xx 重導、4xx 客戶端錯誤、5xx 伺服器錯誤。作者的建議不是背完整張表,而是能區分「這是我送錯了還是伺服器壞了」——4xx 代表問題在請求端(沒帶憑證、格式不對、找不到資源),5xx 代表問題在伺服器端。這個區分決定了你出事時該去找誰、看哪一邊的 log。

相關術語: HTTP (組成部分)

出處:第 3 段「HTTP:REST 底下的請求與回應」

留給下一段 知道 HTTP 是一封純文字信之後,下一個問題是:REST 憑什麼被稱為一種「標準」?這些請求是照什麼規則被設計出來的?

4. REST 端點設計與怎麼實際上手 2:17–5:18

REST 之所以叫 REST,是因為端點依統一標準設計:資源(如 survey)加 ID,配上定義明確的 HTTP 動詞完成 CRUD。作者說不要背 status code,要動手:回自己的 codebase 看所有資料請求,找後端要 OpenAPI/Swagger 文件,從外往內理解,最後試著自己擴充一個端點。他還講了自己收到 swagger 檔卻不知道那是什麼、因此被當成 junior 的親身經歷。

資源式端點與 HTTP 動詞對應 CRUD 的表格,是 REST「統一介面」的具體長相
2:30 · 資源式端點與 HTTP 動詞對應 CRUD 的表格,是 REST「統一介面」的具體長相
Swagger UI 畫面,作者要你回公司去找的就是這個東西,看過才認得出來
3:20 · Swagger UI 畫面,作者要你回公司去找的就是這個東西,看過才認得出來
承上 承上:上一段問「REST 憑什麼算一種標準」,這一段給出答案——標準在於端點的設計方式是統一的。

推理因為 HTTP 本身只規定了訊息格式、沒規定該怎麼組織 API,作者接著補上 REST 加上去的那層約定:用資源當名詞、用 HTTP 動詞當動作。畫面上他把兩欄並排——左欄 GET/POST/DELETE/PUT,右欄 `/surveys`、`/surveys/123`、`/surveys/123/resp...`——兩欄交叉就組合出所有 CRUD 操作,回應是 JSON。這正是「uniform(統一)」的具體含義,也是 REST 的 R 所指的東西。 有了這個結構,他才能回答「我到底要學多少」。答案不是背 status code,而是三個動作:回自己的 codebase 看所有資料請求;去找後端要 OpenAPI/Swagger 文件,那個 UI 會把所有端點攤在你面前;然後試著自己擴充一個端點——如果後端也是 TypeScript/Node 會容易得多,C# 或 Java 就等於再學一門語言。面試的實際考法他也講了:現場把某個資源的端點寫出來(拿 user 當例子,取得、修改、刪除各是什麼請求、各回什麼)。

AI 補充這一段最有價值的其實是那個親身經歷:他當時收到後端傳來的 swagger 檔,卻不知道那是什麼,被團隊當成 junior。這個故事的重點不在尷尬,而在於它示範了一種特定的知識落差——不是「不會寫」,而是「不認得業界共通的東西」。這種落差在面試裡致命,因為它會被解讀成「沒待過成熟團隊」。 作者說「從外往內」也值得補一步他沒展開的:先看契約(有哪些端點、進出什麼形狀),再看實作(這個端點內部做了什麼)。契約是穩定的、可讀的、跨語言的,實作才需要語言知識。這就是為什麼一個不懂 Java 的前端,仍然可以完全看懂一個 Java 後端的 API。

REST

表現層狀態轉移

把 API 組織成資源加上統一 HTTP 動詞的一組設計約定。

REST 不是協定也不是規格,是一組約束(constraints)。最關鍵的兩條是「統一介面」——所有資源用同一套動詞操作,以及「無狀態」——每次請求自帶完整資訊。統一介面帶來的好處是可預測:看到 `DELETE /users/123` 你不必查文件就知道它做什麼。常見誤解是把「回傳 JSON 的 HTTP API」都叫 REST,但沒有資源導向的 URL 設計,其實只是 HTTP API。

相關術語: CRUD (對應於)、OpenAPI (文件化於)

出處:第 4 段「REST 端點設計與怎麼實際上手」

CRUD

建立/讀取/更新/刪除

對一個資源的四種基本操作,分別對應 POST/GET/PUT/DELETE。

CRUD 是資料操作的最小完整集合,幾乎所有業務功能拆到底都是這四件事的組合。REST 的巧妙之處在於它不必為每個操作發明一個端點名稱(像 `/createUser`、`/deleteUser`),而是靠動詞加資源就表達完畢。面試常考的是邊界情況:部分更新該用 PUT 還是 PATCH、建立成功該回 200 還是 201。

相關術語: REST (實作於)

出處:第 4 段「REST 端點設計與怎麼實際上手」

OpenAPI

OpenAPI 標準

用機器可讀的規格檔描述一整套 REST API 的業界標準。

OpenAPI(前身叫 Swagger Specification)用一份 YAML 或 JSON 描述每個端點的路徑、動詞、參數、回應形狀與錯誤碼。它的價值在於這份檔案能被工具消費:自動生成文件頁、自動生成前端的 API client、自動產測試。作者被傳了一份 swagger 檔卻不知道能拿它做什麼——實際上那份檔案可以直接生成整套型別安全的呼叫程式碼,這正是它被當作成熟團隊標配的原因。

相關術語: Swagger (呈現為)

出處:第 4 段「REST 端點設計與怎麼實際上手」

Swagger

Swagger UI

把 OpenAPI 規格渲染成可瀏覽、可直接試打的網頁介面。

畫面上那個把 `/pet` 的 PUT/POST/GET/DELETE 一條條展開、每條都能點開直接送出請求的頁面就是 Swagger UI。對前端來說它是最快的探索工具:不用寫任何程式碼就能知道某個端點回什麼形狀。作者要你「從外往內」的起點就是這個頁面——它是後端 API 的契約攤開來的樣子。

相關術語: OpenAPI (渲染自)

出處:第 4 段「REST 端點設計與怎麼實際上手」

留給下一段 會用、會查、甚至會改一個端點之後,下一個門檻是被追問「為什麼 REST 更容易擴展」——這需要一組更抽象的概念。

5. 冪等性、網路分層與 TCP/IP 5:18–7:55

想更深入就要能回答「REST 為什麼更容易擴展」。關鍵是冪等性(idempotency):同一個操作做多次結果不變,像乘以 1。因為前端常有 retry 機制,非冪等端點被重試會造成無法預測的副作用。接著他建議認識 DNS 與網路七層(我們只工作在第六、七層),以及 IP 負責定址、TCP 保證封包依序且不遺失。

白板上乘以 1 的數學例子,是理解冪等性最直觀的一張圖
5:50 · 白板上乘以 1 的數學例子,是理解冪等性最直觀的一張圖
網路七層堆疊圖,說明「我們只碰上面兩層、但它建在更低的抽象上」
6:50 · 網路七層堆疊圖,說明「我們只碰上面兩層、但它建在更低的抽象上」
承上 承上:上一段留下的門檻是「為什麼 REST 更容易擴展」,作者從冪等性開始回答,並順勢往下探到協定底層。

推理因為擴展性的問題無法用「會打 API」回答,作者引進第一個抽象概念:冪等性。畫面上他放的是一個矩陣乘以單位矩陣仍等於自己的例子(口頭講的是「乘以 1」)——同一個操作做幾次,結果都一樣。他接著把它接回前端最熟悉的場景:前端常有 retry 機制;如果一個請求其實成功了、只是回應沒收到,重試一個非冪等的操作就會做兩次,資料庫因此出現無法預測的變化。所以除了 POST,端點都應該追求冪等。 往更底層走,他建議認識 DNS 與網路分層。畫面上是完整的 OSI 七層圖,右邊圈出「Software Layer」;他的說法是應用開發者實際工作在最上面幾層——七層的 DNS/HTTP、六層的資料表示——底下那些是我們站著的地基。最後他點到 IP 負責定址(header 記著從哪來、要去哪,路由器靠它轉送)與 TCP 負責可靠性(保證封包依序抵達、不遺失),所以前端不必自己處理分塊回應的重組。

AI 補充這裡有一個作者跳過的推論步驟值得補上:REST 之所以容易擴展,主因其實是無狀態,不是冪等性。因為伺服器不保存會話狀態,任何一台機器都能處理任何一個請求,你才能無腦加機器。冪等性解決的是另一個問題——重試時的安全性。兩者在面試裡常被一起問,但它們回答的不是同一件事,分清楚會讓你的答案比多數人準確。 冪等性的定義也有一個常見陷阱:DELETE 是冪等的(刪第二次結果仍是「不存在」),但它不是「安全的」(safe,指完全不改變狀態)。GET 兩者皆是,POST 兩者皆非,PUT 冪等但不安全。面試官問「哪些動詞是冪等的」時,真正在確認的是你有沒有分清楚這兩個維度。

術語:OSI model

idempotency

冪等性

同一個操作執行一次或多次,結果都相同的性質。

冪等性在分散式系統裡是安全重試的前提。它不代表「每次回應都一樣」(DELETE 第二次可能回 404),而是「系統最終狀態一樣」。實務上讓 POST 也變冪等的標準手法是冪等鍵(idempotency key):客戶端產生一個唯一 ID 隨請求送出,伺服器記住這個 ID,重複請求直接回上次的結果——支付類 API 幾乎都這樣做。要跟「安全(safe)」區分開:安全指完全不改變狀態,冪等只要求重複執行不再造成新的改變。

相關術語: REST (設計原則)

出處:第 5 段「冪等性、網路分層與 TCP/IP」

OSI model

OSI 七層模型

把網路通訊從硬體到應用切成七個抽象層的參考模型。

從下到上是實體、資料連結、網路、傳輸、會話、表示、應用。它是「參考模型」而不是實作——真實的網際網路跑的是 TCP/IP 四層模型,兩者對不齊。它的實用價值在於給你一組定位問題的座標:連不上是三層路由的事,連上但斷線是四層的事,連上且穩定卻回錯資料才是七層的事。作者說得對——能講出這幾層的人不多,講得出來就會顯眼。

相關術語: TCP (位於第四層)、HTTP (位於第七層)

出處:第 5 段「冪等性、網路分層與 TCP/IP」

IP

網際網路協定

負責定址與路由的協定,決定封包從哪來、往哪去。

IP 提供的是「盡力而為」的傳送:它會盡量把封包送到,但不保證送達、不保證順序、不保證不重複。這個刻意的簡陋是網際網路能擴展到全球的原因——中間的路由器只需要看 header 上的目的地就轉送,不必記住任何連線狀態。所有可靠性都被推到上層去處理。

相關術語: TCP (承載於)

出處:第 5 段「冪等性、網路分層與 TCP/IP」

TCP

傳輸控制協定

在不可靠的 IP 之上提供依序、不遺失的可靠資料流。

TCP 靠三次握手建立連線、靠序號與確認(ACK)保證順序與完整、靠重傳補上遺失的封包。作者說「TCP 保證依序抵達所以你不用自己重組」——這正是為什麼前端拿到的 response 永遠是完整而有序的字串,而不是一堆需要拼裝的碎片。代價是延遲:一個封包掉了,後面的都得等它補到(head-of-line blocking),HTTP/3 改用 QUIC 就是為了繞開這個代價。

相關術語: IP (建立於其上)、HTTP (承載)

出處:第 5 段「冪等性、網路分層與 TCP/IP」

DNS

網域名稱系統

把人類可讀的網域名稱解析成 IP 位址的分散式目錄。

DNS 是那個經典面試題「在瀏覽器輸入 google.com 後發生了什麼」的第一步:瀏覽器快取 → 作業系統快取 → 遞迴解析器 → 根伺服器 → 頂級網域 → 權威伺服器,一路問出 IP。對前端的實際影響比想像大:每個新網域的第一次請求都要付一次 DNS 解析的延遲,這也是為什麼 `dns-prefetch` 與 `preconnect` 這類提示能實際加快載入。

相關術語: IP (解析為)

出處:第 5 段「冪等性、網路分層與 TCP/IP」

留給下一段 作者自己也承認這一層可以講三小時。那麼問題就變成:這些東西到底該讀到多深才夠?

6. 該讀多深:把網路當歷史讀 7:55–9:30

主持人問:這些到底要學到多深?作者的答案是——不是每天用到的東西,讀了也會忘,買本厚書硬啃只會半途而廢(他自己讀 15 頁就放棄了)。對超出日常範圍的主題,把它當讀歷史:你沒親身經歷過那些事件,但要能講出一條連貫的故事,說明 IP/TCP 怎麼堆疊成你每天在用的東西。

承上 承上:上一段以「這可以講三小時」收尾,主持人立刻替觀眾問出那個問題——到底要讀多深?

推理因為前一段丟出了大量可以無限深入的主題,作者必須先給一個停損點,否則觀眾會被淹沒。他的判準是使用頻率:不是每天用到的東西,讀了也會忘(use it or lose it)。他用自己的失敗當證據——買了一本厚厚的網路書,讀了 15 頁就放棄,因為書很枯燥、而且他當時有更重要的問題要解決。 然後他給出替代的深度標準:把它當讀歷史。你沒有親身經歷過那些事件,但你要能講出一條連貫的故事——IP 做什麼、TCP 補上什麼、它們怎麼疊成你每天在用的東西。這個標準的巧妙之處在於它可驗證:你能不能一口氣講完,自己馬上知道。

AI 補充「把它當歷史讀」這個比喻背後其實是一個更精確的學習原則:對於不會反覆練習的知識,該追求的是可提取的結構,而不是可執行的細節。你需要的是一張能掛東西的骨架——遇到新資訊時知道它該掛在哪裡,而不是一堆孤立的事實。 這也回頭解釋了前面那些「回你的 codebase 找」的建議為什麼一直重複:那不是懶人做法,而是把知識綁在你會反覆遇到的東西上。綁得住的部分用練的,綁不住的部分用故事記——這就是作者實際在用的分配策略,只是他沒有明講。

留給下一段 說完該讀多深,作者要示範一個「綁得住」的例子——一個前端每天都在受益、卻幾乎沒人真的看過的機制。

7. HTTP 快取:Cache-Control 與 ETag 9:30–11:46

多數人把瀏覽器快取視為理所當然,卻很少有人能打開 console 說出快取現在的狀態。瀏覽器看 response 的 cache-control 決定要不要重用,max-age 說明能留多久,過期後用 ETag 跟伺服器確認有沒有新版本。作者要你明天回公司就打開 network tab,挑一個靜態資源把這三個 header 找出來。

cache-control / max-age 的說明圖,快取決策流程要看圖才連得起來
10:00 · cache-control / max-age 的說明圖,快取決策流程要看圖才連得起來
實際的 network tab response headers,可以看到 max-age、age 與 ETag 三者並列——這是作者要你動手複製的畫面
11:00 · 實際的 network tab response headers,可以看到 max-age、age 與 ETag 三者並列——這是作者要你動手複製的畫面
承上 承上:上一段的原則是「知識要綁在你每天會碰到的東西上」,HTTP 快取正是那個例子——它每天替你工作,你卻沒看過它。

推理因為快取是瀏覽器自動做的,多數人從沒檢查過它的狀態。作者先講機制:瀏覽器讀回應的 `cache-control` 決定要不要重用;如果可重用,會標明是 private 還是 public 快取,並附上 `max-age` 說明能留多久;超過時效就用 `ETag` 去問伺服器有沒有新版本。畫面上他放了一張完整的決策樹——可重用嗎?要每次重新驗證嗎?中介快取能存嗎?最長能留多久?——每個分岔對應一個 cache-control 的值(no-store、no-cache、private、public)。 然後他做了這一段真正的動作:打開自己的 DevTools,指著一個 JavaScript 檔的 Response Headers,把 `Cache-Control: public, max-age=86400` 圈起來,旁邊還有 `Age: 10843`。max-age 是允許保存的時間,Age 是這份回應已經被存了多久,兩者一比就知道還剩多少。他要你明天回公司就做同一件事。

AI 補充這一段是全片方法論最完整的示範:先給機制(決策樹)、再給實例(自己的 network tab)、最後給一個明天就能做的動作。三者缺一,知識就綁不住。 要補上作者略過的一個關鍵區分:`max-age` 過期不代表「快取失效」,只代表「需要重新驗證」。這時瀏覽器帶著 `If-None-Match: <ETag>` 去問,伺服器如果內容沒變就回 `304 Not Modified`——一個沒有 body 的空回應,瀏覽器繼續用本地那份。所以 ETag 省下的是傳輸量,不是往返次數。真正要連往返都省掉,靠的是還沒過期的 max-age。這個差別直接決定了你該怎麼配置靜態資源:檔名帶 hash 的資源可以給極長的 max-age(內容變了檔名就變),HTML 入口檔則必須每次驗證。

術語:HTTP caching

HTTP caching

HTTP 快取

由回應標頭驅動、讓瀏覽器或中介節點重用先前回應的機制。

HTTP 快取分兩段:先判斷「新鮮不新鮮」(靠 max-age/Expires),過期後再判斷「有沒有變」(靠 ETag/Last-Modified)。新鮮的資源連請求都不發,這是最大的效能來源;過期但沒變的資源會拿到 304,省下傳輸但仍付一次往返。它也是前端排查「為什麼線上還是舊版」最常見的現場——大多數這類問題都是 max-age 設得太長又沒有做檔名雜湊。

相關術語: Cache-Control (由此控制)、header (承載於)

出處:第 7 段「HTTP 快取:Cache-Control 與 ETag」

Cache-Control

快取控制標頭

指定一份回應能不能被快取、被誰快取、能留多久的回應標頭。

常見的值:`no-store` 完全不存(敏感資料用)、`no-cache` 可以存但每次都要重新驗證、`private` 只有瀏覽器能存、`public` 中介快取與 CDN 也能存、`max-age=N` 新鮮期 N 秒、`immutable` 保證內容永不改變。畫面上的決策樹就是照這個順序在問。注意 `no-cache` 不是「不要快取」——那是 `no-store`,這個命名是 HTTP 最常被誤解的地方之一。

相關術語: max-age (包含指令)

出處:第 7 段「HTTP 快取:Cache-Control 與 ETag」

max-age

最長存活秒數

Cache-Control 裡指定這份回應可以被視為新鮮的秒數。

單位是秒,且是相對於這份回應產生的時間,不是相對於你收到它的時間——所以才需要 `Age` 標頭告訴你它已經在快取裡待了多久。畫面上 `max-age=86400` 配 `Age: 10843` 的意思是:允許存一天,已經存了約三小時,還剩約二十一小時。這種相對時間的設計是為了避免依賴客戶端時鐘,因為使用者的系統時間並不可信。

相關術語: Cache-Control (屬於)

出處:第 7 段「HTTP 快取:Cache-Control 與 ETag」

ETag

實體標籤

代表某份資源特定版本的識別碼,用來檢查內容有沒有變。

ETag 通常是內容的雜湊值。過期後瀏覽器帶著 `If-None-Match: <ETag>` 詢問,內容沒變就回 304、不帶 body。它跟 `Last-Modified` 的差別在精度:後者只到秒,而且「時間變了」不等於「內容變了」(重新部署會刷新時間戳但檔案可能一模一樣),ETag 直接比對內容因此更準。

相關術語: HTTP caching (用於重新驗證)

出處:第 7 段「HTTP 快取:Cache-Control 與 ETag」

確定錯誤/已過時 11:00
「I have a max age of 86 400,000 milliseconds」
單位講錯了。`Cache-Control` 的 `max-age` 指令單位是「秒」,不是毫秒。他自己畫面上圈起來的正是 `Cache-Control: public, max-age=86400`,也就是 86400 秒 = 24 小時;若真的是 86,400,000 毫秒也剛好是同一個 24 小時,但螢幕上的數字是 86400 而非 86400000。同一段講到的 `Age: 10843` 同樣以秒計。
依據: RFC 9111 §5.2.2.1(Cache-Control max-age,delta-seconds);影片 11:00 畫面 DevTools Response Headers 顯示 max-age=86400、Age: 10843
留給下一段 REST 加上快取已經能覆蓋日常大部分工作,但它有一個結構性的限制還沒被解決——那正是下一個技術出現的理由。

8. GraphQL 為何出現:under-fetching 11:46–13:13

GraphQL 是較新的取資料方式,動機是 REST 的限制,其中之一是 under-fetching:通用資源端點給的資料不夠,抓一份清單後還要為每一筆再打一次請求,一個畫面可能要打上幾十次。GraphQL 的回應是給前端一個近似資料庫的查詢層,讓幾十個請求變成一次 query、一次 response。

under-fetching 的示意圖:一次清單請求後衍生出的一串額外請求,看到數量才有感
12:25 · under-fetching 的示意圖:一次清單請求後衍生出的一串額外請求,看到數量才有感
承上 承上:上一段結尾指出 REST 有一個結構性限制還沒解決,作者現在把它命名出來——under-fetching。

推理因為 REST 的統一介面是它的優點也是它的天花板:端點的形狀由後端事先決定,而通用的資源端點永遠不會剛好等於某個畫面需要的資料。畫面上他把兩種做法並排:左邊 REST 要打三次——`/users/<id>` 拿到使用者、`/users/<id>/posts` 拿到貼文、`/users/<id>/followers` 拿到追蹤者;右邊 GraphQL 只送一個 query,裡面同時要 name、posts 的 title、followers 的 name,回來一份剛好的 JSON。 這個對照讓 GraphQL 的動機變得不必解釋:它不是「更好的 REST」,而是把「決定資料形狀」這件事的決定權從後端移到客戶端。作者用一句話總結——GraphQL 給前端一個近似資料庫的查詢層。

AI 補充作者說 under-fetching 會「為每一筆再打一次請求」,這個現象在前端有個更常見的名字:瀑布式請求(request waterfall)。它的代價不只是請求數量,而是延遲會累加——第二次請求必須等第一次回來才知道要打哪些 ID,所以總延遲是往返時間的倍數,不是總和被平行化掉。這也是為什麼「合併成一次 query」的收益比單看請求數更大。 另外要補一個他沒說的權衡:把決定權交給客戶端,代價是後端失去了對查詢成本的控制。REST 的每個端點成本是可預估的,GraphQL 的一個 query 可能便宜也可能極貴,取決於客戶端怎麼寫。這個代價後面會以一個具體的故障形式出現。

GraphQL

GraphQL 查詢語言

讓客戶端在單一請求中精確指定所需資料形狀的 API 查詢語言。

GraphQL 的三個核心構件是 schema(後端宣告有哪些型別與欄位)、query(客戶端宣告要哪些欄位)、resolver(後端每個欄位怎麼取值)。它通常只用一個端點、一律用 POST,所以 HTTP 層的快取幾乎失效——這是它相對 REST 最實際的損失,也是為什麼很多團隊在 CDN 邊緣仍然保留 REST。它解決的是資料形狀問題,不是效能問題本身。

相關術語: REST (對照組)、under-fetching (為此而生)

出處:第 8 段「GraphQL 為何出現:under-fetching」

under-fetching

取得不足

單次請求拿到的資料不夠一個畫面使用,必須再追加請求。

under-fetching 的根源是端點的粒度由後端決定,而畫面的需求由前端決定,兩者不可能長期對齊。它最痛的形式是 N+1 型的瀑布:先拿一份清單,再為清單裡每一筆各打一次請求,請求數隨資料量線性成長。前端常見的緩解手法是後端提供批次端點(`/users?ids=1,2,3`)或欄位選擇參數,但那其實是在 REST 上逐步長出 GraphQL 的功能。

相關術語: GraphQL (催生了)

出處:第 8 段「GraphQL 為何出現:under-fetching」

留給下一段 如果前端可以自己決定查詢形狀,那這層查詢介面該由誰來建、放在哪裡?答案指向一個前端最容易切入的架構位置。

9. BFF:後端為前端 13:13–15:24

當同一個資料層要服務網頁、手機、桌面等不同客戶端,各自需要的資料視圖都不同,硬拼在 REST 上會變成科學怪人。乾淨的做法是 BFF(Backend For Frontend):由前端/全端工程師建的後端,把背後多個服務的回應縫成單一回應給自己的客戶端。作者說這通常是前端能貢獻的第一塊架構。用 GraphQL 做 BFF 的好處是彈性夠大,多半一個就夠;用 REST 做則每個客戶端都得各來一個。

BFF 架構圖:GraphQL 層在前、多個服務在後,回應被縫合成一份——這張圖是本段的全部論證
13:50 · BFF 架構圖:GraphQL 層在前、多個服務在後,回應被縫合成一份——這張圖是本段的全部論證
mobile BFF 與 web BFF 並列的對照圖,說明為什麼要為不同客戶端各建一層
14:40 · mobile BFF 與 web BFF 並列的對照圖,說明為什麼要為不同客戶端各建一層
承上 承上:上一段問「這層查詢介面該由誰建、放在哪裡」,作者的答案是一個有名字的架構位置——BFF。

推理因為同一份資料要服務網頁、手機、桌面等不同客戶端,而每個客戶端要的視圖都不同,硬把所有需求塞進同一套 REST 端點,作者的形容是會長成一個「科學怪人」。乾淨的做法是加一層:BFF——由前端或全端工程師建的後端,專門服務自己的客戶端。畫面上這個結構很清楚:左邊是 API 消費者,中間綠圈圈住的是 BFF 回傳的那份完整 JSON,右邊綠圈圈住的是它背後真正被呼叫的一堆服務——DynamoDB 存使用者資料、API Gateway 接訂單服務、Lambda 管庫存、Aurora 管定價。BFF 的工作就是把這些回應縫成一份剛好合用的回應。 他強調這通常是前端能貢獻的第一塊架構:後端工程師建那些服務,前端建這一層。而用 GraphQL 做 BFF 有個額外好處——因為客戶端本來就能自選欄位,多半一層就夠;如果用 REST 做 BFF,每個客戶端都得各來一層,否則又會變回科學怪人。

AI 補充作者沒有明說但值得指出的是:BFF 的價值不只在資料形狀,更在「歸屬權」。這一層屬於前端團隊,意味著前端要改欄位時不必排進後端團隊的迭代——組織上的解耦往往比技術上的收益更大。這也是為什麼 BFF 最早是 SoundCloud 為了讓行動端團隊不被後端阻塞而提出來的。 代價同樣要說清楚:多一層就多一個要部署、要監控、要處理故障的東西,而且它非常容易長成第二個單體。判準是——如果你只有一種客戶端、而且後端 API 本來就貼合你的需求,BFF 是純粹的成本。

BFF

後端為前端

為特定客戶端量身打造、由前端團隊擁有的一層薄後端。

BFF 的正式名稱是 Backend For Frontend,由 SoundCloud 在 2015 年前後提出。它的職責很窄:聚合下游服務、裁切成這個客戶端要的形狀、處理該客戶端專屬的驗證與快取。它不該包含商業規則——那屬於下游服務;一旦業務邏輯開始往 BFF 裡搬,它就會退化成另一個難以維護的中間層。判斷 BFF 是否健康的簡單標準是:刪掉它,功能仍然存在,只是前端要多打幾次請求。

相關術語: GraphQL (常實作於)、layered architecture (新增一層)

出處:第 9 段「BFF:後端為前端」

留給下一段 既然 GraphQL 給了前端自由選擇的能力,那個「後端失去查詢成本控制權」的代價,會以什麼具體形式爆炸?

10. 圖的彈性與 N+1 問題 15:24–18:24

GraphQL 叫 graph,是因為資料是彼此相連的節點:查到蒙娜麗莎就能順著走到達文西,而 REST 的資源彼此獨立,只能整包拿(over-fetching)或不夠拿(under-fetching)。彈性的代價是 N+1 問題:查 100 個產品、再為每個產品各查一次價格,等於對自己的資料庫發動 DDoS。解法是把查詢合併成一次 SQL,GraphQL 生態的工具叫 DataLoader。

graph 節點關聯圖(蒙娜麗莎 → 達文西 → 相關資訊),解釋「像走圖一樣查詢」
16:15 · graph 節點關聯圖(蒙娜麗莎 → 達文西 → 相關資訊),解釋「像走圖一樣查詢」
同一張圖上圈出兩塊不同的子圖,具體呈現「前端自己決定要拿多少」的 optionality
16:40 · 同一張圖上圈出兩塊不同的子圖,具體呈現「前端自己決定要拿多少」的 optionality
承上 承上:上一段留下的問題是「客戶端自由選擇的代價會怎麼爆炸」,這一段先把那份自由講清楚,再讓它爆炸。

推理因為要先理解自由有多大,才理解代價有多重,作者先解釋 GraphQL 為什麼叫 graph:畫面上是一張知識圖譜,蒙娜麗莎連到達文西(painted)、連到羅浮宮(is in)、羅浮宮連到巴黎(is located in),節點彼此相連。REST 的資源是各自獨立的島,圖的節點則可以一路走下去。他在同一張圖上圈了兩塊不同的子圖,旁邊寫著兩行字:gives the client optionality、gives the client a schema——你要拿多少,自己圈。 然後代價出現了。如果你查一份產品清單、又要每個產品的價格,而 resolver 是逐筆解析的,那就是 1 次清單查詢加上 N 次欄位查詢——這就是 N+1。作者把後果講得很直白:這等於對自己的資料庫發動 DDoS。主持人補上關鍵的一句——這些查詢是同時發出的獨立查詢,如果有五萬個使用者各自這樣打一次,資料庫會被自己人打垮。解法是在送出前把它們合併成一次 SQL,GraphQL 生態的標準工具叫 DataLoader。

AI 補充N+1 值得補上一個判斷方法,因為它幾乎不會在開發環境出現:本機的測試資料通常只有幾十筆,N=20 的時候一切正常,上線後 N=5000 才炸開。所以偵測它不能靠體感,要靠監測「單次請求觸發的 DB 查詢數」——這個指標一旦隨資料量成長,就是 N+1。 DataLoader 的原理也值得說明,因為它常被誤以為是快取:它其實是把同一個事件迴圈週期內收到的所有取值請求先攢起來(batching),到週期結尾一次送出合併查詢,再把結果分派回各個 resolver。所以它不改變你的 resolver 寫法,只改變它們實際打出去的時機——這是它能無痛套用的原因。 順帶一提,N+1 完全不是 GraphQL 獨有的。任何 ORM 在迴圈裡讀取關聯欄位都會產生一模一樣的問題,只是 GraphQL 因為讓客戶端自由組合欄位,讓它更容易被意外觸發。

術語:N+1 problem

over-fetching

取得過多

回應裡包含大量這個畫面根本用不到的欄位。

over-fetching 是 under-fetching 的對稱面,兩者同源:端點形狀固定,而畫面需求多變。它的代價比較隱性——不是請求數,而是傳輸量與解析成本,在行動網路與低階裝置上才會痛。REST 的緩解手法是 sparse fieldsets(`?fields=id,name`),但那同樣是在往 GraphQL 的方向長。

相關術語: under-fetching (相反)

出處:第 10 段「圖的彈性與 N+1 問題」

N+1 problem

N+1 查詢問題

取一份 N 筆的清單後,又為每一筆各發一次查詢,共 N+1 次。

N+1 的危險在於它在小資料量下完全隱形,卻隨資料量線性放大。它不只發生在 GraphQL——ORM 的延遲載入(lazy loading)在迴圈裡讀關聯欄位是最經典的來源。診斷方法是監測單次請求的 DB 查詢數;修法有兩種,一是預先載入(eager loading/JOIN),二是批次合併(DataLoader)。作者說它是 GraphQL 最常見的面試題,這是準的。

相關術語: DataLoader (解法)、GraphQL (常見於)

出處:第 10 段「圖的彈性與 N+1 問題」

DataLoader

批次載入器

把同一輪內的多次取值請求攢成一次批次查詢的工具。

DataLoader 做兩件事:批次(batching)與同輪去重快取(per-request caching)。它利用 JavaScript 事件迴圈的特性——在同一個 tick 內收集所有 `load(key)` 呼叫,到 tick 結尾一次交給你提供的批次函式,再把結果按 key 分派回去。關鍵是它的快取只活在單次請求範圍內,不是跨請求的快取;把它當成應用層快取用會導致資料過期。

相關術語: N+1 problem (解決)

出處:第 10 段「圖的彈性與 N+1 問題」

留給下一段 REST 與 GraphQL 加起來覆蓋了絕大多數日常工作,但兩者都是「你問、它答」。當資料需要主動推過來時呢?

11. 資料串流:WebSocket 與 SSE 18:24–21:24

REST 與 GraphQL 覆蓋約 95% 的日常工作,剩下的是需要即時更新的場景。WebSocket 開一條雙向通道,聊天類應用(WhatsApp、Messenger、Instagram)都靠它,但難實作也難擴展。若通訊是不對稱的——像 ChatGPT,你送一句、伺服器回一大串 chunk——用 Server-Sent Events 就好:瀏覽器原生、兩行程式碼、更好擴展。

多個 client 與 server 之間雙向 socket 的示意圖,說明聊天應用的連線模型
19:20 · 多個 client 與 server 之間雙向 socket 的示意圖,說明聊天應用的連線模型
SSE 的不對稱通訊圖(送一則、收很多),是選 SSE 而非 WebSocket 的判準
20:15 · SSE 的不對稱通訊圖(送一則、收很多),是選 SSE 而非 WebSocket 的判準
承上 承上:上一段結尾問「資料需要主動推過來時呢」,這正是資料層的第三種模式——串流。

推理因為請求/回應模型本質上只能由客戶端發起,即時場景(會跳動的圖表、聊天訊息)只能靠每五秒問一次來模擬,而那對伺服器壓力極大。所以有了 WebSocket:開一條雙向通道,伺服器能主動推、客戶端也能送。作者說 WhatsApp、Facebook、Instagram 都是這樣運作的。 但他接著做了這一段最有價值的判斷。現在的 AI 應用(像 ChatGPT)也在串流,可是那個通訊是不對稱的——你送一句話,伺服器回一大串 chunk。畫面上他打開 OpenAI 的回應,一行行 `event: delta` 與 `data` 疊著往下,旁邊是幾行 `e.data` 的接收程式碼。既然你幾乎不往上送,就不需要雙向通道:Server-Sent Events 是瀏覽器原生的、兩行程式碼就能收、而且更好擴展。他給的判準很乾脆——只要客戶端送的訊息遠少於伺服器送的,就用 SSE,不必上 WebSocket。

AI 補充SSE 更好擴展的原因作者沒展開,值得補:SSE 就是一個一直不關閉的 HTTP 回應,所以它天然享有 HTTP 的一切基礎設施——反向代理、負載平衡、CDN、驗證機制全部照用,斷線後瀏覽器還會自動重連並帶上 `Last-Event-ID` 續傳。WebSocket 則要先用 HTTP 握手再升級成另一種協定,中間每一層代理都得特別支援它,這才是「難擴展」的實際含義。 SSE 的限制也要說清楚,否則會用錯地方:它只能傳文字(要傳二進位得先編碼),而且在 HTTP/1.1 下受同網域連線數上限影響(每個網域約六條),開太多分頁會卡住——HTTP/2 之後這個限制才消失。需要低延遲雙向(多人協作、遊戲、語音)時,WebSocket 仍然是唯一選項。

WebSocket

網頁通訊端

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

WebSocket 先發一個帶 `Upgrade: websocket` 的 HTTP 請求握手,成功後這條 TCP 連線就脫離 HTTP 語意,改用它自己的訊框協定。這個「脫離」是它強大也麻煩的原因:沒有 HTTP 的方法、狀態碼與快取,中介設備也看不懂它,所以每一層代理都要特別配置。連線是有狀態的,代表水平擴展時必須解決「同一個使用者要回到同一台機器」或改用外部訊息匯流排。

相關術語: Server-Sent Events (對照組)、TCP (建立於其上)

出處:第 11 段「資料串流:WebSocket 與 SSE」

Server-Sent Events

伺服器推送事件

伺服器透過一個持續開啟的 HTTP 回應單向推送文字事件的原生瀏覽器 API。

前端用 `new EventSource(url)` 就開始收,內建自動重連與 `Last-Event-ID` 續傳。傳輸格式是純文字的 `event:` / `data:` 行——畫面上 OpenAI 那串就是標準的 SSE 格式。它只能單向、只能文字,換來的是完全相容既有 HTTP 基礎設施。判準很簡單:資料主要往下流就用 SSE,需要頻繁往上送才用 WebSocket。

相關術語: WebSocket (更輕的替代)、HTTP (建立於其上)

出處:第 11 段「資料串流:WebSocket 與 SSE」

見仁見智 19:39
「That's how WhatsApp, Facebook, Instagram, that's how they all work」
當成心智模型可以,當成事實則不精確。這些平台的行動 App 大多不是用瀏覽器的 WebSocket——WhatsApp 的行動端長期使用改造自 XMPP 的自訂二進位協定跑在持久 TCP 連線上,Facebook Messenger 行動端則以 MQTT 為主,都是為了在弱網與省電上表現更好。它們的「網頁版」確實用 WebSocket。作者要傳達的「持久雙向連線」概念是對的,但把它們一律等同於 WebSocket 並不準確。
依據: Facebook Engineering, "Building Mobile-First Infrastructure for Messenger"(MQTT);WhatsApp 公開技術說明與協定分析文獻(XMPP 變體)
留給下一段 資料層的三種模式到這裡走完了。沿著架構圖往右,下一層是決定「資料進來之後要做什麼」的地方。

12. 商業邏輯層:後端的大腦 21:24–23:38

沿著分層往下走,離開資料層就是 business logic layer——應用真正的大腦,決策在這裡發生。請求進來後被 REST API 攔下,觸發附掛的函式:處理、驗證,套用像 if 一樣的商業規則,最後才呼叫資料庫(persistence layer)。這些程式碼通常被歸類成 controller。這一層最常被問的是驗證與授權,例如 JWT 的完整生命週期:你怎麼拿到它、後端拿它做什麼。

請求 → REST API → 商業邏輯 → 資料庫的流程圖,標出這一層在架構裡的位置
22:20 · 請求 → REST API → 商業邏輯 → 資料庫的流程圖,標出這一層在架構裡的位置
承上 承上:上一段以「沿著架構圖往右、看資料進來之後做什麼」收尾,這一段就停在那一層上。

推理因為前面三種模式講的都是資料怎麼流動,作者現在要處理資料到達之後發生什麼。畫面上他把鏡頭拉遠,回到最初那張分層圖——現在圖上已經掛滿了這一路講過的東西:資料串流、REST、GraphQL、Underfetching、BFF 各自被畫在下方,而中央那三格 1. Data Layer、2. Bussiness Logic Layer、3. Persistance Layer 依然是主幹。這個「拉遠再對位」的動作本身就是他的教學方法。 商業邏輯層是應用的大腦:請求被 REST API 攔下後,觸發附掛的函式,處理、驗證、套用像 if 一樣的商業規則,最後才呼叫資料庫。相對地資料庫是記憶——這個大腦/記憶的對比是他給這兩層的定位。實作上這些程式碼通常被歸類成 controller。他坦承這一層可以自成一支影片,只挑了面試最常考的切入點:JWT 的完整生命週期——你怎麼拿到它、後端拿它做什麼。

AI 補充作者把 controller 說成「大腦」稍微含糊了一個重要區分,值得補上:在分層清楚的後端裡,controller 其實應該很薄——它負責接請求、驗參數、呼叫服務、組回應,真正的商業規則放在 service 或 domain 層。之所以要分,是因為商業規則必須能脫離 HTTP 被測試與重用(同一條規則可能同時被 API、排程任務、後台工具呼叫)。面試裡問到「你怎麼組織後端程式碼」時,能講出這個分工就足以區隔出經驗深度。 JWT 的生命週期作者只留了問題沒給答案,補完整:登入成功後伺服器簽發一個由 header、payload、signature 三段 base64 組成的 token,前端後續在 `Authorization: Bearer <token>` 帶著它;伺服器不查資料庫,只用密鑰驗簽章就知道它沒被竄改。關鍵在於 payload 是編碼不是加密——任何人都能解開讀內容,所以絕不能放敏感資料;而且因為伺服器不存狀態,token 一旦簽發就無法單獨撤銷,這正是要搭配短效期 access token 加上 refresh token 的原因。這也是面試官問「JWT 怎麼登出」時真正想聽的東西。

business logic layer

商業邏輯層

請求被接收後套用業務規則、做出決策的那一層。

這一層是應用真正的價值所在——資料層與持久層基本上可以被框架與資料庫取代,商業規則不行。判斷它是否健康的標準是「這些規則能不能在沒有 HTTP、沒有資料庫的情況下被單元測試」;如果不行,代表商業邏輯被綁進了控制器或 SQL 裡。作者的「大腦 vs 記憶」比喻抓到了關鍵:決策在這裡,儲存在下一層。

相關術語: layered architecture (屬於)、controller (常實作為)

出處:第 12 段「商業邏輯層:後端的大腦」

controller

控制器

接收請求、呼叫對應邏輯、組出回應的那一組類別或函式。

controller 是 HTTP 世界與商業邏輯之間的轉接頭。健康的 controller 很薄:解析輸入、驗證格式、呼叫服務、把結果映射成回應與狀態碼。一旦 if 判斷與業務規則開始堆進 controller,就出現了所謂的「胖控制器」——症狀是規則無法在非 HTTP 的情境下重用,而且測試必須先偽造一個請求物件。

相關術語: business logic layer (屬於)

出處:第 12 段「商業邏輯層:後端的大腦」

JWT

JSON 網頁權杖

由伺服器簽章、可自行驗證真偽的 JSON 憑證字串。

結構是 `header.payload.signature` 三段 base64url,用點號連接。它的核心特性是自帶資訊且可離線驗證——伺服器只需密鑰就能確認沒被竄改,不必查資料庫,這是它在分散式服務裡受歡迎的原因。三個必須知道的陷阱:payload 是編碼不是加密(人人可讀);簽發後無法單獨撤銷(所以要短效期加 refresh token);演算法欄位若接受 `none` 會造成致命漏洞。

相關術語: business logic layer (驗證於)

出處:第 12 段「商業邏輯層:後端的大腦」

persistence layer

持久層

負責把資料實際寫入並長期保存的那一層。

持久層對應架構圖上的第三格,是應用的「記憶」。它跟資料層的差別容易混淆:資料層講的是「資料怎麼在前後端之間流動」(REST、GraphQL、串流),持久層講的是「資料存在哪裡、怎麼被查」(資料庫、schema、索引)。兩者中間隔著商業邏輯層,這也是為什麼前端不該直接碰資料庫。

相關術語: layered architecture (屬於)、business logic layer (被呼叫於)

出處:第 12 段「商業邏輯層:後端的大腦」

留給下一段 大腦要做的第一件事是確認來的人是誰。確認完之後,緊接著的問題是——送來的東西可信嗎?

13. 清洗驗證與 DTO 23:38–25:24

使用者通過驗證之後,下一步是 sanitize 與 validate:確認送來的 email 真的是 email、username 裡沒有被注入 JavaScript。接著才進到持久化,多數後端框架會用 DTO(Data Transfer Object)把資料打包成統一形狀,一路在後端管線裡傳遞直到寫進資料庫。作者形容 DTO 是「資料送進資料庫前的包裝」。

DTO 打包示意圖:前端送來的原始欄位被包裝成統一形狀再往下傳
24:15 · DTO 打包示意圖:前端送來的原始欄位被包裝成統一形狀再往下傳
承上 承上:上一段結尾問「確認完身分之後,送來的東西可信嗎」,這一段處理的正是這件事。

推理因為身分驗證只證明「你是誰」,不保證「你送的東西是乾淨的」,所以緊接著要做 sanitize 與 validate:確認送來的 email 真的是 email 的形狀、username 裡沒有被塞進 JavaScript,以及各種攻擊者會做的骯髒手法。畫面上「Validation」與「DTO」兩個標題並列,下面是一張 UML:Data Transfer Object 在最左,往右是 Remote Facade(accepts from and sends to remote clients),再往右是 Business Logic,而 Remote Facade 底下有一條 translates to/from DTOs 的虛線指向 Business Object。 這張圖正好說明 DTO 的位置:它是邊界上的形狀,不是內部的模型。作者的比喻是「資料送進資料庫前的包裝」——前端送來 username、name、email,這些原始欄位要先被打包成一個統一形狀,才在後端的管線裡一路傳遞下去。主持人用一個具體流程覆述確認:使用者送出表單 → 經過 REST API → 到後端 → 用 DTO 處理 → 再持久化。

AI 補充作者說 DTO「很抽象、沒碰過後端 codebase 會難懂」是誠實的,但有一個更精確的說法可以讓它立刻具體:DTO 存在的理由是讓「外部契約」與「內部模型」可以各自演化。如果 controller 直接把前端送來的物件交給資料庫模型,那你的資料表結構就等於公開 API——改欄位名會直接打壞客戶端,而多送一個欄位就可能被寫進資料庫(這就是有名的 mass assignment 漏洞)。DTO 是那道明確的閘門:只有被宣告的欄位能通過。 順序也值得釐清,因為作者講得比較鬆:正確的次序是先 validate(形狀對不對、必填有沒有、型別對不對)再 sanitize(把危險內容處理掉),而且真正防 XSS 的關鍵不在寫入時清洗,而在輸出時依情境轉義——同一段文字放進 HTML、放進屬性、放進 JavaScript 需要的轉義方式並不相同。寫入時清洗是輔助,不是防線。

術語:sanitization

validation

驗證

檢查送進來的資料是否符合預期的形狀、型別與規則。

驗證要在信任邊界上做,也就是資料從外部進入系統的那一刻。前端驗證只是體驗優化(讓使用者早點看到錯誤),完全不構成安全——任何人都能繞過瀏覽器直接打 API。所以同一組規則必須在後端再做一次。實務上會用 schema 驗證工具(Zod、Joi、class-validator)把規則宣告成資料,這樣前後端才可能共用同一份定義。

相關術語: sanitization (先於)、DTO (作用於)

出處:第 13 段「清洗驗證與 DTO」

sanitization

資料清洗

移除或轉義輸入中可能造成攻擊的危險內容。

清洗與驗證常被混為一談但目的不同:驗證是拒絕不合格的輸入,清洗是把可能有害的輸入改造成安全的形式。要注意的是,防 XSS 的主戰場其實在輸出端——依據內容要放進 HTML、屬性、URL 還是 JavaScript,需要不同的轉義;而防 SQL injection 的正解是參數化查詢,不是清洗字串。輸入端清洗是縱深防禦的一層,不能當唯一防線。

相關術語: validation (搭配)

出處:第 13 段「清洗驗證與 DTO」

DTO

資料傳輸物件

在系統邊界上定義資料形狀、只負責搬運不含行為的物件。

DTO 由 Martin Fowler 在企業應用架構模式中命名,原始動機是減少跨網路呼叫的次數(把多次細粒度呼叫合併成一次粗粒度傳輸)。在現代後端裡它更常見的價值是解耦:外部契約與內部領域模型分開,各自能獨立演化。它刻意不含商業行為——一旦 DTO 裡開始出現方法,它就變成領域物件,邊界就模糊了。它擋下的最典型漏洞是 mass assignment:使用者偷塞一個 `isAdmin: true`,因為不在 DTO 宣告裡而被丟棄。

相關術語: persistence layer (傳遞至)、business logic layer (邊界於)

出處:第 13 段「清洗驗證與 DTO」

留給下一段 資料被清洗、被打包,接下來要真的寫下去。那個「寫下去」的地方,本身就是一整個需要選型的世界。

14. 持久層:NoSQL 與 SQL 怎麼選 25:24–30:12

最後一層是資料庫。作者要你先把它想成「一個可以下聰明查詢的檔案」——底下仍然是硬碟,只是雲把它抽象掉了。分兩大類:NoSQL 存非結構化資料,沒有約束也沒有保證(新增「最愛顏色」欄位後,舊資料不會有),像把東西全丟進一個房間;SQL 是有 schema 的關聯式資料庫,形狀不符就報錯,99% 的商業軟體用它。實務上兩者混用:log 這種沒有關聯的資料用 NoSQL,電商的商品/價格/目錄這種關聯很重的用 SQL。

非結構化 JSON 文件形狀各不相同的示意圖,是「沒有保證」的具體長相
26:40 · 非結構化 JSON 文件形狀各不相同的示意圖,是「沒有保證」的具體長相
整齊分格收納的比喻圖,對照上一張的雜亂,一眼看出 schema 的意義
28:20 · 整齊分格收納的比喻圖,對照上一張的雜亂,一眼看出 schema 的意義
資料庫 schema 的欄位宣告畫面,說明「多加一個未定義欄位就報錯」
29:05 · 資料庫 schema 的欄位宣告畫面,說明「多加一個未定義欄位就報錯」
承上 承上:上一段結尾說「那個寫下去的地方本身就是一整個需要選型的世界」,這一段就打開它。

推理因為資料庫容易被當成黑盒子,作者先做一次除魅:不管雲怎麼抽象,它終究是一台有硬碟的電腦;最簡單的想法是「一個可以下聰明查詢的檔案」——如果只是文字檔,你得一行行找,資料庫多的是那層讓你能快速取回的抽象。畫面上持久層往右分出兩個分支:3.1 Unstructured Data - NoSQL 配一疊亂堆的紙,以及 Organized Storage - SQL 配一整櫃分格收納的樂高。這組對比是整段的論證。 NoSQL 存非結構化資料:丟進去什麼形狀都行,之後用 ID 撈回來,但沒有任何關於形狀的保證。他舉的例子很實際——產品經理說每個使用者要多一個「最愛顏色」,你加了,但此前建立的所有使用者都沒有;你查出來的資料有些有、有些沒有,於是寫不出能規模化的穩固邏輯。沒有約束的另一面就是沒有保證。SQL 則相反:畫面上那個分格收納櫃,紅色的積木塞不進藍色的格子就是報錯。這就是 schema——欄位、型別、結構的宣告;他接著把 MediaWiki 的實際資料表結構攤開,user、user_properties、user_groups、ipblocks 一格格連著,每個欄位都標明型別。99% 的商業軟體用這種,因為商業邏輯需要可預測的輸出。 最後他給選型判準:多數架構兩者混用。關聯少、量大、彼此獨立的資料(例如登入紀錄這類 log)用非結構化;關聯密而且關聯本身有意義的(電商的商品、價格、目錄)用關聯式。

AI 補充有一個作者略過的重點會改變你的判斷:NoSQL 並不是「沒有 schema」,而是「schema 由讀取端負責」。資料的形狀假設沒有消失,只是從資料庫移到了你的程式碼裡——那個「有些使用者沒有最愛顏色」的問題,正是這個轉移的帳單。所以真正的選擇不是「要不要 schema」,而是「schema 由誰來守、什麼時候發現違規」:關聯式資料庫在寫入時就擋下,文件資料庫則等到讀取時才炸。 另外「NoSQL 比較快」這個常見說法需要限縮條件:它快在單一文件的讀寫與水平擴展,因為資料是聚合在一起的、不需要跨表 JOIN。但一旦你的查詢需要關聯多份文件,你就得在應用層自己做 JOIN,那通常比資料庫做慢得多。所以判準其實是「你的存取模式是否已經確定」——確定且固定,文件資料庫可以貼著它設計;還會變,關聯式的彈性查詢會救你一命。

NoSQL

非關聯式資料庫

不要求固定表結構、以彈性形狀儲存資料的資料庫類別。

NoSQL 是一個大傘,底下至少四種型態:文件(MongoDB)、鍵值(Redis)、寬欄(Cassandra)、圖(Neo4j),彼此差異極大。它們的共同點不是「沒有 schema」,而是把形狀的責任交給應用程式,並且為水平擴展而設計。選它的正當理由通常是「存取模式已經確定且需要極高吞吐」,而不是「不想設計 schema」——後者是把今天的方便換成明天的資料清理。

相關術語: SQL (對照組)、schema (不強制)

出處:第 14 段「持久層:NoSQL 與 SQL 怎麼選」

SQL

關聯式資料庫/結構化查詢語言

以表格與明確欄位型別儲存資料、用 SQL 查詢的資料庫類別。

關聯式資料庫的核心不只是表格,而是兩件事:資料庫在寫入時強制守住形狀與關聯完整性,以及 ACID 交易保證一組操作要嘛全成功要嘛全失敗。後者是任何牽涉金額、庫存、狀態轉移的系統無法讓步的。它的另一個優勢常被低估——因為查詢是宣告式的,你可以在資料存進去很久以後才想出新的查法,而不必預先為它設計結構。

相關術語: NoSQL (對照組)、schema (強制執行)

出處:第 14 段「持久層:NoSQL 與 SQL 怎麼選」

schema

資料庫結構定義

宣告資料表有哪些欄位、各是什麼型別與約束的定義。

schema 是資料庫對資料形狀的承諾,違反就寫不進去。它帶來的不只是整潔——因為形狀有保證,查詢優化器才能規劃執行路徑,工具才能自動生成型別。它的代價是變更成本:改一個既有大表的欄位需要 migration,可能鎖表。這個代價正是很多團隊誤選 NoSQL 的原因,但 migration 的痛是一次性的、可控的,讀取端的形狀不確定則是永久的。

相關術語: SQL (定義於)

出處:第 14 段「持久層:NoSQL 與 SQL 怎麼選」

留給下一段 選好了存在哪裡,下一個問題是量變大之後怎麼辦——而這在系統設計面試裡是必考題。

15. CAP 定理與讀寫分離 30:12–33:05

系統設計面試一定會問資料庫擴展,而背後的心智模型是 CAP:一致性、可用性、分區容錯三者不可兼得,只能挑兩個。關聯式資料庫的資料多半在單一伺服器上,流量成長時先垂直加硬體,但很快撞到物理上限。第一個橫向解法是唯讀複本(read replica):主庫負責寫,複本供讀。對照 CAP,這換來了分區與可用性,代價是一致性——資料同步有延遲,讀到主庫和讀到複本可能拿到不同版本。

CAP 三角圖,「只能挑兩個」的關係要看三角形才成立
30:45 · CAP 三角圖,「只能挑兩個」的關係要看三角形才成立
master 與 read-only replica 的架構圖,用來對照 CAP 三個角各拿到什麼、失去什麼
32:15 · master 與 read-only replica 的架構圖,用來對照 CAP 三個角各拿到什麼、失去什麼
承上 承上:上一段留下的問題是「量變大之後怎麼辦」,作者先給心智模型,再給第一個手段。

推理因為擴展手段很多、單獨背會變成散落的記憶點,作者先立一個統一框架。畫面上是四行字:Database Scalability、CAP Theorem,底下條列 Consistency、Availability、Partitioning——三者不可兼得,只能挑兩個。他承認這很抽象,所以立刻拿實際情境去套。 先看沒擴展前的樣子:關聯式資料庫的資料多半住在同一台伺服器上,因為查詢要跨好幾張表、好幾筆記錄組合起來。流量上來時第一反應是加硬體——加 CPU、加記憶體、加硬碟——但這條路會撞到電腦的物理上限。 第一個真正的手段是唯讀複本。畫面上一個 master 在上、三個 read-only replica 在下,虛線從 master 流向它們。後端往 master 寫,其他服務從複本讀,壓力就不集中在單一實例。然後他做了這一段最重要的動作:把它放回 CAP 上檢查——資料被分散到不同節點所以有了分區,master 掛掉還能讀複本所以有可用性,但寫入到複本之間有延遲,同一時刻讀 master 和讀複本可能拿到不同版本,一致性因此被犧牲了。他也提醒這個模式雲端資料庫多半內建,你不用自己實作,但要能解釋。

AI 補充CAP 有一個非常常見的誤讀值得糾正,因為它會影響你在面試裡的答案:CAP 不是「三選二」的自由選擇。分區容錯(P)在任何跨網路的分散式系統裡都不是選項而是事實——網路一定會斷。所以真正的選擇只在網路已經分區的那一刻發生:這時你要繼續回應但可能給出舊資料(選 AP),還是拒絕回應直到恢復一致(選 CP)。網路正常時,一致性與可用性可以同時擁有。作者說的「只能挑兩個」是流傳最廣的簡化版本,能講出上面這層區分會明顯拉開距離。 另外「加硬體很貴」這個說法在今天需要修正:現代單機能垂直擴展到極高的規格,而且垂直擴展沒有任何架構複雜度。實務上的正確順序幾乎總是——先垂直擴展、先加快取、先修慢查詢,撐不住了才開始動架構。太早分散式化是常見的過早優化。 讀寫分離還有一個作者沒提但會實際咬人的坑:使用者剛送出表單、頁面立刻重新讀取,如果讀請求被導到還沒同步的複本,使用者會看到自己的修改「不見了」。標準解法是「寫後讀自己」——寫入後的一小段時間內,該使用者的讀取強制走 master。

術語:eventual consistency

CAP theorem

CAP 定理

分散式資料系統在網路分區時,一致性與可用性只能擇一。

由 Eric Brewer 提出、後經正式證明。最重要的澄清是:P 不是選項而是前提,因為網路必然會斷。所以實際的選擇只在分區發生的那一刻——CP 系統會拒絕服務以保證正確(如需要強一致的金融帳務),AP 系統會繼續回應但可能給舊資料(如社群動態、購物車)。後續的 PACELC 定理補上了另一半:即使沒有分區(Else),你仍要在延遲(Latency)與一致性之間取捨。

相關術語: read replica (用於分析)、eventual consistency (導致)

出處:第 15 段「CAP 定理與讀寫分離」

read replica

唯讀複本

從主資料庫複製資料、只供讀取的資料庫副本。

適用前提是讀遠多於寫——多數業務系統的讀寫比在 10:1 以上,所以這是最常見也最先採用的擴展手段。它幾乎不需要改應用架構,只需要在資料存取層區分讀寫連線。要注意的是它完全不減輕寫入壓力,寫入仍全部落在 master;而且複本越多,master 的複製負擔越重。它的隱藏代價是複製延遲(replication lag),監控這個數字比監控 CPU 更能預警問題。

相關術語: eventual consistency (產生)、CAP theorem (取捨於)

出處:第 15 段「CAP 定理與讀寫分離」

eventual consistency

最終一致性

更新後各副本會在一段延遲後趨於一致,但期間可能讀到舊值。

這是作者說「可能失去一點一致性」的正式名稱。它不代表資料錯誤,只代表「正確會遲到」。設計時要問的是:這個場景能容忍多久的遲到?按讚數慢三秒無妨,帳戶餘額慢三秒可能造成超額扣款。常見的緩解手法是把不能容忍延遲的讀取(如寫入後立即讀回)強制導向主庫。

相關術語: CAP theorem (來自)

出處:第 15 段「CAP 定理與讀寫分離」

vertical scaling

垂直擴展

把單一台機器加大——更多 CPU、記憶體、儲存——來承受更多負載。

垂直擴展的最大優點是零架構複雜度:程式碼一行都不用改。它的極限是硬體上限與單點故障。實務上的建議順序是先垂直擴展、先優化查詢與快取,真的撐不住才走水平路線——因為水平擴展帶進來的分散式問題(一致性、協調、故障處理)遠比多付的機器錢昂貴。

相關術語: horizontal scaling (對照組)

出處:第 15 段「CAP 定理與讀寫分離」

留給下一段 讀寫分離處理的是讀取的併發量。但如果問題不是人多,而是單一張表本身太大呢?

16. 索引與分片 33:05–35:26

第二個加速讀取的方式是索引:讓資料庫在底層建 B-tree,把 full table scan 的 O(n) 換成二分搜尋的 O(log n)——一百萬筆從一百萬次讀取降到約 20 次。第三個是水平擴展/分片(sharding):依 shard key(例如 ID 區間)把資料寫到不同的獨立實例。分片放在最後講,因為它對應用程式碼最複雜;對照 CAP,這裡拿到分區容錯,但在一致性或可用性上要讓步。

B-tree 與全表掃描的對照圖,O(n) 對 O(log n) 的差距靠圖才具體
33:40 · B-tree 與全表掃描的對照圖,O(n) 對 O(log n) 的差距靠圖才具體
分片圖:一個大實例被切成四個小實例,並標出 shard key 的區間分配
34:40 · 分片圖:一個大實例被切成四個小實例,並標出 shard key 的區間分配
承上 承上:上一段結尾問「如果問題不是人多、而是單表太大呢」,這一段給出兩個針對資料量本身的手段。

推理因為表大到一定程度後,光是找到一筆記錄就很慢,第一個手段是索引:讓資料庫在底層建一棵 B-tree(他說是類似二元樹的 B 樹),用二分搜尋取代全表掃描。畫面上這張圖把原理攤得很清楚——上半是 Records,每筆記錄配一個位址 0x2000、0x2100、0x2200…;下半是 Index file,一棵以 LastName 為鍵的樹,Dover 在根、往下 Dover 與 Teapot、再往下 Babbage、Knight、Allen、Gates、Lovelace,每個節點旁邊掛著對應的位址。索引本身就是一份額外的檔案。他接回演算法:全表掃描是 O(n),一百萬筆就要讀一百萬次;換成樹就是 O(log n),一百萬筆大約十九、二十次。 第二個手段是水平擴展到資料庫上——分片。畫面上是 Shard Key 欄位經過 HASH FUNCTION 算出雜湊值,再據此分派到 Shard 1 或 Shard 2;作者口頭舉的例子是用 ID 區間:1 到 100 放第一片、100 到 200 放第二片。他把分片排在最後講的理由很明確——它對應用程式碼的複雜度最高。回到 CAP 上檢查:分片明確拿到了分區,但代價落在一致性或可用性,因為你得先確定目標記錄在哪一片才找得到。

AI 補充索引有一個被作者略過、但決定它成敗的事實:索引不是免費的加速器,它是用寫入速度換讀取速度。每一次 INSERT、UPDATE、DELETE 都必須同步維護每一個相關索引,所以索引開太多會讓寫入變慢、佔用額外空間。實務上的正確做法是依實際的查詢模式建索引,而不是「重要欄位都加一個」。 還有一個前端最常誤會的點值得補:索引只有在查詢條件能「照著索引的順序從左邊開始用」時才生效。對欄位做運算(`WHERE YEAR(created_at) = 2025`)、用前綴萬用字元(`LIKE '%abc'`)、或複合索引跳過前面的欄位,都會讓索引失效而退回全表掃描。看執行計畫(`EXPLAIN`)是唯一可靠的確認方式。 分片的兩種切法值得分清楚,因為畫面與口白剛好各講了一種:範圍分片(照 ID 區間切,像作者說的)實作直觀、範圍查詢有效率,但容易出現熱點——新資料全都湧向最後一片;雜湊分片(畫面上那個 HASH FUNCTION)分佈均勻,代價是範圍查詢必須問過所有分片。選 shard key 是分片裡最難也最不可逆的決定:一旦選錯,重新分片是極痛苦的工程。

術語:database index

database index

資料庫索引

額外維護的資料結構,讓資料庫不必掃描全表就能定位記錄。

索引是典型的空間與寫入換讀取:它是一份額外儲存的檔案,而且每次寫入都要同步更新。它只在查詢能利用其排序時生效——對欄位做函式運算、前綴萬用字元的 LIKE、複合索引跳過左側欄位,都會讓它失效。實務上判斷要不要加索引,看的是實際查詢的執行計畫,而不是欄位聽起來重不重要。

相關術語: B-tree (實作為)、full table scan (避免)

出處:第 16 段「索引與分片」

B-tree

B 樹

節點可容納多筆鍵值、專為磁碟讀取設計的平衡樹結構。

B-tree 跟二元樹的關鍵差別在分支度:二元樹每個節點只有兩個子節點,B-tree 一個節點可以有數百個。這是為了配合磁碟——磁碟讀取以區塊為單位,一次讀進來的區塊塞越多鍵值,往下走的層數就越少。真實資料庫多用 B+tree(資料只放葉節點、葉節點串成鏈結串列),因為這讓範圍查詢可以沿著葉節點一路掃過去。

相關術語: database index (用於)

出處:第 16 段「索引與分片」

full table scan

全表掃描

逐筆讀過整張表來找出符合條件的記錄。

全表掃描的成本是 O(n),隨資料量線性成長。它並非永遠是壞事——當查詢會命中表中很大比例的資料時,順序讀取整張表其實比在索引與資料之間來回跳躍更快,查詢優化器有時會刻意選它。它成為問題的時機是:大表、只取少數幾筆、卻沒有可用的索引。

相關術語: database index (被取代於)

出處:第 16 段「索引與分片」

sharding

分片

依某個鍵把一張大表的資料水平切分到多個獨立資料庫實例。

分片是唯一能同時擴展讀與寫的手段,也是複雜度最高的。跨分片的 JOIN 與交易基本上不可行,得在應用層自己處理;重新分片(resharding)則是重量級工程。所以它應該是最後手段——在垂直擴展、快取、讀寫分離都用盡之後。要注意它跟分區(partitioning)的差別:分區是把表切開但仍在同一台機器上,分片是切到不同機器上。

相關術語: shard key (依據)、horizontal scaling (一種)

出處:第 16 段「索引與分片」

shard key

分片鍵

決定一筆資料該落在哪一個分片的欄位。

shard key 是分片裡最重要也最不可逆的決定。好的 shard key 要同時滿足兩件事:分佈均勻(避免某一片過熱)、而且大多數查詢的條件裡都包含它(否則每次查詢都要問過所有分片)。範圍切法(照 ID 區間)容易理解但新資料會擠在最後一片;雜湊切法分佈均勻但失去範圍查詢能力。選錯的代價是整個資料集要重新搬移。

相關術語: sharding (決定於)

出處:第 16 段「索引與分片」

horizontal scaling

水平擴展

用更多台機器分攤負載,而不是把單一台加大。

水平擴展理論上沒有上限,這是它相對垂直擴展的根本優勢。代價是分散式系統的所有難題一次到齊:資料一致性、節點協調、部分故障處理、以及運維複雜度。對無狀態的應用伺服器來說水平擴展幾乎免費(加機器就好),對有狀態的資料庫則昂貴得多——這正是為什麼資料庫總是最後一個被水平化的元件。

相關術語: vertical scaling (對照組)、sharding (應用於資料庫)

出處:第 16 段「索引與分片」

留給下一段 資料庫講完,架構圖上就只剩最後一格還沒點名——那些讓所有服務真的跑起來的東西。

17. 基礎設施層與先找出自己的缺口 35:26–37:30

架構圖上還剩最後一塊:infrastructure layer——雲、CI/CD、虛擬機、Docker、serverless、Kubernetes、IaC,這些留待另一支影片。但作者強調,今天要拿資深前端職位,至少要會自己部署前端應用,而資深級面試會同時問架構與 CI/CD。面對這麼多主題不被淹沒的方法是:先搞清楚自己的缺口在哪,而不是從頭學所有東西。

完整分層架構圖上補進 infrastructure layer,是整支影片地圖的收尾狀態
36:00 · 完整分層架構圖上補進 infrastructure layer,是整支影片地圖的收尾狀態
承上 承上:上一段結尾指向架構圖上最後一格——讓所有服務真的跑起來的那一層。

推理因為前面三層都是「程式怎麼寫」,還缺一層「程式怎麼真的跑在世界上」。畫面上這一格擺著 EC2、Docker、Lambda、Kubernetes 四個圖示,底下是靜態資源的部署架構(Route 53 → CloudFront → S3 或負載平衡後的伺服器),旁邊寫著 To be continued...——他明白地把虛擬機、容器、serverless、K8s、基礎設施即程式碼留給下一支影片。 但他不讓這一層整個空著,而是切出對前端最低限度的要求:今天要拿資深前端職位,至少要會自己部署前端應用。他點出一個實際的落差——很多開發者接觸不到部署,可是資深級面試會同時考架構與 CI/CD,即使你現在只寫前端。 然後他做了整支影片的方法論收束:面對這麼多主題,不被淹沒的方法不是從頭學所有東西,而是先搞清楚自己的缺口在哪。這句話呼應了他先前對「該讀多深」的答案——兩次都是同一個原則:先定位,再投入。

AI 補充「至少要會部署前端」這個要求可以講得更具體,因為它其實是一組可檢核的能力:你的專案 build 出什麼、那些檔案被放到哪裡、誰在服務它們、快取怎麼設、環境變數在建置時還是執行時注入、以及出事怎麼回滾。這六個問題如果你都答得出來,你就跨過了那道門檻——而它們全部可以在一個週末用任何一個靜態託管平台親手驗證一遍。 值得補上的是,這一層跟前面講過的東西比想像中更相連:CDN 的行為完全由快取標頭決定,回滾能不能安全依賴的是部署產物是否不可變(帶 hash 的檔名),而部署架構圖上那條 Route 53 就是網域解析。基礎設施不是一個新世界,而是把已經學過的協定知識放到真實環境裡。

infrastructure layer

基礎設施層

承載並運行所有服務的運算、網路與部署環境。

這一層涵蓋執行環境(虛擬機、容器、serverless)、編排(Kubernetes)、網路(DNS、負載平衡、CDN)與交付流程(CI/CD、IaC)。對前端來說它不是遙遠的後端話題——你的靜態資源怎麼被服務、快取多久、從哪個節點送出,全部發生在這裡,而且直接決定使用者感受到的載入速度。

相關術語: layered architecture (承載)、CI/CD (包含)

出處:第 17 段「基礎設施層與先找出自己的缺口」

CI/CD

持續整合/持續交付

把測試、建置與部署自動化成每次提交都會跑的流水線。

CI 是每次提交自動跑測試與建置,確保主線隨時可用;CD 則分兩種——持續交付是自動產出隨時可部署的產物、上線仍由人按下按鈕,持續部署是連按鈕都省了。資深面試問 CI/CD 時通常不是問你會不會寫 YAML,而是問你怎麼設計流水線:哪些檢查該擋住合併、產物如何保證可重現、以及出事怎麼快速回滾。

相關術語: infrastructure layer (屬於)

出處:第 17 段「基礎設施層與先找出自己的缺口」

留給下一段 方法論說完,剩下最後一個實際問題:一個現在就在做前端的人,第一步到底該踏在哪裡?

18. 從能力圈開始往外擴 37:30–39:18

主持人問:一個資深 React/Angular 工程師,今年想轉全端,第一步該怎麼走?作者的答案是待在自己的能力圈(circle of competence)裡,再慢慢把邊界往外推——不要一次跳進陌生領域。最後是頻道的 mentorship 導引。

承上 承上:上一段結尾留下的是「第一步該踏在哪裡」,主持人把它問成一個具體的人設。

推理因為抽象的建議沒有用,主持人把問題落地成一個具體的人:一個資深 React 或 Angular 工程師,碰過大概一成的後端、大概摸過 REST API 那一層,今年想轉全端。最有效率的起手式是什麼? 作者的回答只有一句話但份量很重:待在你的能力圈裡,慢慢把那個範圍往外推。這句話同時否定了兩種常見做法——不是去學一門全新的後端語言,也不是從頭補完電腦科學。它把整支影片的所有建議統一了起來:回你自己的 codebase 看資料請求、跟你的後端要 Swagger 檔、打開你正在用的應用的 network tab、看看你們現在怎麼處理某個問題。每一條都是從你已經站著的地方往外踏一步,而不是跳到一塊陌生的土地上。 最後他把話題轉向頻道的 mentorship 與技術評量,收尾。

AI 補充「能力圈」這個詞來自投資領域,原意是你真正理解的範圍——重點不在圈子多大,而在你清楚知道邊界在哪。用在學習上,它的意思是:往外推一步的地方,你有足夠的既有知識可以判斷自己做得對不對;再遠一點,你連錯了都不知道。 這也解釋了為什麼作者全片都在推薦「回你的 codebase」而不是「去修一門課」——課程給你的是離你的邊界很遠的知識,你缺乏可以驗證它的參照系;而你自己的專案是你唯一能立刻檢驗對錯的地方。 把整支影片壓成一條可執行的路徑,大致是:先把 REST 與 HTTP 弄到能自己查、能自己除錯(這是最大的一次躍進),再往下摸到你們的商業邏輯與資料庫(先能讀懂,再能改一個端點),同時把部署學會,而 GraphQL、串流、分片這些看你的公司實際用不用——用得到就是每天在練,用不到就當歷史讀,能講出連貫的故事即可。

circle of competence

能力圈

你真正理解、能判斷自己對錯的知識範圍。

這個概念源自巴菲特與蒙格的投資原則,重點不是圈子多大,而是你是否清楚知道邊界在哪——在圈內你能判斷自己是否犯錯,在圈外你連犯錯都不會察覺。用在技能成長上,它給出一個具體的行動判準:優先學那些能立刻在現有工作裡驗證的東西,因為驗證回饋才是知識被固化的機制。這正是作者反覆推薦「回你的 codebase 找」而不是「去修一門課」的理由。

相關術語: full-stack (擴展路徑)

出處:第 18 段「從能力圈開始往外擴」

留給下一段 總結收束。

4. 總結

作者從一個市場觀察出發——只會刻 UI 元件不再等於資深——但他沒有給一份雜亂的清單,而是先畫出一張分層架構圖,讓後面每個概念都有位置可放。 推理鏈是這樣往下走的:前端每天已經站在資料層的消費端,所以第一步是把 REST 底下的 HTTP 弄懂(請求與回應是同一種純文字格式的兩個方向);懂了格式才能理解 REST 加上去的那層約定(資源 + 動詞 = CRUD),也才能從「呼叫 API」變成「查得動、除錯得了、甚至改得動端點」——作者認為這是前端能做的最大一次躍進。往深處走會遇到冪等性與網路分層,但這裡他立刻插入一個停損點:不是每天用到的知識該當歷史讀,能講出連貫的故事就夠。緊接著他用 HTTP 快取示範什麼叫「綁得住的知識」——機制、自己的 DevTools 實例、明天就能做的動作,三者齊備。 然後資料層內部往下分岔:REST 的形狀由後端決定,於是有了 under-fetching,於是有了讓客戶端自選形狀的 GraphQL;GraphQL 給了前端選擇權,於是有了前端能擁有的第一塊後端 BFF;選擇權的代價則是後端失去查詢成本控制,於是有了 N+1 與 DataLoader。請求/回應走完,剩下即時場景交給串流——而 WebSocket 與 SSE 的取捨判準就是通訊對不對稱。 穿過資料層才進入商業邏輯層(大腦:controller、JWT、驗證、DTO)與持久層(記憶:NoSQL 與 SQL 的取捨、schema)。資料庫的擴展則用 CAP 當統一框架,讓讀寫分離、索引、分片變成同一個取捨下的三種選擇,而不是三個記憶點。最後停在基礎設施層,留給下一支影片。 貫穿全片的第二條線是「該學多深」,答案在最後收束成一句:待在能力圈裡,把邊界慢慢往外推——這也解釋了為什麼他全片的建議幾乎都是「回你自己的 codebase 找」,而不是「去修一門課」。

勘誤總整理

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

段落原話(transcript 逐字)說明
7. HTTP 快取:Cache-Control 與 ETag
11:00
「I have a max age of 86 400,000 milliseconds」單位講錯了。`Cache-Control` 的 `max-age` 指令單位是「秒」,不是毫秒。他自己畫面上圈起來的正是 `Cache-Control: public, max-age=86400`,也就是 86400 秒 = 24 小時;若真的是 86,400,000 毫秒也剛好是同一個 24 小時,但螢幕上的數字是 86400 而非 86400000。同一段講到的 `Age: 10843` 同樣以秒計。
依據: RFC 9111 §5.2.2.1(Cache-Control max-age,delta-seconds);影片 11:00 畫面 DevTools Response Headers 顯示 max-age=86400、Age: 10843
11. 資料串流:WebSocket 與 SSE
19:39
「That's how WhatsApp, Facebook, Instagram, that's how they all work」當成心智模型可以,當成事實則不精確。這些平台的行動 App 大多不是用瀏覽器的 WebSocket——WhatsApp 的行動端長期使用改造自 XMPP 的自訂二進位協定跑在持久 TCP 連線上,Facebook Messenger 行動端則以 MQTT 為主,都是為了在弱網與省電上表現更好。它們的「網頁版」確實用 WebSocket。作者要傳達的「持久雙向連線」概念是對的,但把它們一律等同於 WebSocket 並不準確。
依據: Facebook Engineering, "Building Mobile-First Infrastructure for Messenger"(MQTT);WhatsApp 公開技術說明與協定分析文獻(XMPP 變體)

5. 推薦三個下一步

1. 往下挖深:商業邏輯層與後端架構

作者自己說商業邏輯層可以自成一支影片,只留了 JWT 生命週期這個切入點就跳過了。controller 該多薄、規則放哪一層、交易邊界在哪,是這條推理鏈上最大的空白。

YouTube 搜尋:clean architecture nodejs service layer vs controller JWT refresh token flow explained domain driven design for backend beginners

2. 往旁邊對照:基礎設施與部署

影片在基礎設施層直接寫了 To be continued,但作者同時說資深前端面試一定會考 CI/CD 與部署。這是唯一被點名為必備、卻完全沒展開的一塊。

YouTube 搜尋:docker for frontend developers CI CD pipeline explained serverless vs containers infrastructure as code beginners

3. 往上應用:系統設計面試實戰

整支影片的每個概念(CAP、分片、快取、串流)都被標成面試會考,但沒有示範它們在一場完整的系統設計面試裡怎麼被組合起來用。

YouTube 搜尋:frontend system design interview system design mock interview database scaling design a chat application system design caching strategies system design

📄 全部影片 · 主題區: 網路與 API 基礎