Module 0.0.1 — First Principles Thinking
Context (Bối cảnh)
Bạn đã học JavaScript 1-2 năm. Bạn biết useEffect, biết async/await, biết cách config Webpack, biết "best practice" là dùng const thay vì `var". Nhưng khi được hỏi "Tại sao?", bạn thường trả lời: "Vì mọi người bảo vậy", "Vì ESLint khuyến nghị", hoặc "Vì nó nhanh hơn" — mà không biết nhanh hơn ở đâu, với ai, trong điều kiện nào.
Module này không dạy syntax. Module này dạy bạn cách hỏi trước khi học bất kỳ syntax nào. Đây là nền tảng của toàn bộ lộ trình.
Mục tiêu: Sau module này, bạn sẽ không còn hài lòng với câu trả lời "Vì nó là best practice". Bạn sẽ đòi hỏi cơ chế, constraint, và trade-off.
Prerequisites (Kiến thức cần có)
- Không có prerequisite kỹ thuật.
- Bạn đã từng copy-paste code từ Stack Overflow/ChatGPT và không hiểu tại sao nó chạy.
- Bạn đã từng nói câu "Dùng A thay B vì A tốt hơn" mà không định lượng được "tốt hơn" ở đâu.
Knowledge Building (Xây dựng kiến thức)
A. First Principles Thinking (Tư duy nguyên lý đầu tiên)
Definition (Định nghĩa) — L1
Nhận thức phổ biến
"First principles là phải tự mình nghĩ ra mọi thứ, không được dựa vào kiến thức của người khác. Nếu tôi không tự nghĩ ra được, nghĩa là tôi chưa đủ giỏi."
→ Vấn đề: Đây là một cách hiểu sai. First principles không có nghĩa là phải tự phát minh lại mọi thứ. Phương pháp này là đi ngược về những sự thật cơ bản nhất, những điều có thể kiểm chứng và khó có thể phủ nhận, rồi từ đó tự xây dựng cách hiểu và cách giải quyết vấn đề — thay vì chỉ làm theo cách người khác đã làm.
Định nghĩa đúng
First Principles Thinking là cách chia một vấn đề phức tạp thành những sự thật cơ bản nhất, sau đó từ những sự thật đó xây dựng lại cách hiểu hoặc cách giải quyết vấn đề.
Thay vì suy nghĩ theo kiểu:
"Người khác làm như vậy, nên tôi cũng làm như vậy."
Ta hỏi:
"Điều gì thực sự đúng ở đây? Vì sao nó đúng? Nếu bỏ hết những giả định và cách làm có sẵn, tôi sẽ xây dựng lại vấn đề này như thế nào?"
"Không phải 'tự nghĩ ra mọi thứ'. Mà là 'hiểu rõ điều gì thực sự đúng trước khi đồng ý'."
Feel It (Trực quan hóa) — L2
Junior nhìn thấy một bug: "UI bị freeze khi scroll table 10k rows". Junior nghĩ: "Chắc do React render chậm. Mình sẽ thêm React.memo vào từng row."
Junior nhìn thấy: một symptom → nghĩ đến một solution quen thuộc → apply ngay.
Staff nhìn thấy cùng một bug: "UI bị freeze khi scroll table 10k rows". Staff hỏi:
- "Freeze xảy ra ở phase nào của rendering pipeline? Layout, Paint, hay Composite?"
- "10k rows có nằm trong DOM cùng lúc không, hay chỉ là virtual scroll?"
- "Nếu là Layout thrashing,
React.memokhông giải quyết được gì cả."
Staff nhìn thấy: một symptom → suy nghĩ ra một cây câu hỏi → kiểm thử từng câu và tìm root cause → solution phù hợp với constraint thực tế.
Visualization:
JUNIOR MENTAL PATH:
Symptom ──────► "Tôi từng gặp cái này" ──────► Solution A (memo)
▲ │
└──────────────────────────────────────────────┘
(Loop: nếu không work, thử Solution B)
STAFF MENTAL PATH:
Symptom ──► "Điều gì KHÔNG THỂ SAI ở đây?"
│
▼
┌─────────────────────────────┐
│ 1. Browser render pipeline │
│ 2. React reconciliation │
│ 3. Main thread blocking │
└─────────────────────────────┘
│
▼
"Trong 3 cái này, cái nào KHÔNG THỂ gây freeze ở scroll?"
│
▼
Root Cause ──► Constraint ──► DecisionThe Gist (Ý chính) — L3
4 điểm cốt lõi:
First Principles không phải "không dùng best practice" — mà là "hiểu tại sao nó tồn tại trước khi dùng".
Điểm 1: Best practice là kết quả, không phải nguyên nhân
Best practice (
const>var,useMemocho heavy compute, v.v.) là kết quả của hàng nghìn lần thử-nghiệm dưới constraint (ràng buộc) cụ thể. Nếu bạn copy kết quả mà không biết constraint, bạn sẽ apply sai context.Ví dụ: "Dùng
constthayvar" là best practice. Nhưng tại sao?- Không phải vì
const"tốt hơn" — mà vìvarcó function scope + hoisting tạo ra behavior không thể suy luận từ code structure (lexical scope violation). constthêm assignment immutability ở binding level, giảm cognitive load (gánh nặng nhận thức) khi đọc code.- Nếu bạn chỉ biết "dùng
constvì best practice", bạn sẽ không hiểu tại saoconst obj = {}vẫn mutate được property.
javascript// Junior: "Dùng const vì best practice" const config = { timeout: 5000 }; config.timeout = 10000; // ❌ Junior bối rối: "Sao const lại đổi được?" // Staff: "const chỉ bảo vệ binding, không bảo vệ value. // Nếu cần immutable config, phải dùng Object.freeze hoặc structuredClone."- Không phải vì
Phương pháp Socrates (Socratic method) là công cụ chính: hỏi "Tại sao?" 3-5 lần liên tiếp cho đến khi chạm fundamental truth.
Điểm 2: Socratic Questioning Chain
Scenario: "Dùng Vite thay Webpack."
- Lần 1: Tại sao dùng Vite?
- "Vì dev server nhanh."
- Lần 2: Tại sao Vite nhanh hơn?
- "Vì trong development, Vite tận dụng native ES Modules của browser và không cần bundle toàn bộ app trước"
- Lần 3: Tại sao native ES Modules nhanh hơn bundling ở dev?
- "Vì Vite không phải xử lý và gom toàn bộ dependency graph ngay khi khởi động. Browser có thể yêu cầu các module khi cần."
- Lần 4: Tại sao xử lý ít hơn lúc startup lại nhanh?
- "Vì dev server có ít công việc phải làm trước khi app có thể chạy. Khi sửa code, Vite cũng chỉ cần xử lý phần liên quan thay vì rebuild toàn bộ."
- Lần 5: Vậy nếu project có 5000 modules, native ES Modules vẫn nhanh hơn không?
- Fundamental truth: Không chắc. Tốc độ còn phụ thuộc vào số lượng module, cách browser tải module, network protocol, kích thước dependency và cách project được tổ chức. HTTP request overhead (HTTP/1.1 limit) có thể thắng. Vite nhanh ở điều kiện HTTP/2 + ít modules. Nếu bạn không biết điều kiện này, bạn sẽ chọn sai tool cho legacy project trên HTTP/1.1. Vì vậy, "Vite nhanh hơn" không phải là một sự thật tuyệt đối; nó đúng trong những điều kiện nhất định.
Staff insight: Mỗi lần hỏi "tại sao", bạn đang đào xuống một abstraction layer sâu hơn. Ban đầu bạn thấy một kết luận như "Vite nhanh hơn". Sau đó bạn tìm nguyên nhân, rồi tiếp tục tìm nguyên nhân phía sau nguyên nhân đó. Khi bạn chạm layer không thể phân rã thêm (như cách browser tải module, engine behavior, network protocol, CPU,memory layout hoặc filesystem) — đó là first principle.
- Lần 1: Tại sao dùng Vite?
"Bạn tưởng" (assumption) là kẻ thù lớn nhất. Mỗi lần bạn nói "Bạn tưởng", bạn đang dùng analogy (dựa vào điều mình nghĩ là đúng) thay vì reasoning (tự mình kiểm chứng và suy luận).
Điểm 3: Assumption Audit
Trong suốt lộ trình khóa học, bạn sẽ thường xuyên gặp prompt: "Bạn tưởng X là... → Đúng/Sai ở đâu?"
Đây không phải là cách "bắt lỗi". Đây là cách làm rõ mental model.
Ví dụ thực tế:
- Junior: "Bạn tưởng
setStatelà synchronous vì nó chạy ngay lập tức trong event handler." - Reality:
setStatelà request để React schedule update. React batch nhiềusetStatethành một re-render. "Chạy ngay" không đồng nghĩa "commit ngay".
Kỹ thuật: Giữ một "Assumption Log" — mỗi khi bạn nói "Bạn tưởng", ghi lại. Sau 1 tháng, bạn sẽ thấy pattern nhận thức sai của chính mình.
- Junior: "Bạn tưởng
Staff không hỏi "Cái này đúng không?" — Staff hỏi "Cái này đúng trong điều kiện nào?"
Điểm 4: Staff Implication — Context-Dependent Truth
Junior tìm câu trả lời binary: đúng/sai. Staff tìm câu trả lời constraint-based: đúng với điều kiện A, sai với điều kiện B.
Ví dụ: "Dùng
useMemođể optimize."- Junior: "Đúng.
useMemogiúp tránh re-render." - Staff: "Sai.
useMemocó cost (memory để giữ cache + comparison function). Nếu computation cost < comparison cost,useMemolàm chậm hơn. Nếu dependency array không stable,useMemovô dụng."
Staff question khi review code: "Nếu input này thay đổi 1000 lần/giây, solution này còn đúng không? Nếu bundle size tăng 20KB, business có chấp nhận không? Nếu Junior maintain code này sau 6 tháng, họ hiểu được không?"
Đây là lens bạn sẽ dùng xuyên suốt 151 module.
- Junior: "Đúng.
How It Works (Cách hoạt động) — L4
First Principles Thinking hoạt động qua 3 bước phân rã + 1 bước xây dựng:
Bước 1: Identify Assumptions Liệt kê tất cả những gì bạn "cho là đúng" về vấn đề. Không filter. Viết ra.
Bước 2: Deconstruct to Fundamental Truths Với mỗi assumption, hỏi: "Điều này có thể phủ nhận được không? Nếu có, nó không phải first principle."
Bước 3: Rebuild with Constraints Từ fundamental truths, xây dựng solution mới với constraint thực tế (time, memory, team size, business goal).
Analogy (có giới hạn):
First principles giống như việc bạn mua một chiếc xe đạp cũ. Junior nhìn thấy: "Bánh trước hỏng → thay bánh mới". Staff tháo rời: "Bánh hỏng vì vành cong, vành cong vì nan hoa lỏng, nan hoa lỏng vì đầu nối bị mòn. Thay bánh mới không fix root cause."
Giới hạn analogy: Trong software, "tháo rời" không phải tháo phần cứng, mà là tháo abstraction layers xuống đến engine/protocol/memory.
Nếu bạn là Staff đang review code này, bạn nhìn thấy gì?
// Junior viết:
function fetchUserData() {
const data = fetch('/api/user').then(r => r.json());
return data;
}
// Staff nhìn thấy:
// 1. Assumption: "fetch trả về dữ liệu" — Sai.
// fetch trả về Promise, tức là kết quả chưa có ngay.
// 2. Assumption: "r.json() luôn đọc được dữ liệu" — Sai.
// Nếu phản hồi không phải JSON hợp lệ, việc đọc dữ liệu có thể thất bại.
// 3. Assumption: "Không cần error handling ở đây" — Nguy hiểm,
// Architectural risk. Lỗi mạng hoặc lỗi từ máy chủ có thể xảy ra.
// 4. Fundamental truth: Network request là async,
// có thể fail ở 4+ layers: DNS, TCP, TLS, HTTP, Application (tầng ứng dụng).
// 5. Rebuild: Phải có error boundary + retry strategy + loading state.In Production (Trong thực tế) — L5
Anti-pattern: Cargo Cult Programming
"Cargo cult" (tục thờ hàng hóa) là hiện tượng các bộ lạc ở Melanesia (Thái Bình Dương) mô phỏng đường băng, tháp điều khiển và tai nghe giả từ gỗ, tre sau Thế chiến II . Họ làm vậy để mong máy bay quân sự quay lại thả hàng hóa xuống, vì họ bắt chước hình thức bề ngoài mà không hiểu bản chất khoa học phía sau.
Architectural Anti-pattern Registry — Stage 0:
- "Cargo Cult Best Practice" — áp dụng pattern (Redux, microservices, GraphQL) vì "công ty lớn dùng", không vì constraint của team mình phù hợp.
Code fix cốt lõi:
// ❌ Cargo Cult: "Dùng Redux vì Facebook dùng"
// Team 3 người, app đơn giản, nhưng có 20 files boilerplate
// → Complexity cost > Benefit
// ✅ First Principles Rebuild:
// Constraint: Team 3 người, state chủ yếu là server state.
// Fundamental truth: Server state != Client state.
// Decision: Dùng TanStack Query cho server state, Zustand cho client state.
// Trade-off: Mất ecosystem Redux DevTools, được simplicity.War Story: "Chọn State Management" — Staff Decision Simulation
Context
Team 5 FE engineers, startup SaaS, vừa nhận funding Series A. Product là dashboard quản lý task. PM yêu cầu thêm real-time collaboration (multiple users edit cùng task).
Constraint
- Tech: App hiện tại dùng React + Zustand. Chưa có real-time layer.
- Business: 3 tháng để ship. Không có dedicated backend engineer cho FE (kĩ sư BE chuyên hỗ trợ FE).
- Org: Team chỉ có 1 Senior, 2 Mid, 2 Junior. Junior chưa từng dùng Redux.
Options
| Option | Pros | Cons | Risk | Metric Impact |
|---|---|---|---|---|
| A: Migrate to Redux + Redux Toolkit + RTK Query | Ecosystem mạnh, dev tools tốt, nhiều tutorial cho Junior | Rewrite toàn bộ state layer, 3 tháng không đủ, bundle size +30KB | Junior stuck, delay release | Bundle ↑, Dev velocity ↓, Time to ship ↑ |
| B: Giữ Zustand + thêm Yjs/Zustand-middleware cho real-time | Không rewrite, Zustand API đơn giản, Yjs chuyên CRDT | Tự maintain sync logic, ít tutorial hơn Redux | Conflict resolution bug nếu không hiểu CRDT | Bundle ↓, Dev velocity ↑, Technical debt ↑ (maintain sync) |
| C: Dùng Vercel KV + Server-sent Events, Zustand chỉ là local cache | Backend đơn giản, real-time ổn định | Phụ thuộc Vercel, cost tăng, latency cao hơn WebSocket | Vendor lock-in, cost scaling | Cost/user ↑, Latency ↑, Maintainability ↑ |
Decision
Chọn B. Vì:
- Constraint thời gian (3 tháng) là hard constraint. Option A violate constraint.
- Team có 2 Junior — complexity của Redux sẽ làm giảm velocity không chỉ ở state management mà cả ở feature development.
- Yjs là fundamental truth của real-time sync (CRDT — conflict-free replicated data type). Dùng tool đúng cho problem thay vì tool quen thuộc.
Trade-off Accepted
- Chấp nhận technical debt: CRDT sync logic phải tự maintain.
- Chấp nhận risk: Junior cần học CRDT concepts (nhưng Yjs abstract phần lớn).
- Chấp nhận mất ecosystem Redux DevTools (dùng Zustand DevTools thay thế, ít powerful hơn).
Metric & Review
- Metric theo dõi: Time to ship (target: < 3 tháng), Bundle size (target: < 200KB), Bug rate ở real-time feature (target: < 2 bugs/sprint).
- Review sau 2 tháng: Nếu bug rate > 5 bugs/sprint → cân nhắc migrate sang option A sau khi có thêm Senior hire.
Staff Review Note
Nếu review PR này, tôi hỏi: "Em đã đo thời gian Junior cần để hiểu Yjs conflict resolution chưa? Nếu Junior rời công ty sau 3 tháng, ai maintain?"
Go Deeper (Đào sâu) — L6
Principal Track: Những gì Principal sẽ hỏi Staff:
- Epistemology of Software Engineering: Làm sao biết một "sự thật" trong FE là fundamental truth hay chỉ là implementation detail của một engine/browser cụ thể? (Ví dụ: Event Loop spec vs V8 implementation).
- Inversion of Reasoning: Khi nào dùng abductive reasoning (từ symptom đoán cause) thay vì deductive reasoning (từ principle suy ra behavior) trong debugging?
- Mental Model Transfer: Làm sao để dạy First Principles cho Junior mà không làm họ choáng ngợp? (Kỹ thuật: "Scaffolded Unlearning" — cho Junior thấy prediction của họ sai ở một case cụ thể, rồi mới đưa principle).
Tài liệu tham khảo:
- "The Art of Reasoning" — David Kelley (logic cơ bản)
- "Thinking, Fast and Slow" — Daniel Kahneman (System 1 vs System 2)
- ECMAScript Spec — đọc phần Abstract Operations để thấy first principles của JS engine.
Mental Model (Mô hình tư duy)
"The Reasoning Stack"
┌─────────────────────────────────────┐
│ Layer 4: Solution / Best Practice │ ← Junior sống ở đây
│ (useMemo, Redux, Vite, Tailwind) │
├─────────────────────────────────────┤
│ Layer 3: Pattern / Heuristic │ ← Mid-level
│ (Virtual DOM diff, ES Modules graph│
│ CSS cascade) │
├─────────────────────────────────────┤
│ Layer 2: Engine / Protocol │ ← Senior
│ (V8 hidden class, HTTP/2 stream, │
│ render pipeline) │
├─────────────────────────────────────┤
│ Layer 1: Fundamental Truth │ ← Staff/Principal
│ (Memory layout, Network latency, │
│ Computational complexity, │
│ Human cognitive limit) │
└─────────────────────────────────────┘
First Principles = Đào từ Layer 4 xuống Layer 1,
rồi xây lên với constraint thực tế.Junior nhìn thấy: Một công cụ mới → học cách dùng → apply vào project.
Staff nhìn thấy: Một công cụ mới → hỏi "nó giải quyết vấn đề gì ở Layer nào?" → so sánh với công cụ hiện tại ở cùng layer → quyết định có đáng đổi không.
Visualization (Trực quan hóa)
Socratic Questioning Flow:
"Vì sao lại vậy?"
│
▼
┌───────────────┐
│ Assumption │──► "Bạn tưởng X là..." ──► ĐÚNG/SAI?
│ Check │
└───────────────┘
│
┌───────┴─────────────┐
▼ ▼
SAI ĐÚNG
│ │
▼ ▼
┌─────────────┐ ┌───────────────┐
│ Deconstruct│ │ Continue │
│ to deeper │ │ questioning │
│ layer │ │ (next "why") │
└─────────────┘ └───────────────┘
│
▼
┌─────────────────┐
│ Fundamental │
│ Truth reached? │
└─────────────────┘
│
├── KHÔNG ──► Lặp lại "Vì sao?"
│
└── CÓ ─────► Rebuild with constraintsGuided Example (Ví dụ có hướng dẫn)
Scenario: Bạn đọc được bài blog: "Tại sao bạn nên dùng useLayoutEffect thay vì useEffect cho animation?"
Mentor think aloud:
- Assumption audit: "Bạn tưởng
useLayoutEffectluôn tốt hơnuseEffectcho animation." - First question: Tại sao
useLayoutEffectkhácuseEffect?useEffectchạy sau paint.useLayoutEffectchạy sau DOM mutation nhưng TRƯỚC paint.
- Second question: Tại sao "trước paint" lại quan trọng cho animation?
- Vì nếu bạn đo DOM element rồi set state để animate,
useEffectsẽ gây visual flash (user thấy frame trước animation).
- Vì nếu bạn đo DOM element rồi set state để animate,
- Third question: Tại sao không dùng
useLayoutEffectcho mọi thứ?- Vì nó block paint. Nếu calculation nặng, bạn gây INP (Interaction to Next Paint) regression.
- Fundamental truth:
useLayoutEffecttrade paint blocking lấy visual consistency. Nó chỉ đúng khi visual flash cost > paint blocking cost. - Staff decision: "Tôi sẽ dùng
useLayoutEffectcho FLIP animation, nhưng đo INP trước và sau. Nếu INP > 200ms, tôi chấp nhận visual flash và dùnguseEffect+opacity: 0ban đầu."
Guided Questions (Câu hỏi dẫn dắt)
Question 1:
Bạn thấy một PR dùng
forEachthay vìfor...ofđể loop qua 100k items. Junior bảo: "forEach ngắn gọn hơn, code sạch hơn." Bạn hỏi gì?
Gợi ý dần
- Lần 1:
forEachcó thểbreakkhông? Nếu cần early exit ở item thứ 10, behavior khác biệt là gì? - Lần 2:
forEachtạo function scope cho mỗi iteration. Với 100k items, memory allocation cost là gì? - Lần 3:
for...ofdùng iterator protocol.forEachdùng array method. Tại sao iterator protocol cho phép lazy evaluation?
Question 2:
Bạn đọc: "Không nên dùng
indexlàmkeytrong React list." Tại sao? Đào xuống fundamental truth.
Gợi ý dần
- Lần 1: React dùng
keyđể identify element across renders. Nếukeylàindex, khi list reorder, React nghĩ element đổi content thay vì đổi vị trí. - Lần 2: Tại sao React cần identify element? Để quyết định reconcile (update) hay unmount/remount (destroy/create).
- Lần 3: Unmount/remount cost gì? DOM node destruction + creation, state loss, effect cleanup/re-run. Đây là fundamental truth của browser rendering + React lifecycle.
- Lần 4: Vậy khi nào
indexlàmkeyđược chấp nhận? Khi list static (không reorder, không filter) và items không có unique ID. Staff chấp nhận trade-off này khi cost của việc generate fake ID > cost của remount.
Guided Practice (Luyện tập có hướng dẫn)
Bài tập: First Principles Audit
Chọn một best practice bạn đang tin tưởng. Hoàn thành checklist:
- [ ] Viết câu: "Bạn tưởng [best practice] là [mô tả nhận thức của bạn]."
- [ ] Hỏi "Tại sao?" lần 1. Viết câu trả lời.
- [ ] Hỏi "Tại sao?" lần 2. Viết câu trả lời.
- [ ] Hỏi "Tại sao?" lần 3. Viết câu trả lời.
- [ ] Xác định: Câu trả lời lần 3 có còn có thể phủ nhận không? Nếu có, hỏi tiếp.
- [ ] Khi chạm đến điều không thể phủ nhận (engine behavior, protocol spec, physical limit) — đó là first principle.
- [ ] Từ first principle, viết lại: "Với constraint [X], best practice này đúng. Với constraint [Y], nó sai vì [Z]."
Ví dụ mẫu (Mentor):
- Best practice: "Luôn dùng
===thay vì==." - Bạn tưởng: "
==bị coi là bad practice,===là good practice." - Tại sao 1: "
==có type coercion,===không." - Tại sao 2: "Type coercion dựa trên Abstract Equality Comparison algorithm trong spec."
- Tại sao 3: "Algorithm này có 20+ rules, không thể nhớ hết, dẫn đến behavior không predictable."
- First principle: Human cognitive limit — developer không thể giữ 20+ rules trong đầu khi đọc code.
===giảm cognitive load xuống 1 rule (same type + same value). - Constraint rebuild: "Nếu team làm compiler/transpiler và PHẢI implement Abstract Equality Comparison, họ buộc phải hiểu
==. Trong context đó,==không phải 'bad practice'."
Independent Practice (Tự luyện tập)
Bài tập độc lập: The "Why" Challenge
Chọn 3 trong số các statement sau. Thực hiện First Principles audit độc lập (không dùng Google, chỉ dùng reasoning):
- "React
keyphải là unique trong toàn bộ app." - "CSS
z-indexcàng cao càng nổi lên trên." - "
localStorageđủ tốt để lưu trạng thái app." - "
async/awaitluôn dễ đọc hơn Promise chain." - "HTTP/3 nhanh hơn HTTP/2 nên nên migrate ngay."
Self-check rubric:
- [ ] Mỗi audit có ít nhất 3 lần hỏi "Tại sao".
- [ ] Điểm dừng là một fact không thể phủ nhận (spec, engine, protocol, physics).
- [ ] Có ít nhất 1 trường hợp statement đó sai.
- [ ] Có xác định constraint mà statement đó đúng.
Edge Cases (Các trường hợp đặc biệt)
Edge Case 1: The "Analysis Paralysis" Trap
Hỏi "tại sao" quá nhiều dẫn đến không bao giờ quyết định. First principles không phải là "phải hiểu tất cả mới được code". Nó là "hiểu đủ để biết mình đang trade-off cái gì". Staff vẫn ship code với incomplete knowledge, nhưng họ biết rõ những gì họ chưa biết.
Edge Case 2: The "Recursion Depth" Limit
Hỏi "tại sao" 10 lần về
constsẽ dẫn bạn đến V8 engine C++ code, rồi đến assembly, rồi đến transistor. Đâu là điểm dừng? Điểm dừng là layer mà bạn có thể predict behavior của layer trên nó. Nếu bạn hiểu memory layout, bạn không cần biết assembly.
Edge Case 3: The "Authority Bias" in Reverse
"Tôi không tin best practice nào cả, tôi chỉ tin code của mình." Đây là anti-pattern ngược: từ cargo cult chuyển sang "not invented here syndrome". First principles không loại bỏ kiến thức tập thể — nó verify kiến thức tập thể trước khi dùng.
Architectural Edge Case:
Team quyết định "không dùng framework nào vì chúng tôi muốn hiểu từng dòng code". Kết quả: 2 năm sau, team có framework nội bộ kém hơn React 10 năm, với 1000+ bugs đã được React community fix. First principles không nghĩa là "tự làm mọi thứ". Nó nghĩa là "hiểu tại sao React tồn tại trước khi dùng hoặc không dùng".
Reflection (Tổng kết suy ngẫm)
Teach Back Prompt:
Giả sử bạn phải dạy First Principles cho một Junior vừa tốt nghiệp bootcamp 3 tháng. Họ tin rằng "React là thư viện tốt nhất vì mọi người dùng". Viết 3 câu hỏi Socratic bạn sẽ hỏi họ, và dự đoán câu trả lời của họ ở mỗi lần.
Self-Check checklist:
- [ ] Tôi có thể phân biệt "best practice" và "fundamental truth".
- [ ] Tôi có thể đào ít nhất 3 lần "tại sao" cho một quyết định kỹ thuật.
- [ ] Tôi biết khi nào dừng lại (không rơi vào analysis paralysis).
- [ ] Tôi có thể viết một câu có dạng: "X đúng khi [constraint], sai khi [constraint khác]."
Exit Exam (Kiểm tra cuối bài)
Câu 1 (L1-L2):
Định nghĩa First Principles Thinking. Tại sao nó khác với việc "tự nghĩ ra mọi thứ từ đầu"?
Câu 2 (L3):
Lấy một best practice bạn thường xuyên dùng (ví dụ: "dùng
constthayvar"). Thực hiện Socratic questioning chain ít nhất 3 lần "tại sao". Điểm dừng của bạn là gì? Tại sao đó là fundamental truth?
Câu 3 (L4-L5):
Bạn review một PR migrate từ REST sang GraphQL. Junior viết: "GraphQL tốt hơn vì nó linh hoạt hơn REST." Áp dụng First Principles, bạn sẽ hỏi những câu gì? Constraint nào khiến GraphQL sai lựa chọn?
Câu 4 (L4 System Design):
Bạn có 1 dashboard hiển thị 10k data points cập nhật real-time. Junior đề xuất: "Dùng WebSocket vì nó real-time." Áp dụng First Principles, phân rã yêu cầu xuống fundamental truths (network, browser, human perception). Thiết kế một scheduling strategy cho data update. Trade-off nào bạn chấp nhận?
Interview Q&A (Hỏi đáp phỏng vấn)
L1 — Concept (30 giây)
Q: What is First Principles Thinking in software engineering?
"First Principles Thinking is the practice of deconstructing a technical problem down to its fundamental truths — engine behavior, protocol specs, or physical constraints — and then rebuilding a solution from those truths rather than relying on analogy, tradition, or authority. It's not about reinventing everything from scratch; it's about understanding why a best practice exists before applying it."
Bản dịch
"First Principles Thinking là phương pháp phân rã vấn đề kỹ thuật xuống các sự thật cơ bản — behavior của engine, spec của protocol, hoặc ràng buộc vật lý — rồi xây dựng lại solution từ những sự thật đó thay vì dựa vào analogy, truyền thống, hoặc thẩm quyền. Nó không phải tự phát minh lại mọi thứ; mà là hiểu tại sao một best practice tồn tại trước khi áp dụng."
L2 — Application (1 phút)
Q: A junior developer says: 'We should use Redux because it's a best practice for React state management.' How do you respond using First Principles?
"I'd start by challenging the assumption. 'Best practice' is a result, not a cause. I'd ask: What specific problem does Redux solve? It provides predictable state updates via pure reducers and a single source of truth. Now, does our project have that problem? If we're a 3-person team with mostly server state and no complex client-side interactions, Redux adds 30KB bundle and significant boilerplate. The fundamental truth here is that state management tools trade simplicity for predictability. In our constraint — small team, server-heavy — that trade-off doesn't make sense. I'd suggest TanStack Query for server state and Zustand for client state instead."
Bản dịch
"Tôi sẽ challenge assumption. 'Best practice' là kết quả, không phải nguyên nhân. Tôi hỏi: Redux giải quyết vấn đề gì? Nó cung cấp predictable state updates qua pure reducers và single source of truth. Giờ project của ta có vấn đề đó không? Nếu team 3 người, chủ yếu server state, không có complex client-side interactions, Redux thêm 30KB bundle và boilerplate đáng kể. Fundamental truth ở đây là state management tool trade simplicity lấy predictability. Với constraint của ta — team nhỏ, server-heavy — trade-off đó không hợp lý. Tôi đề xuất TanStack Query cho server state và Zustand cho client state."
L3 — Deep Dive (2-3 phút)
Q: Explain the difference between reasoning by analogy and reasoning by first principles. Give a concrete frontend example where analogy leads to the wrong decision.
"Reasoning by analogy says: 'Company X used micro-frontends successfully, so we should too.' Reasoning by first principles says: 'Micro-frontends solve the problem of independent deployment for large teams with different release cycles. Our team has 5 engineers, ships weekly, and shares a monorepo. The fundamental constraint is coordination cost, not deployment independence. Therefore, module federation adds complexity without solving our actual problem.'
A concrete frontend example: A junior sees that Netflix uses client-side rendering for performance. The analogy is 'CSR is faster.' But first principles reveal that Netflix has a complex edge caching strategy and a hydration architecture that most teams don't have. For a content site with low interactivity, SSR or static generation is faster because the fundamental truth is that HTML parsing and rendering is faster than executing JavaScript to generate DOM. The analogy leads to a 3-second TTI instead of a 500ms FCP."
Bản dịch
"Reasoning by analogy nói: 'Công ty X dùng micro-frontend thành công, nên ta cũng nên dùng.' Reasoning by first principles nói: 'Micro-frontend giải quyết vấn đề independent deployment cho team lớn với release cycle khác nhau. Team ta có 5 engineers, ship hàng tuần, share monorepo. Constraint thực sự là coordination cost, không phải deployment independence. Vậy module federation thêm complexity mà không giải quyết vấn đề thực của ta.'
Ví dụ cụ thể: Junior thấy Netflix dùng client-side rendering cho performance. Analogy là 'CSR nhanh hơn.' Nhưng first principles cho thấy Netflix có edge caching strategy phức tạp và hydration architecture mà hầu hết team không có. Với content site ít interactivity, SSR hoặc static generation nhanh hơn vì fundamental truth là HTML parsing và rendering nhanh hơn thực thi JavaScript để generate DOM. Analogy dẫn đến 3 giây TTI thay vì 500ms FCP."
L4 — System Design (5 phút)
Q: Design a caching strategy for a SaaS dashboard that serves 100k users with varying data freshness requirements. The junior suggests: 'Let's cache everything in Redis for 1 hour.' Apply First Principles to evaluate this proposal.
"The junior's proposal is reasoning by analogy — 'caching makes things faster.' Let's apply first principles.
Step 1 — Deconstruct to fundamental truths:
- Cache invalidation is one of the two hard problems in computer science. The fundamental truth is that stale data has a business cost, and the cost varies by data type.
- Network latency is bounded by physics. The fundamental truth is that edge caching is always faster than origin caching.
- Memory is finite. The fundamental truth is that caching everything has a storage cost and an eviction cost.
Step 2 — Rebuild with constraints:
- User profile data: Changes rarely, high read frequency. Cache at CDN edge with long TTL. Invalidation on user update.
- Real-time analytics: Changes every second, stale data is worse than slow data. Don't cache; use request coalescing instead.
- Dashboard configuration: Medium read, medium change. Cache in browser with IndexedDB, sync on reconnect.
Step 3 — Decision with trade-offs:
- We accept CDN cost for user profiles because the hit rate will be 99%+.
- We accept higher origin load for real-time data because business decisions depend on freshness.
- We accept client-side storage complexity because it reduces server load and improves perceived performance.
Metrics: Cache hit rate by tier, stale data incident rate, origin server CPU, P95 dashboard load time.
Review: After 2 weeks, if real-time data origin load is too high, we'll add a 5-second short-term cache with active invalidation via SSE — but only after measuring, not before."
Bản dịch
"Đề xuất của Junior là reasoning by analogy — 'cache làm mọi thứ nhanh hơn.' Ta áp dụng first principles.
Bước 1 — Phân rã xuống sự thật cơ bản:
- Cache invalidation là một trong hai vấn đề khó của computer science. Sự thật cơ bản là stale data có business cost, và cost thay đổi theo loại data.
- Network latency bị giới hạn bởi vật lý. Sự thật cơ bản là edge caching luôn nhanh hơn origin caching.
- Memory là hữu hạn. Sự thật cơ bản là cache mọi thứ có storage cost và eviction cost.
Bước 2 — Xây lại với constraint:
- User profile data: Ít thay đổi, đọc nhiều. Cache ở CDN edge với TTL dài. Invalidation khi user update.
- Real-time analytics: Thay đổi mỗi giây, stale data tệ hơn slow data. Không cache; dùng request coalescing.
- Dashboard configuration: Đọc trung bình, thay đổi trung bình. Cache ở browser với IndexedDB, sync khi reconnect.
Bước 3 — Quyết định với trade-off:
- Chấp nhận CDN cost cho user profile vì hit rate sẽ 99%+.
- Chấp nhận origin load cao hơn cho real-time data vì business decision phụ thuộc freshness.
- Chấp nhận client-side storage complexity vì nó giảm server load và cải thiện perceived performance.
Metrics: Cache hit rate theo tier, stale data incident rate, origin server CPU, P95 dashboard load time.
Review: Sau 2 tuần, nếu origin load real-time data quá cao, ta sẽ thêm short-term cache 5 giây với active invalidation qua SSE — nhưng chỉ sau khi đo, không phải trước."
Module Summary
Concepts Taught
- [FirstPrinciples:FULL:L1-L5] — Phân rã xuống fundamental truths, rebuild với constraint
- [SocraticMethod:FULL:L1-L5] — Hỏi "tại sao" 3-5 lần liên tiếp để đào xuống root cause
- [UnlearnRebuild:FULL:L1-L5] — Tháo dỡ assumption cũ trước khi xây dựng reasoning mới
- [AssumptionAudit:FULL:L1-L5] — Nhận diện và challenge "Bạn tưởng" trong nhận thức
- [StaffLens:Applied] — Junior nhìn thấy symptom→solution; Staff nhìn thấy symptom→question tree→root cause→constraint-based decision
- [DecisionRecord:Sample] — DR: Chọn state management cho team 5 người với real-time constraint
Anti-Patterns Covered
- Cargo Cult Programming (Section A, L5) — Áp dụng best practice/pattern vì "công ty lớn dùng" mà không hiểu constraint
- Analysis Paralysis (Edge Case 1) — Hỏi "tại sao" quá nhiều dẫn đến không quyết định
- Not Invented Here Syndrome (Edge Case 3) — Anti-pattern ngược: bác bỏ mọi kiến thức tập thể
Forward References
- [V8Engine:TOUCHED:L1-seed] — Nhắc qua ở L6 (engine behavior là first principle) — sẽ học chi tiết ở Module 0.1.1
- [RenderPipeline:TOUCHED:L1-seed] — Nhắc qua ở L2 visualization — sẽ học chi tiết ở Module 0.2.1
- [CostEngineering:TOUCHED:L5-context] — Nhắc qua ở War Story (bundle size, cost/user) — sẽ học chi tiết ở Module 0.8.1
Staff Checkpoint
- [ ] Giải thích First Principles cho Junior bằng một analogy đúng (không dumbing down)
- [ ] Viết 1 Decision Record cho 1 trade-off đơn giản (chọn tool/framework)
- [ ] Thực hiện Socratic questioning chain 3 lần "tại sao" cho một best practice bạn đang dùng
- [ ] Phân biệt được khi nào một statement là "fundamental truth" và khi nào là "implementation detail"
Tiếp theo: Module 0.1.1 — V8 Engine & Memory Basics. Bạn sẽ áp dụng First Principles để phân rã câu hỏi: "JavaScript là interpreted language — đúng hay sai? Tại sao?"