結論先講
你有沒有過這種經驗:加入新公司第一天,花了整整八小時還沒把本地開發環境跑起來?README 寫著「直接 npm start」,結果缺了五個環境變數、三個系統套件,還有一個只有某個前輩腦中才有的 workaround。
開發者體驗(DX)就是讓工程師不要把時間浪費在跟程式碼無關的事情上。 好的 DX 讓新人第一天就能送出 PR,壞的 DX 讓資深工程師也想離職。
這篇是系列的最後一篇,也是最容易被忽略的一篇。因為 DX 不會直接產出商業價值,所以常常被犧牲。但它影響的是整個團隊的生產力和幸福感。
體檢清單
1. README 品質
一個好的 README 至少要有:
# Project Name
一句話說明這個專案是什麼。
## Quick Start
git clone ...
cp .env.example .env
docker compose up -d
npm install
npm run dev
# 打開 http://localhost:3000
## Architecture
簡單的架構圖或說明。
## Tech Stack
- Frontend: Next.js 14, TypeScript, Tailwind
- Backend: FastAPI, PostgreSQL, Redis
- Infra: Docker, GitHub Actions, AWS
## Development
### Prerequisites
- Node.js 20+
- Docker Desktop
- ...
### Available Commands
- `npm run dev` - 啟動開發伺服器
- `npm run test` - 跑測試
- `npm run lint` - 跑 linter
- ...
## Deployment
如何部署到各環境。
## Contributing
如何貢獻程式碼。- README 有且內容是最新的
- 有 quick start 可以五分鐘內跑起來
- 有 tech stack 說明
- 有 available commands 列表
2. Onboarding Guide
README 是給所有人看的,onboarding guide 是給新人看的。
# 新人上手指南
## 第一天
1. 設定開發環境(按照 README)
2. 閱讀架構文件
3. 閱讀 coding conventions
4. 認領一個 "good first issue"
## 第一週
1. 完成一個小 PR
2. 參加 code review(觀摩)
3. 了解部署流程
4. 了解值班制度
## 第一個月
1. 獨立完成一個 feature
2. 開始參與 code review(審查)
3. 了解系統全貌- 有 onboarding 文件
- 有 “good first issue” label
- 有 buddy / mentor 制度
- 新人第一天能跑起開發環境
3. 一鍵啟動本地開發環境
新人 clone 下來,一個指令就能跑。 這是 DX 的黃金標準。
# 理想狀態
git clone git@github.com:company/project.git
cd project
make dev # 或 ./scripts/setup.sh
# 這個指令應該做到:
# 1. 安裝依賴
# 2. 設定環境變數(從 .env.example 複製)
# 3. 啟動 Docker 容器(DB、Redis 等)
# 4. 跑 migration 和 seed
# 5. 啟動開發伺服器# Makefile 範例
.PHONY: dev setup test
setup:
cp -n .env.example .env || true
docker compose up -d
npm install
npm run db:migrate
npm run db:seed
dev: setup
npm run dev
test:
docker compose -f docker-compose.test.yml up -d
npm run test
docker compose -f docker-compose.test.yml down- 一個指令(
make dev或npm run setup) - Docker Compose 管理外部依賴
- 有
.env.example - 有 seed data
4. Linting / Formatting(自動化)
永遠不要在 code review 裡討論程式碼風格。 讓工具來處理。
// .husky/pre-commit
// #!/usr/bin/env sh
// npx lint-staged
// package.json
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml}": ["prettier --write"]
}
}// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100
}- ESLint + Prettier(或 Biome)
- Pre-commit hook 自動格式化(Husky + lint-staged)
- CI 也跑 lint(雙保險)
- 團隊統一的規則(不是每個人各自設定)
5. PR Template
<!-- .github/pull_request_template.md -->
## What does this PR do?
<!-- 簡短說明這個 PR 做了什麼 -->
## Why?
<!-- 為什麼要做這個改動 -->
## How to test?
<!-- 如何測試這個改動 -->
1.
2.
3.
## Screenshots (if UI change)
<!-- 如果有 UI 變動,附上截圖 -->
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated (if needed)
- [ ] No console.log left
- [ ] Self-reviewed the diff- 有 PR template
- Template 包含 what/why/how to test
- 有 checklist
6. Code Review Guidelines
# Code Review 原則
## 作為 Reviewer
- 24 小時內回覆(至少 acknowledge)
- 區分 "must fix"、"suggestion"、"nit"
- 給建設性回饋,不是批評
- 大 PR 可以要求拆分
## 作為 Author
- PR 盡量小(< 400 行)
- 寫清楚 PR description
- Self-review 後再請人看
- 回覆所有 comment
## Convention
- 使用 Conventional Comments:
- `suggestion:` 建議但不強制
- `issue:` 需要修改
- `question:` 想了解原因
- `nitpick:` 非常小的事
- `praise:` 稱讚好的寫法- 有 code review guidelines
- Review 有時間限制(24h 內回覆)
- 有 comment convention
- 大 PR 會被要求拆分
7. 文件系統(ADR、Runbook)
ADR(Architecture Decision Record)
<!-- docs/adr/001-use-postgresql.md -->
# ADR 001: 使用 PostgreSQL 作為主要資料庫
## Status: Accepted
## Context
我們需要選擇一個關聯式資料庫。團隊有 PostgreSQL 和 MySQL 的經驗。
## Decision
選擇 PostgreSQL。
## Reasons
- JSONB 支援好,未來可能需要彈性 schema
- 全文搜尋內建
- 授權比 MySQL (GPL) 友善
- 團隊多數人較熟悉
## Consequences
- 需要學習 PostgreSQL 特有的語法
- 部署需要 PostgreSQL 16+Runbook
<!-- docs/runbooks/database-disk-full.md -->
# Database Disk Full
## Symptoms
- 告警:DiskWillFull
- 寫入操作失敗
## Steps
1. 確認磁碟使用率:`df -h`
2. 檢查大表:`SELECT relname, pg_size_pretty(pg_total_relation_size(oid)) FROM pg_class ORDER BY pg_total_relation_size(oid) DESC LIMIT 10;`
3. 清理可能的候選:
- 舊的 audit logs(超過 90 天的可以刪)
- 過期的 sessions
4. 如果需要緊急空間:擴展 EBS volume
5. 長期:設定自動清理 cron job
## Escalation
如果磁碟 > 95%,聯繫 SRE 團隊。- 重要決策有 ADR
- 常見問題有 runbook
- 文件跟程式碼放在一起(
docs/目錄) - 有人負責維護文件(不然會腐爛)
8. Development Container
// .devcontainer/devcontainer.json
{
"name": "My Project",
"dockerComposeFile": "../docker-compose.yml",
"service": "dev",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "20" },
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" }
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"postCreateCommand": "npm install && npm run db:migrate"
}- 有 Dev Container 或 Docker-based 開發環境
- 預裝必要的 VS Code extensions
- 預設 editor settings
9. Seed Data
// seeds/development.ts
async function seed() {
// 建立測試帳號
await db.users.createMany([
{ email: 'admin@dev.local', role: 'admin', password: hash('password') },
{ email: 'editor@dev.local', role: 'editor', password: hash('password') },
{ email: 'viewer@dev.local', role: 'viewer', password: hash('password') },
]);
// 建立測試資料
await db.articles.createMany([
{ title: 'Test Article 1', authorId: admin.id, status: 'published' },
{ title: 'Draft Article', authorId: editor.id, status: 'draft' },
]);
console.log('Seed completed!');
}- 有 seed script
- 涵蓋各種角色和狀態
- 資料量足以測試分頁、搜尋等功能
- Seed 可以重複跑(idempotent)
10. Hot Reload
- 前端有 HMR(Hot Module Replacement)
- 後端有 file watching(nodemon、uvicorn —reload)
- 改 code 後 < 3 秒看到結果
11. IDE Config
# .editorconfig
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.tsdk": "node_modules/typescript/lib"
}
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"prisma.prisma"
]
}-
.editorconfig(跨 IDE 統一) -
.vscode/settings.json(VS Code 設定) -
.vscode/extensions.json(推薦的 extensions) - 不要 commit 個人化設定
DX 成熟度對照
| 等級 | 特徵 | 新人 setup 時間 |
|---|---|---|
| L0 糟糕 | 沒有 README、問前輩才知道怎麼跑 | 2-3 天 |
| L1 基本 | 有 README、但步驟很多 | 半天 |
| L2 不錯 | Docker Compose + seed、一鍵啟動 | 1 小時 |
| L3 優秀 | Dev Container、完整文件、自動化 | 15 分鐘 |
| L4 頂級 | Codespaces/Gitpod、即開即用 | 5 分鐘 |
DX 投資回報計算
假設:
- 團隊 5 人
- 每人每天因 DX 不好浪費 30 分鐘
- 工程師月薪 8 萬台幣
每月浪費 = 5 人 × 30 分鐘 × 22 天 = 55 小時
換算金額 = 55 × (80000 / 176) ≈ 25,000 台幣/月
投入 2 週(80 小時)改善 DX:
成本 = 80 × 455 ≈ 36,400 台幣
回收期 = 36,400 / 25,000 ≈ 1.5 個月
結論:DX 改善的 ROI 非常好。
FAQ
Q1: DX 這些東西誰來做?什麼時候做?
每個 sprint 留 10-15% 的時間做。不需要一次到位,每週改善一點。可以輪流由不同的人負責(developer experience champion)。新人加入時最能發現 DX 的問題,讓新人記錄下來是很好的做法。
Q2: PR 大小怎樣算合理?
經驗法則:差異在 400 行以內。超過 400 行的 PR,reviewer 的注意力會急劇下降,review 品質也會跟著掉。如果 feature 很大,拆成多個 PR(feature flag 控制上線)。
Q3: ADR 需要多正式?
不需要很正式。一個 Markdown 檔案,記錄 context、decision、reasons 就好。重點是「未來的自己(或新同事)能理解當初為什麼這樣決定」。不需要開會審批,PR review 就好。
Q4: 每個專案都要 Dev Container 嗎?
不一定。如果你的專案只需要 Node.js,本地跑就好。Dev Container 最有價值的場景是:需要多個系統依賴(特定版本的 Python + Node + 系統套件)、或團隊成員用不同 OS。
Q5: 文件怎麼維持更新?
兩個策略:1) 文件放在程式碼旁邊(docs/ 目錄),隨 code 一起 review。2) 定期的 documentation audit(每季一次,檢查文件是否過期)。最重要的是建立文化——改了 code 就更新相關文件,就像寫了 code 就寫 test 一樣自然。
系列導航
| # | 文章 | 狀態 |
|---|---|---|
| 01 | 好的前端專案該有什麼?一張體檢表 | |
| 02 | 好的後端框架需要具備哪些功能? | |
| 03 | 好的 API 該長什麼樣? | |
| 04 | 好的資料庫設計需要什麼? | |
| 05 | 好的基礎建設需要什麼? | |
| 06 | CD Pipeline 需要什麼? | |
| 07 | 好的監控系統需要什麼? | |
| 08 | 好的開發者體驗(DX)需要什麼? | 📍 你在這裡 |