FE Day 45 延伸路線:全端工程師的下一步
執行需求:CPU 可跑。今天是「前端開發實戰:React 與 Next.js 全套」系列的最後一天。今天不學新框架、不裝新套件、不寫產品功能,而是把「下一步該往哪裡走」變成一條可以執行的路線:第一,用 Day 44 的能力盤點找出自己的缺口,而不是憑感覺決定要學什麼;第二,把缺口排成一份 90 天的計畫,每一週都有具體產出;第三,建立一份個人技術雷達,分成「採用、試驗、評估、暫緩」四環,讓追逐新工具這件事有節制;第四,把預約系統延伸成三個新作品的提案,用作品驅動學習。今天所有內容都是虛構示範,沿用 Day 31–44 的專案設定與資料格式,全部在本機 CPU 上就能跑。
引言
學完一個系列之後最危險的狀態,是「知道很多名詞,但不知道自己缺什麼」。最常發生的兩件事:一是繼續看更多教學,把學習本身當成產出,看了一百小時卻沒有多一個能用的作品;二是追著最新的工具跑,每次重寫都讓上一個作品變成沒人維護的孤島。兩者的共同問題不是「不夠努力」,而是「沒有方向」。
貫穿專案的「預約管理系統」是個小型服務業線上預約平台(情境涵蓋攝影棚、健身教練、諮詢工作室,所有資料都是虛構示範)。Day 44 結案時它是 11 個頁面、兩種角色、可測試、可部署、可交接的 v1.0.0。這是一個「完整但不夠深」的作品:它證明了你能把需求做成系統,還沒有回答「能把它做多深」。今天要把「深」與「廣」兩條路畫出來,並排出先後順序。
今天的內容分四段:第一段做最後一次對照,說明哪些能力已具備;第二段說明 T 型能力、作品驅動學習、技術雷達三個觀念;第三段實作缺口分析、90 天計畫、技術雷達、三個延伸提案與開源貢獻流程;第四段講長期學習的節奏。讀完之後你會拿到一份可以照著跑的 90 天計畫,以及一套判斷「這個新東西該不該花時間」的準則。
貫穿專案共用設定(Day 31–44 沿用)
最後一天同樣沿用這份設定,作為「已經具備什麼」的對照基準:
- 框架:Next.js 15(App Router、Server Components 預設)、React 19.x、TypeScript 5.9
- 樣式:Tailwind CSS 4.x、CSS variables 設計 token、
components/ui/六個基礎元件 - 資料層:
lib/api/依NEXT_PUBLIC_API_MODE切換 mock 與 live,後端為 Web 系列 Day 35–44 的 FastAPI - 認證:JWT access token 與 refresh token 雙 token、角色導向、三層權限檢查
- 品質:Vitest 3.x、Playwright 1.5x、axe-core 4.x、ESLint 9 flat config、效能預算
- 維運:Vercel 三層環境變數、CI workflow、Runbook、七份交接資料
- 版本:v1.0.0(2026-04-15)
把清單攤開,缺口集中在三處:資料的持久化與查詢(只會呼叫別人寫好的 API,未設計過 schema 與索引)、系統的規模化(單一服務、單一環境,未處理多租戶、快取層、佇列)、觀測與營運的深度(只有錯誤回報與效能指標,沒有追蹤與告警策略)。Day 44 的結案報告也列出三個待補方向(邊界處理、同時編輯、國際化)。這些缺口不是「學得不夠」,而是「作品規模還沒逼你遇到」;今天的路線就是刻意去遇到它們。
原理解念:T 型能力、作品驅動學習與技術雷達
第一個觀念是「T 型能力」。T 的橫線代表廣度:你對前端的路由、樣式、測試、部署、無障礙都有基本掌握。T 的豎線代表深度:在其中一到兩個領域,你的理解深到能解決別人解決不了的問題。橫線讓你具備「把東西做出來」的能力,豎線讓你具備「被需要」的價值。多數人的問題是橫線夠長但沒有豎線,於是永遠停在「什麼都會一點」。選豎線的原則是:挑「難題需要長時間累積、短期不會被工具取代」的方向;以本系列的範圍來說,資料層設計、可觀測性、無障礙都是不錯的候選。
第二個觀念是「作品驅動學習」。看教學的知識留存率遠低於「為了解決一個真實問題而查資料」。原因是教學給你整理好的路徑,真實問題卻會逼你面對取捨:索引該建在哪個欄位、快取要失效幾秒、錯誤要重試還是放棄。取捨才是能力。所以 90 天計畫不是「第一週學 X、第二週學 Y」,而是「第一到四週把預約系統接上真實資料庫」,把學習綁在具體交付上;產出永遠是「可以打開來看的東西」,不是「讀完的章節數」。
第三個觀念是「技術雷達」。技術雷達是 ThoughtWorks 提出的一種溝通工具,把技術分成四個環:採用(已驗證、可以放心用在正式專案)、試驗(在非關鍵路徑上試用,值得投入時間)、評估(只讀資料與做小實驗,不投入)、暫緩(明確不採用,記錄原因)。雷達的價值不在「選對工具」,而在「節制」:每年只把少數東西移進「採用」環,其餘留在評估或暫緩。沒有雷達的人被每次發布推著走;有雷達的人會問「它解決了我現在的哪個問題」,答案是「沒有」就留在評估環。
三個觀念合起來就是今天的節奏:用缺口分析決定豎線方向、用作品綁定學習、用雷達控制新工具流入。三件事都不需要寫程式,但都需要寫下來。
完整實作:缺口分析、90 天計畫、技術雷達與延伸提案
第一步,寫缺口分析腳本。Day 44 的能力盤點每項都有「證據」但沒有等級,今天補上等級欄位,再用腳本把等級最低的挑出來。關鍵是「由資料決定學習順序」,而不是由心情決定。
// scripts/find-gaps.mjs
// 讀能力盤點,挑出等級為「入門」或缺少證據的能力,當成下一步的優先能力。
// 執行:node scripts/find-gaps.mjs
const SKILLS = [
{ skill: 'TypeScript 型別設計', level: '熟練', evidence: 'strict 全開、公開介面明確型別' },
{ skill: 'React 元件與狀態', level: '熟練', evidence: '設計系統 6 元件、登入狀態機' },
{ skill: 'Next.js App Router', level: '熟練', evidence: '11 頁、Server 與 Client 邊界、Route Handler' },
{ skill: '資料庫與 schema 設計', level: '入門', evidence: '只呼叫既有 API,未設計過資料表' },
{ skill: '快取與一致性', level: '入門', evidence: '只用過 ISR 與 TanStack Query 預設值' },
{ skill: '可觀測性', level: '入門', evidence: '只接過錯誤回報與效能指標,沒有追蹤與告警' },
{ skill: '測試策略', level: '熟練', evidence: '三層測試與 CI 守門' },
{ skill: '無障礙與響應式', level: '熟練', evidence: 'axe 掃 11 頁、四斷點檢查' },
{ skill: '部署與維運', level: '中等', evidence: '單一環境部署、Runbook 已建立' },
];
const ORDER = ['入門', '中等', '熟練'];
const gaps = SKILLS.filter((item) => ORDER.indexOf(item.level) <= ORDER.indexOf('中等'))
.sort((a, b) => ORDER.indexOf(a.level) - ORDER.indexOf(b.level));
console.log('=== 優先補強(依等級排序)===');
for (const gap of gaps) {
console.log(`[${gap.level}] ${gap.skill}|現況:${gap.evidence}`);
}
console.log('');
console.log('建議:把「入門」的能力排進 90 天計畫的前 8 週,每週一個具體交付。');
第二步,把 90 天計畫寫成資料。原則是「每一週都有一個能打開來看的產出」,並刻意混搭深度與廣度:前 8 週主攻資料層與可觀測性,之後回到橫線補強。
// docs/PLAN-90.mjs
// 90 天學習計畫:每一週都綁定一個具體交付,而不是「讀完某章」。
export const PLAN = [
{
week: '第 1-2 週',
focus: '資料庫與 schema 設計',
deliverable: '把 mock 資料換成 PostgreSQL,寫出 services、bookings、users 三張表與外鍵',
check: '能用 SQL 查出一位客戶的歷史預約並解釋每個索引的用途',
},
{
week: '第 3-4 週',
focus: 'ORM 與資料存取層',
deliverable: '用 ORM 改寫 lib/api 的 live 分支,型別由 schema 自動產生',
check: '移除一個手寫型別檔而型別檢查仍通過',
},
{
week: '第 5-6 週',
focus: '查詢效能與索引',
deliverable: '為後台的預約清單加上分頁與篩選,並用查詢計畫驗證索引被使用',
check: '在十萬筆資料下把清單查詢壓在 50 毫秒內',
},
{
week: '第 7-8 週',
focus: '快取與一致性',
deliverable: '為公開服務頁加上快取層,並定義失效時機與標籤',
check: '改動服務資料後,30 秒內全站看到新資料',
},
{
week: '第 9-10 週',
focus: '可觀測性',
deliverable: '加入結構化紀錄、追蹤與告警規則,串接既有的監控層',
check: '能從一筆錯誤回報追到對應的後端請求與資料庫查詢',
},
{
week: '第 11 週',
focus: '國際化與在地化',
deliverable: '把介面文案抽成資源檔,加入繁體中文與英文兩套',
check: '切換語言後所有頁面不出現未翻譯文字',
},
{
week: '第 12 週',
focus: '回顧與作品化',
deliverable: '把這 90 天的成果整理成一份新的結案報告與示範環境',
check: '陌生人能在 10 分鐘內照著說明跑起來並完成一次預約',
},
];
第三步,建立技術雷達。雷達要回答「這個東西現在該不該碰」,所以每一項都寫下「為什麼放在這一環」;刻意只放少數幾項,因為它的價值來自可以一眼看完。
// docs/RADAR.mjs
// 個人技術雷達:adopt 採用、trial 試驗、assess 評估、hold 暫緩。
// 每季更新一次,移動條目時必須寫下理由。
export const RADAR = {
adopt: [
{ name: 'TypeScript strict 模式', why: '已在本系列專案驗證,能擋下多數欄位與空值錯誤' },
{ name: 'Playwright', why: '端對端與無障礙檢查共用一套工具,CI 成本可接受' },
{ name: 'Tailwind CSS 4.x 設計 token', why: '主題集中在 CSS variables,換色不需要改元件' },
],
trial: [
{ name: '關聯式資料庫加 ORM', why: '下一個作品的主要學習目標,先在非關鍵路徑試用' },
{ name: '結構化紀錄與追蹤', why: '目前只有錯誤回報,缺少可追查的請求脈絡' },
],
assess: [
{ name: '邊緣執行環境', why: '對本系列規模沒有立即效益,先讀資料與做小實驗' },
{ name: '前端狀態機工具', why: '目前 useReducer 足夠;等真的出現複雜狀態再評估' },
],
hold: [
{ name: '為換而換的框架遷移', why: 'v1.0.0 已驗證,遷移只會讓所有驗證重來一次' },
{ name: '在沒有需求前導入微前端', why: '單一團隊單一應用,切分只增加維運負擔' },
],
};
第四步,把預約系統延伸成三個新作品。延伸比從零開始划算,因為路由、設計系統、測試與 CI 都能重用,學習成本集中在真正的新東西上。每個提案都要寫清楚使用情境、主要操作與獨特之處。
// docs/EXTENSIONS.mjs
// 由預約系統延伸的三個作品提案:重用既有的設計系統與測試層。
export const EXTENSIONS = [
{
name: '多租戶預約平台',
scenario: '讓多間小型工作室各自登入,各自管理服務、時段與客戶',
mainFlow: '註冊工作室、設定服務與時段、客戶在自己的子網域預約',
uniqueness: '同一套程式碼服務多個租戶,資料隔離是最核心的技術挑戰',
newSkills: ['資料表加上租戶維度', '行級權限', '子網域路由'],
},
{
name: '課程預約與行事曆同步',
scenario: '語言家教的團體班預約,老師與學生共用一份行事曆',
mainFlow: '課程開班、學生選班、預約成功後產生行事曆連結',
uniqueness: '預約與外部行事曆雙向同步,衝突偵測是主要難題',
newSkills: ['行事曆資料格式', '雙向同步與衝突處理', '背景工作'],
},
{
name: '營運報表工具',
scenario: '把預約資料整理成工作室每週要看的使用率與營收報表',
mainFlow: '選擇期間、產生報表、匯出並排程寄送',
uniqueness: '同一份資料要能同時支援即時查詢與大量彙總',
newSkills: ['彙總查詢與物化檢視', '排程工作', '檔案匯出'],
},
];
第五步,寫一支每天會用的提醒腳本。計畫失敗最常見的原因不是計畫不好,而是「忘記現在該做哪一週」。這支腳本讀計畫、算出目前第幾週、印出交付與檢查點,讓「今天要做什麼」變成一行指令。
// scripts/next-steps.mjs
// 依開始日期算出目前應在計畫的第幾週,印出該週的交付與檢查點。
// 執行:node scripts/next-steps.mjs
import { PLAN } from '../docs/PLAN-90.mjs';
const START = new Date('2026-04-17T00:00:00+08:00');
const MS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
const elapsedWeeks = Math.floor((Date.now() - START.getTime()) / MS_PER_WEEK);
const index = Math.min(Math.max(elapsedWeeks, 0), PLAN.length - 1);
const current = PLAN[index];
console.log(`=== 第 ${elapsedWeeks + 1} 週 ===`);
console.log(`主題:${current.focus}`);
console.log(`本週交付:${current.deliverable}`);
console.log(`通過標準:${current.check}`);
if (elapsedWeeks >= PLAN.length) {
console.log('');
console.log('90 天計畫已完成,請更新能力盤點並重建技術雷達。');
}
第六步,把「嚴格度升級」也排進計畫。TypeScript 的 strict 只是起點,還有幾個更嚴格的旗標可以逐步開啟。與其一次全開而面對上百個錯誤,不如寫一支腳本先盤點影響範圍,再一項一項打開。
// scripts/check-strictness.mjs
// 盤點開啟更嚴格的型別旗標後會有多少錯誤,決定升級順序。
// 執行:node scripts/check-strictness.mjs
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const run = promisify(execFile);
const FLAGS = [
'noUncheckedIndexedAccess',
'exactOptionalPropertyTypes',
'noImplicitOverride',
'noUnusedLocals',
];
for (const flag of FLAGS) {
try {
await run('pnpm', ['exec', 'tsc', '--noEmit', '--strict', `--${flag}`], { shell: true });
console.log(`通過 ${flag}`);
} catch (error) {
const output = String(error.stdout ?? '');
const count = output.split('\n').filter((line) => line.includes('error TS')).length;
console.log(`待處理 ${flag}:${count} 處`);
}
}
第七步,把開源貢獻排成可執行的流程。這是「用別人的真實問題練功」最便宜的方式,門檻比想像中低:從型別定義缺漏、重現步驟清楚的 bug 開始。重點是「先確認對方想不想收」再動手。
# 開源貢獻的標準流程(以修一個型別定義缺漏為例)
# 1. 先找有 good first issue 標籤的議題,並在議題下留言說明你要處理
git clone git@github.com:<owner>/<repo>.git
cd <repo>
git checkout -b fix/typing-for-slot-response
# 2. 依專案的 CONTRIBUTING 說明安裝與執行測試
pnpm install
pnpm test
# 3. 小範圍修改,並補上一個會失敗的測試(先寫測試再修)
git add src/types/slot.ts tests/slot.test.ts
git commit -m "fix(types): 修正時段回應的欄位型別"
# 4. 推上自己的 fork 並開 PR,說明「問題、重現、修法、測試」
git push origin fix/typing-for-slot-response
第八步,把學習筆記與新作品的起手式固定下來。每學一個主題就留一份「給三個月後的自己」的筆記:原本以為什麼、實際學到什麼、踩到哪個坑。成本很低,卻是日後寫文章與技術分享最紮實的素材。
# 建立學習筆記與新作品的目錄(與本系列相同的結構慣例)
mkdir -p notes/2026-04-postgresql notes/2026-05-observability
mkdir -p playground/multi-tenant-booking
# 每個主題一份筆記,固定三段:原本的認知、實際的發現、踩到的坑
cat > notes/2026-04-postgresql/README.md << 'EOF'
# PostgreSQL 記錄
## 原本的認知
(動手前的假設)
## 實際的發現
(用查詢計畫與實測數據說話)
## 踩到的坑
(症狀、原因、修法)
EOF
# 新作品直接沿用本系列的骨架,避免重新發明一次
pnpm create next-app@^15 playground/multi-tenant-booking \
--typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
常見錯誤與踩雷
第一個常見錯誤是「把學習計畫寫成課程清單」。「第一週讀指南、第二週看影片」這種計畫沒有驗收方式。修法是把產出改成「可以打開來看的東西」加上「通過標準」:例如「在十萬筆資料下把清單查詢壓在 50 毫秒內」可以驗證,「讀完索引章節」不行。
第二個踩雷是「只追一條豎線,卻停掉所有橫線」。90 天全投入資料庫,回來後會發現樣式與測試習慣都退步了。修法是在計畫裡保留維護型工作的固定時間:每週花兩小時跑一次既有專案的驗收、修一個小問題、更新一次交接資料。
第三個是「沒有需求就換工具」。看到新工具就想改過去,每次重構都讓已驗證的行為變回未驗證。修法就是技術雷達:新東西先放評估環、做一個小實驗,等它真的解決你正在痛的問題才移進試驗環。
第四個是「只做作品,不留紀錄」。做完作品卻說不出「解決了哪個難題」很吃虧。修法是把寫下來當成作品的一部分:每個作品補一份結案報告,每個主題留一份三段式筆記,逼自己把經驗從感覺整理成可複述的知識。
第五個是「把開源貢獻想得太難」。很多人以為要修核心程式碼才算貢獻,所以不敢開始。最常見也最受歡迎的貢獻其實是:補一段缺失的型別定義、補一個重現步驟。
效能與實務提醒
學習時間的分配有個實用比例:六成動手、三成讀資料、一成與人交流。動手不一定要做大專案,修一個 bug、寫一個小工具都算;重點是「有回饋」:跑測試、看查詢計畫、量效能數字。
另一個提醒是「把標準提高當成練習」。第六步的嚴格度升級就是這個思路:noUncheckedIndexedAccess 會逼你處理每個可能的空值,訓練的是「不確定就明講」的習慣。同樣的練習還有逐步收緊 ESLint、覆蓋率門檻與效能預算;這些不會讓功能變多,但會讓你的下限上升。
技術選擇上要記得「可搬移的能力優先」:schema 設計原則、查詢的最佳化思路、快取失效策略、可觀測性的三個支柱(紀錄、指標、追蹤)在不同工具之間相通;特定套件的 API 細節則很可能兩年後過期。把力氣放在「為什麼」與「什麼情況下不適用」。
最後是「公開展示」的成本效益。把作品放上線、把過程寫成文章,會回饋三件事:真實環境逼你處理原本會忽略的細節(憑證、環境變數、錯誤回報)、別人的提問暴露理解盲點。
小結
今天把「學完之後怎麼辦」變成一條可執行的路線:缺口分析腳本、90 天計畫、技術雷達、三個延伸提案、每日提醒腳本、型別嚴格度盤點腳本,以及開源貢獻與學習筆記的固定流程。全部不需要新增任何執行期依賴。
這份路線的核心是「把方向寫下來」。四個放在一起,就構成一個能自我修正的迴圈:做完一週的交付、通過一次檢查、更新一次盤點與雷達,然後決定下一週。這個迴圈可以一直重複,與你用什麼框架無關。
也要提醒:路線是為了服務作品,不是反過來。如果某一週結束後你更想深入另一個題目,就改計畫——但要把「為什麼改」寫下來。被修改過的計畫仍是計畫;沒寫下來的計畫才是真的不存在。
結語
45 天前,我們從「後端工程師的前端地圖」開始,先建立環境與工具鏈,走過 TypeScript 型別系統、React 19.x 的元件與狀態、表單與資料取得,接著進入 Next.js 15 的 App Router、Server Components、Server Actions、認證與 Route Handler,再補上效能、測試、無障礙、部署與監控,最後用 14 天把這些零件組成一個能上線、能驗收、能交接的預約管理系統前端 v1.0.0。順序是刻意的:工具先於框架、品質在框架之後、專案在最後——只有真的做完一次,每個名詞才會有位置。
這 45 天真正留下的不只是 11 個頁面或一套測試,而是一組可重複使用的習慣:動手前先定義路由與契約、把主觀判斷轉成可驗證的門檻、把規範寫成檢查項而不是靠記憶、把限制誠實寫進交接資料、用作品驅動學習。這些習慣不綁定版本號,明年、後年都適用。
下一步的三個方向今天已經各有起點。更深:把資料層做起來——設計 schema、寫查詢、看查詢計畫、處理快取與一致性,這是把「會串 API」變成「會設計資料」的分界。更廣:補上可觀測性與國際化,讓系統在沒人盯著時也能被理解。更實:把預約系統延伸成多租戶平台或行事曆同步作品,讓同一套骨架長出第二、第三個能公開展示的成果。挑一條,跑完一週,回來更新盤點與雷達,再挑下一條。這就是全端工程師的下一步:不是換一個更大的框架,而是把同一個問題做得更深、更廣、更完整。
延伸資源
- ThoughtWorks 技術雷達:
https://www.thoughtworks.com/radar,四環分類與每期的技術動態。 - PostgreSQL 官方說明:
https://www.postgresql.org/docs/,資料表、索引與查詢計畫的完整說明。 - OpenTelemetry 官方說明:
https://opentelemetry.io/docs/,紀錄、指標與追蹤三種訊號的標準做法。 - WCAG 2.2 官方規格:
https://www.w3.org/TR/WCAG22/,把無障礙從檢查清單推進到設計原則。 - GitHub 開源指南:
https://opensource.guide/,第一次貢獻開源專案的流程與禮儀。 - Day 44 系列總結:原文連結,v1.0.0 的結案報告與待補方向。
留言
張貼留言