Mục tiêu học tập
Sau bài này, bạn sẽ có thể:
- ✅ Nắm vững 4 phases của workflow EPCC (Explore, Plan, Code, Commit) và mục đích riêng của từng phase
- ✅ Biết khi nào nên skip phase nào và khi nào cần lặp lại nhiều vòng
- ✅ Dùng Plan Mode đúng cách để align với Claude trước khi code, tránh course-correct tốn kém
- ✅ Setup test suite và tools phù hợp để Code phase chạy mượt, ít back-and-forth
- ✅ Tạo subagent code reviewer cho Commit phase để có “fresh pair of eyes” trước khi push
Mở đầu: Hai dev, cùng task, kết quả ngược nhau
Hãy tưởng tượng hai backend engineer — Minh và An — nhận cùng một ticket vào sáng thứ Hai:
“Add WebP conversion to the image upload pipeline.”
Minh (làm việc theo cách cũ): Mở Claude Code, prompt thẳng:
“Add WebP conversion to our image upload pipeline.”
Claude bắt đầu viết code. Nó tìm một file tên upload.ts, thêm thư viện sharp, viết converter. Trông có vẻ ổn. Minh approve, Claude tiếp tục. 20 phút sau, build error vì project thực ra dùng jimp không phải sharp. Fix xong, lại có lỗi khác — hoá ra pipeline upload không phải ở upload.ts mà ở một middleware chain phức tạp hơn nhiều. Claude đã đoán sai entry point. Sửa tiếp. Test fail. Debug. 2 tiếng sau, Minh vẫn đang loay hoay với một đống code chắp vá.
An (dùng EPCC workflow): Shift+Tab vào Plan Mode, prompt:
“I need to add WebP conversion to our image upload pipeline. Figure out where in the pipeline it should happen, whether we need new dependencies, and how to approach it.”
Claude đọc file, khám phá codebase, tìm ra: pipeline upload nằm ở middleware/storage.ts và project đã có jimp rồi — không cần thêm dependency. 5 phút sau, Claude trả ra plan chi tiết. An đọc, thấy hợp lý, comment thêm một yêu cầu về xử lý animated GIF, Claude revise plan. An approve. Claude execute từng bước theo plan, chạy test suite, commit gọn. Tổng thời gian: 25 phút.
Sự khác biệt không phải do An giỏi hơn Minh. Sự khác biệt nằm ở workflow.
“If you take one thing away from this course, let it be this workflow.”— Boris Cherny, creator of Claude Code
EPCC không phải overhead. Nó là cái làm cho bạn nhanh hơn, không phải chậm hơn.
EPCC: Bức tranh toàn cảnh
Tỷ lệ thời gian trên là ước tính minh hoạ cho một task medium complexity (vài giờ). Với task nhỏ hơn, Explore + Plan có thể chỉ chiếm 10-15%. Với task phức tạp (refactor kiến trúc), Plan có thể chiếm 50%+. Không phải con số cứng.
Điều quan trọng nhất: Explore + Plan = 50% thời gian. Đây không phải overhead — đây là investment để Code phase chạy thẳng, không zigzag.
Mỗi phase có một vai trò riêng:
| Phase | Vai trò |
|---|
| Explore | Claude cần hiểu codebase của bạn trước khi chạm vào code. Không có phase này, Claude đoán. |
| Plan | Điểm align giữa bạn và Claude trước khi code được viết. Đây là nơi rẻ nhất để course-correct. |
| Code | Claude execute theo plan. Bạn verify, test, điều chỉnh nếu cần. |
| Commit | Review kỹ trước khi push. Subagent reviewer cho “fresh pair of eyes”. |
Phase 1: EXPLORE — Đừng để Claude đoán
Tại sao phase này tồn tại
Claude Code không có sẵn kiến thức về codebase của bạn. Nó không biết:
- Image upload pipeline của bạn nằm ở đâu
- Project đã có những thư viện nào
- Convention đặt tên function/file của team bạn
- Business logic đặc thù nào đang được xử lý trong pipeline đó
Nếu bạn skip Explore và đi thẳng vào “viết code đi” — Claude sẽ đoán. Và đoán thì luôn tốn thời gian hơn hiểu đúng từ đầu.
Hai cách Explore
Cách 1: Plan Mode (read-only)
Nhấn Shift + Tab cho tới khi thấy “Plan Mode” xuất hiện dưới text input. Trong Plan Mode, Claude không thể edit files — nó chỉ đọc, search, và nghiên cứu codebase của bạn. Đây là trạng thái lý tưởng cho Explore vì:
- Claude không thể “slip” và bắt đầu viết code giữa chừng
- Mọi “tool call” đều là read-only (grep, glob, file read, web search)
- Bạn có thể để Claude chạy thoải mái mà không lo nó sửa nhầm gì
Cách 2: Prompt explicit (không cần Plan Mode)
Nếu bạn chỉ muốn hiểu codebase mà không có ý định thay đổi ngay:
Khám phá codebase và cho tôi biết:
- Image upload hiện tại flow như thế nào?
- File nào handle upload logic?
- Thư viện image processing nào đang được dùng?
Đừng thay đổi gì. Chỉ đọc và giải thích.
Explore nên tìm ra điều gì
Sau phase Explore, bạn và Claude nên biết được:
| Câu hỏi | Tại sao cần biết |
|---|
| Feature/pipeline liên quan nằm ở đâu? | Tránh sửa sai file, sai module |
| Pattern hiện tại là gì? | Code mới phải consistent với existing code |
| Dependency nào đã có? | Tránh thêm thư viện trùng lặp |
| Test suite ở đâu? Chạy bằng lệnh gì? | Để Code phase có thể verify sau khi sửa |
| Có constraint nào không rõ ràng? | Business logic ẩn, performance requirements, security rules |
Anti-pattern: Skip Explore
Triệu chứng phổ biến nhất khi skip Explore:
- Claude viết code sử dụng thư viện không có trong project (phải thêm dependency không cần thiết)
- Claude sửa file không phải entry point thực sự
- Code mới không match convention của codebase (naming, structure, error handling)
- Build lỗi ngay lần đầu vì môi trường không phù hợp
Thời gian tiết kiệm khi skip Explore: 5-10 phút. Thời gian mất thêm khi phải fix: 30-90 phút.
Phase 2: PLAN — Nơi rẻ nhất để course-correct
Tại sao Plan quan trọng hơn Code
Hãy nghĩ về chi phí thay đổi ở từng giai đoạn:
Thay đổi trong Plan phase: $ (chỉnh vài chữ trong plan)
Thay đổi trong Code phase: $$ (rollback code, viết lại)
Thay đổi sau khi commit: $$$ (revert PR, re-review, re-test)
Plan Mode không phải là tính năng luxury. Nó là cơ chế tiết kiệm tiền và thời gian hiệu quả nhất khi làm việc với AI.
Cách vào Plan Mode
Shift + Tab → Shift + Tab → [thấy "Plan Mode" dưới text input]
Hoặc gõ Shift + Tab 1-2 lần cho tới khi status bar hiển thị “Plan Mode”. Lúc này Claude không thể edit files — chỉ đọc.
Cách viết prompt tốt cho Plan phase
Prompt Plan phase phải trả lời 3 câu hỏi:
- Task là gì? (mô tả rõ ràng, không mơ hồ)
- Constraints là gì? (thứ Claude KHÔNG được làm hoặc phải tuân theo)
- Success trông như thế nào? (test suite pass? API endpoint trả đúng response? UI render đúng?)
Ví dụ prompt Plan phase chất lượng cao:
I need to add WebP conversion to our image upload pipeline.
Context:
- Pipeline hiện tại xử lý upload ở middleware layer
- User upload JPEG/PNG, chúng ta cần convert sang WebP trước khi lưu vào S3
- Animated GIF phải được giữ nguyên (không convert)
Constraints:
- Không thêm dependency mới nếu project đã có library xử lý được
- Giữ API endpoint không đổi (backward compatible)
- Conversion phải happen async, không block response
Success criteria:
- Tất cả test trong `tests/upload/` pass
- Manual test: upload JPEG → S3 có file .webp
- Manual test: upload animated GIF → S3 giữ nguyên .gif
Figure out where in the pipeline it should happen, whether we need
new dependencies, and draft a step-by-step implementation plan.
Claude trả plan — bạn làm gì?
Sau khi Claude trả plan, đừng approve ngay. Đây là lúc bạn đọc kỹ và hỏi:
- Plan này có miss bất kỳ edge case nào không?
- Có bước nào mà bạn không đồng ý về approach?
- Thứ tự các bước có hợp lý không?
- Plan có conflict với architectural decision nào của team không?
Nếu có vấn đề, comment và yêu cầu Claude revise. Đây là lúc rẻ nhất để thay đổi.
Bảng: Plan tốt vs Plan kém
| Tiêu chí | Plan tốt | Plan kém |
|---|
| Cụ thể | Liệt kê từng file cần sửa, từng function cần thêm | ”Modify upload pipeline to support WebP” |
| Có thứ tự rõ ràng | Bước 1, 2, 3 logic, dependency rõ ràng | Danh sách không có thứ tự |
| Có success criteria | ”Test X pass, endpoint Y return Z" | "Feature works” |
| Xử lý edge cases | GIF animated, file size limit, error handling | Chỉ handle happy path |
| Không thêm scope | Chỉ làm đúng yêu cầu | ”Và nhân tiện refactor cả module upload” |
| Feasible | Approach khả thi với codebase hiện tại | Assume library hoặc pattern không tồn tại |
Lặp lại Plan nếu cần
Với task phức tạp, bạn có thể cần nhiều vòng Plan trước khi approve:
Round 1: Claude draft plan tổng quan
→ Bạn: "Step 3 cần xử lý race condition — revise"
Round 2: Claude revise, cụ thể hơn về async handling
→ Bạn: "Tốt. Nhưng step 5 dùng jimp chứ không phải sharp"
Round 3: Claude update dependency reference
→ Bạn: "OK, approve."
Mỗi vòng revise mất 1-2 phút. Tốt hơn nhiều so với debug sau khi code sai.
Phase 3: CODE — Execute có kiểm soát
Sau khi approve plan
Khi bạn approve plan, Claude sẽ bắt đầu execute từng bước. Thoát khỏi Plan Mode (nhấn Shift + Tab để quay lại chế độ bình thường), và bạn cần quyết định: Auto Accept hay Manual Accept?
| Mode | Khi dùng | Trade-off |
|---|
| Auto Accept (Shift+Tab → Auto Accept mode) | Claude edit files không cần hỏi từng cái. Nhanh hơn cho task có plan rõ ràng. Tốt khi bạn trust plan đã review. | Cần verify kỹ ở cuối. |
| Manual Accept (mặc định) | Bạn review từng file edit trước khi Claude apply. Tốt cho task nhạy cảm (security, billing, auth). Learning mode — xem Claude làm từng bước. | Chậm hơn nếu plan dài. |
Với task medium (như WebP conversion), Auto Accept sau khi đã review plan là hợp lý. Với task liên quan auth, payment, hay security — Manual Accept an toàn hơn.
3 yếu tố làm Code phase mượt
Yếu tố 1: Success criteria explicit
Claude cần biết “đúng” trông như thế nào. Nếu success criteria mơ hồ, Claude sẽ không biết khi nào nên dừng và sẽ over-engineer hoặc dừng quá sớm.
Trong plan hoặc prompt đầu Code phase, nói rõ:
Success = tất cả test trong tests/upload/ pass + không có
TypeScript type error + build không fail.
Claude Code làm việc tốt hơn khi có tools để verify kết quả của nó. Ví dụ:
- Web UI? Cài Claude in Chrome extension để Claude Code control browser tab, test UI trực tiếp mà không cần bạn describe lại
- Test suite? Đảm bảo lệnh chạy test rõ ràng (
npm test, pnpm test --run, pytest -v). Claude sẽ tự chạy sau khi implement
- Linting? Nếu bạn muốn Claude tự sửa lint errors, cho Claude biết lệnh lint (
npm run lint --fix)
Yếu tố 3: Test suite là source of truth
Đây là yếu tố quan trọng nhất. Nếu bạn có test suite mà Claude có thể chạy liên tục, Code phase sẽ thành một vòng lặp tự sửa:
Claude implement → chạy test → test fail → Claude đọc error → sửa → chạy lại
↑
Vòng lặp này chạy tự động
Bạn không cần ngồi canh. Claude tự biết khi nào xong (khi test pass). Nếu không có test suite, Claude phải hỏi bạn “đúng chưa?” sau mỗi bước — tốn thời gian của cả hai.
Claude có thể viết test cho bạn. Trước khi implement feature, prompt: “Viết test cho feature này trước. Tôi sẽ review test. Sau đó mới implement.” Test-driven development với AI cực kỳ hiệu quả.
Xử lý khi Claude bị kẹt lặp lại
Đôi khi Claude mắc đi mắc lại cùng một lỗi. Đây là dấu hiệu nó đang thiếu một context quan trọng. Cách xử lý:
Bạn: "Claude keep running into the same issue với X. Hãy lưu
solution vào CLAUDE.md để các lần sau không bị lại."
Claude sẽ viết rule vào CLAUDE.md — từ session sau, nó không cần học lại lỗi đó nữa. Xem chi tiết ở Bài 2.7: File CLAUDE.md.
Multi-Claude: Chạy song song cho task lớn
Khi bạn có nhiều task không liên quan, không cần đợi task này xong mới làm task kia. Một pattern phổ biến trong cộng đồng:
“People run 4-6 Claude instances simultaneously — separate git worktrees, different tasks, no interference.”
Cách setup:
# Terminal tab 1 — feature A
git worktree add ../project-feature-a feature/webp-conversion
cd ../project-feature-a && claude
# Terminal tab 2 — feature B (song song, cùng lúc)
git worktree add ../project-feature-b feature/csv-export
cd ../project-feature-b && claude
Mỗi instance có context window riêng, làm việc trên branch riêng qua git worktree. Không conflict. Bạn chỉ cần switch tab khi Claude hỏi hoặc cần review. Xem thêm ở Bài 2.5: Quản lý Context (section multi-session).
Async Accept mode
Một tính năng ít được biết đến: Async Accept mode. Nhấn Shift + Enter khi Claude đang chạy để chuyển sang chế độ này. Trong Async Accept:
- Claude tiếp tục chạy trong background
- Bạn có thể switch sang task khác hoàn toàn
- Terminal notification khi Claude xong
Hữu ích khi task dài (build + test + fix cycle) mà bạn không muốn ngồi chờ.
Phase 4: COMMIT — Gate trước khi push
Tại sao cần phase riêng cho Commit
Nhiều người coi commit là một thao tác kỹ thuật đơn giản: git add -A && git commit -m "..." && git push. Nhưng với workflow AI-assisted, Commit phase có vai trò quan trọng hơn: đây là lúc bạn hoặc subagent reviewer đọc lại toàn bộ changes với “fresh eyes”.
Claude đã ở trong session đó từ đầu. Nó có bias — nó đã viết code đó, nó “biết” code đó “đúng”. Một subagent reviewer bắt đầu fresh, không có bias đó.
Subagent code reviewer
Trước khi commit, spawn một subagent để review:
Spawn subagent để review tất cả changes tôi vừa làm.
Subagent đọc:
- git diff --staged (hoặc các file tôi vừa sửa)
- Related tests
- CLAUDE.md để check coding standards
Trả về:
1. Summary of changes (2-3 câu)
2. Potential issues hoặc bugs
3. Missing edge cases
4. Code style violations (nếu có)
5. Recommendation: approve to commit hay cần sửa gì
Subagent chạy với context window riêng, đọc fresh, không bị ảnh hưởng bởi session hiện tại. Đây là “second opinion” rẻ nhất và nhanh nhất bạn có thể có. Xem chi tiết ở Bài 2.6: Code Review và Git Workflow.
Claude generate commit message
Sau khi review xong (hoặc fix issues từ review), để Claude generate commit message:
Dựa trên changes và plan vừa thực hiện, generate commit message
theo format của project (xem commit history gần đây để match style).
Claude sẽ xem git log, học style commit message của team, và generate message phù hợp. Không cần bạn tự viết.
GitHub Actions integration
Nếu bạn đã setup GitHub Actions với Claude (xem Bài 2.6), bạn có thêm một layer automation sau khi push:
# Trong PR comment, tag @claude để fix issues:
@claude fix the failing test in test/upload/webp.test.ts
@claude add missing error handling for corrupt image files
@claude write a summary of changes for this PR
Claude tạo commit mới trực tiếp trong PR, không cần bạn pull về local, sửa, push lại. Vòng lặp review → fix trở nên nhanh hơn nhiều.
Khi nào skip phase nào?
EPCC là workflow tối ưu cho task vừa và lớn. Nhưng áp dụng full 4 phases cho mọi task là overhead không cần thiết. Đây là bảng quyết định:
| Loại task | Explore | Plan | Code | Commit | Thời gian ước tính |
|---|
| Tiny — sửa typo, đổi 1 constant, rename variable | Skip | Skip | Nhanh | Minimal | 2-5 phút |
| Easy — thêm 1 field vào form, fix bug 1 file | Optional | Optional | Normal | Minimal | 5-15 phút |
| Medium — feature mới hoàn chỉnh, refactor 1 module | Required | Required | Normal + test | Full review | 20-60 phút |
| Hard — redesign architecture, cross-cutting change | Extended | Multiple rounds | Phased + nhiều test | Multiple commits | 2-8 giờ |
| Massive — legacy modernization, platform migration | Days | Days | Phased over weeks | Per-phase commit | Weeks |
Tiny task — Không cần Explore hay Plan:
# Fix typo trong constant
> Fix typo: đổi "recieve" thành "receive" trong file src/constants.ts dòng 47.
Xong. Commit. 2 phút. Không cần Plan Mode.
Hard task — Plan nhiều vòng, Code nhiều phases:
Round 1: Explore overall architecture → understand scope
Round 2: Plan high-level phases → approve phases
Round 3: Plan Phase 1 chi tiết → execute Phase 1 → commit Phase 1
Round 4: Plan Phase 2 chi tiết → execute Phase 2 → commit Phase 2
...
Với task hard, bạn commit nhiều lần (mỗi phase là 1 commit hoặc vài commit nhỏ) thay vì 1 commit khổng lồ. Dễ review hơn, dễ rollback hơn nếu có vấn đề.
Ví dụ thực chiến đầy đủ: “Add WebP conversion to image pipeline”
Đây là toàn bộ workflow EPCC từ đầu đến cuối, dùng chính task từ story mở đầu.
Setup
Project: Node.js + Express API
Image library đã có: jimp (discovered trong Explore)
Test: Jest, lệnh: npm test
Storage: AWS S3
Phase 1: EXPLORE (5-7 phút)
[Shift+Tab → Plan Mode]
Prompt: "Explore codebase để tôi hiểu current image upload flow:
- File nào handle upload?
- Library image processing nào đang dùng?
- Test cho upload ở đâu?
- S3 integration ở đâu?
Đừng thay đổi gì."
Claude tìm và report:
- Pipeline:
middleware/storage.ts (entry point) → services/upload.service.ts (business logic)
- Library:
jimp đã có trong package.json
- Tests:
tests/upload/ — 12 test cases hiện tại
- S3:
services/s3.service.ts với method uploadBuffer()
Phase 2: PLAN (8-10 phút)
[Vẫn trong Plan Mode]
Prompt: "Dựa trên những gì vừa explore, tạo plan implement WebP conversion:
Requirements:
- Convert JPEG/PNG → WebP trước khi upload S3
- GIF animated: KHÔNG convert (giữ nguyên)
- Max file size sau convert: 2MB
- Backward compatible (API không đổi)
Constraints:
- Dùng jimp (đã có), không thêm thư viện mới
- Follow pattern hiện tại của storage middleware
- Viết tests cho conversion logic
Success criteria:
- npm test pass (bao gồm test mới)
- Upload JPEG → S3 có .webp
- Upload animated GIF → S3 giữ .gif
- TypeScript compile không error"
Claude trả plan:
Plan: Add WebP Conversion to Image Upload Pipeline
Step 1: Tạo utility function trong services/image.service.ts
- convertToWebP(buffer: Buffer, mimeType: string): Promise<Buffer>
- Skip conversion nếu mimeType === 'image/gif'
- Dùng jimp.read() → resize nếu cần → output WebP
Step 2: Update middleware/storage.ts
- Sau khi nhận file buffer, call convertToWebP() trước uploadBuffer()
- Handle error gracefully (log + fallback to original nếu convert fail)
Step 3: Update S3 filename logic trong services/upload.service.ts
- Replace extension với .webp (trừ GIF)
- Update Content-Type header tương ứng
Step 4: Viết tests
- tests/upload/webp-conversion.test.ts
- Test cases: JPEG → WebP, PNG → WebP, GIF → GIF, large file → error
Step 5: Verify
- npm test (tất cả)
- TypeScript check
Bạn đọc plan, thấy ổn. Chỉ một comment:
"Step 1: jimp không support WebP output natively. Check lại —
có thể cần jimp + webp encoder package, hoặc dùng cách khác."
Claude check lại, revise:
Đã verify: jimp cần @jimp/plugin-webp. Package này nhỏ (~50KB),
compatible với jimp version hiện tại. Cập nhật Step 1:
- Install @jimp/plugin-webp
- Configure trong image.service.ts
Bạn approve revised plan.
Phase 3: CODE (15-20 phút)
[Shift+Tab → thoát Plan Mode, về Normal mode]
[Chọn Auto Accept vì plan đã review kỹ]
Prompt: "Execute the plan. Run npm test sau mỗi step để verify."
Claude bắt đầu execute:
- Install
@jimp/plugin-webp, update package.json
- Tạo
services/image.service.ts với convertToWebP() function
- Update
middleware/storage.ts — gọi converter trước upload
- Update
services/upload.service.ts — handle WebP filename
- Viết
tests/upload/webp-conversion.test.ts — 6 test cases
Giữa chừng, npm test fail ở test case “large file error” vì Claude implement sai điều kiện. Claude tự đọc error log, sửa, chạy lại. Test pass.
Output cuối:
npm test
...
✓ upload/webp-conversion.test.ts (6 tests)
✓ upload/storage.test.ts (12 tests)
✓ upload/s3.test.ts (8 tests)
Tests: 26 passed, 0 failed
TypeScript: 0 errors
Build: success
Phase 4: COMMIT (3-5 phút)
Spawn subagent để review all changes:
- services/image.service.ts (new)
- middleware/storage.ts (modified)
- services/upload.service.ts (modified)
- tests/upload/webp-conversion.test.ts (new)
- package.json (modified)
Check: correctness, edge cases, code style, missing tests.
Subagent report:
Review Summary:
- Implementation: Logic đúng, GIF skip handled correctly
- Edge cases: Missing — what if buffer.length === 0? (empty upload)
- Code style: OK, follows existing patterns
- Tests: Good coverage, recommend adding test for empty buffer
Recommendation: Fix empty buffer edge case trước khi commit.
Bạn prompt Claude main: “Fix empty buffer edge case trong convertToWebP(), thêm test.” Claude sửa, test pass.
Generate commit message dựa trên plan và changes.
Match style của project (xem git log --oneline -5).
Claude generate:
feat(upload): add WebP conversion to image upload pipeline
- Convert JPEG/PNG to WebP before S3 upload using @jimp/plugin-webp
- Skip conversion for animated GIFs (preserve format)
- Add graceful fallback if conversion fails
- Handle empty buffer edge case
- Add 7 test cases for conversion logic
Closes #142
Push. Done. Total: ~28 phút từ lúc đọc ticket đến khi push.
Case studies theo role
Backend Engineer: Refactor service architecture
Tình huống: Senior BE Engineer ở fintech startup cần refactor payment service từ monolithic sang microservices pattern. Scope lớn (~2 ngày estimate).
EPCC approach:
- Explore: Spawn 4 subagents song song, mỗi cái map 1 module (payment, billing, notification, webhook). Main agent tổng hợp map tổng thể — 30 phút thay vì 1 ngày đọc code thủ công.
- Plan: Nhiều rounds — Plan tổng thể phases (ngày 1), Plan chi tiết phase 1 (sáng ngày 2), Plan chi tiết phase 2 (chiều). Mỗi plan document được lưu ra file
.md trong repo và commit vào branch.
- Code: Phased execution. Phase 1 extract payment → commit. Phase 2 extract billing → commit. Không làm một lần vì scope quá lớn.
- Commit: Per-phase commit với review. Tổng cộng 8 commits nhỏ thay vì 1 commit khổng lồ.
Kết quả: Refactor hoàn thành trong 1,5 ngày (thay vì 2 ngày estimate). 0 regression bugs do test coverage tốt.
Frontend Engineer: Ship UI feature mới
Tình huống: FE Engineer implement “dark mode toggle” cho dashboard. Task medium, 1 buổi sáng.
EPCC approach:
- Explore: Claude đọc
theme/, tailwind.config.ts, tìm hiểu cách color tokens được defined.
- Plan: Một round đủ — plan đơn giản, 10 phút. Bao gồm: CSS variables, localStorage persistence, system preference detection.
- Code: Auto Accept mode. Claude in Chrome extension để verify UI trực tiếp trong browser. Claude test light/dark toggle, verify cả 3 cases (manual, system pref, localStorage).
- Commit: Subagent review nhanh. Commit gọn.
Kết quả: Done trong 45 phút. Không phải debug UI manually lần nào.
Open source maintainer: Review và merge contributor PRs
Tình huống: Maintainer của popular npm package, nhận PR từ contributor. Code đã được review về logic, cần verify implementation và run tests.
EPCC approach (modified):
- Explore: Skip (đã biết codebase của mình rồi)
- Plan: Skip (contributor đã có plan trong PR description)
- Code: Checkout PR branch, run test suite, dùng Claude để verify logic và edge cases
- Commit: Subagent review nhanh → approve → merge hoặc request changes
Kết quả: Review cycle nhanh hơn 2-3x. Ít miss edge cases.
Anthropic team: 22.000-line RL code change
Đây là case study thực từ inside Anthropic, được chia sẻ trong engineering blog:
“Days of human planning. Concentrated implementation on ‘leaf nodes’ — code that nothing else depends on. Human review focused on extensible parts. Stress tests for stability, verified inputs/outputs without reading all code. Result: just as confident as any other change, delivered in a tiny fraction of time.”
Bài học:
- Explore: Extensive — toàn bộ team hiểu codebase trước khi plan
- Plan: Days — không phải giờ, không phải phút
- Code: Focused trên leaf nodes — code mà không có gì depend vào, nên technical debt nhỏ ở đây acceptable
- Commit: Chia nhỏ, nhiều phases, với stress test riêng
Quote từ team: “Tech debt in leaf nodes is okay because nothing depends on them.” Đây là mindset shift quan trọng — không cần perfect code mọi nơi, concentrate effort vào interfaces và extensible parts.
Solo founder (vibe-coding): Ship nhanh, iterate
Tình huống: Indie hacker build SaaS một mình, ưu tiên speed-to-market, codebase chỉ mình biết.
EPCC approach (simplified):
- Explore: Ngắn — bạn đã biết codebase của mình
- Plan: Dài hơn mức cần thiết vì Plan là lúc bạn think through feature, không chỉ align với Claude
- Code: Skip manual review chi tiết từng dòng. Trust test suite. Focus vào behavior, không phải code.
- Commit: Light review, commit nhanh, iterate
Mindset: Andrej Karpathy (người phổ cập khái niệm “vibe coding”) mô tả: “Fully give into the vibes, embrace exponentials, forget code exists.” Bạn quản lý product và behavior — Claude quản lý code. Bạn là PM, Claude là engineer.
Vibe coding phù hợp cho prototyping và features không critical. Với security, payment, authentication — vẫn cần Code review cẩn thận.
Anti-patterns: Những cái bẫy phổ biến
Anti-pattern 1: Skip Plan để “save time”
Triệu chứng: “Plan Mode tốn thêm 10 phút, tôi muốn đi thẳng vào code.”
Tại sao sai: 10 phút Plan → tiết kiệm 30-90 phút debug. Đặc biệt với task medium trở lên.
Hệ quả: Claude đoán sai approach, viết code không match codebase, phải rollback và restart.
Fix: Luôn Plan cho task medium+. Đối với tiny task (fix typo, rename), skip Plan là đúng — nhưng đó là exception, không phải rule.
Anti-pattern 2: Analysis paralysis — Plan mãi, không Code
Triệu chứng: Revise plan lần thứ 6, vẫn thấy “chưa perfect”, không dám approve.
Tại sao sai: Plan không thể predict mọi thứ. Một số vấn đề chỉ xuất hiện khi bắt đầu implement.
Fix: Plan đủ tốt (không cần perfect) → approve → Code → điều chỉnh khi gặp vấn đề thực tế. Nguyên tắc: nếu plan đã cover happy path + main edge cases, approve. Refinement xảy ra trong Code phase.
Anti-pattern 3: Code không có test suite
Triệu chứng: Không có test, hoặc test nhưng không reliable.
Tại sao sai: Không có test → Claude không thể tự verify → phải hỏi bạn sau mỗi bước → back-and-forth tốn thời gian của cả hai. Tệ hơn: bạn không biết feature “đúng” hay không cho đến khi manual test.
Fix: Đầu tư viết test suite ngay từ đầu. Nếu chưa có, prompt Claude viết test trước khi implement. Test là “source of truth” cho cả bạn và Claude.
Anti-pattern 4: Commit không review
Triệu chứng: Code xong → git add -A && git commit -m "..." && git push không review.
Tại sao sai: Claude có bias từ session. Nó “biết” code đó đúng vì chính nó viết. Subagent reviewer fresh không có bias đó và thường catch được issues Claude bỏ qua.
Fix: Dù review nhanh 2 phút hay subagent chi tiết 5 phút — luôn có một bước review trước commit.
Anti-pattern 5: Full EPCC cho tiny task
Triệu chứng: Fix typo một chữ mà vẫn vào Plan Mode, viết plan chi tiết.
Tại sao sai: Overhead của workflow lớn hơn task. Làm mất đà và demotivating.
Fix: Calibrate theo task size. Tiny task → Code + Commit trực tiếp. Workflow là công cụ, không phải nghi lễ bắt buộc mọi lúc.
Mẹo nâng cao
Mẹo 1: /rewind — rollback khi đi sai hướng
Nếu Claude bắt đầu implement theo hướng sai (ngay cả khi bạn đã approve plan), bạn có thể rollback:
/rewind đưa bạn về conversation state trước đó, bao gồm cả code state (nếu Claude dùng checkpoint). Không phải lúc nào cũng rollback hoàn hảo — git worktree hoặc git stash vẫn là safety net tốt hơn — nhưng /rewind nhanh hơn nhiều cho quick course-correct.
Mẹo 2: /compact giữa các phases
Sau Explore phase, context đã chứa nhiều nội dung file bạn explore. Trước khi vào Plan phase, compact:
Claude tóm tắt những gì đã tìm hiểu, giải phóng context cho Plan phase. Bạn không mất thông tin quan trọng, nhưng context gọn lại. Xem chi tiết ở Bài 2.5: Quản lý Context.
Mẹo 3: Plan-as-document
Với task lớn, đừng để plan chỉ tồn tại trong conversation. Lưu ra file:
"Trước khi approve, lưu plan này vào docs/plans/webp-conversion-plan.md
trong repo. Tôi muốn version control plan này."
Lợi ích:
- Plan được commit vào repo — team khác xem được
- Nếu session crash, bạn vẫn có plan
- Sau khi done, plan trở thành documentation
- Có thể reference lại trong future sessions
Mẹo 4: Test-driven prompt
Thay vì “implement feature X”, thử:
"Viết test cases cho feature X trước. Tôi sẽ review.
Sau khi tôi approve tests, implement để tests pass."
Approach này force Claude (và bạn) phải suy nghĩ rõ ràng về expected behavior trước khi viết implementation. Ít bug hơn, cleaner code hơn.
Mẹo 5: Sử dụng CLAUDE.md để persist workflow rules
Nếu bạn có workflow rules mà muốn Claude follow mọi lúc (ví dụ: “luôn chạy tests trước commit”, “không thêm dependency mà không hỏi”), đưa vào CLAUDE.md:
## Workflow Rules
- Luôn chạy test suite trước khi declare "done"
- Không thêm npm dependency mới mà không list ra và get approval
- Mọi async function phải có error handling
- Commit message format: conventional commits (feat/fix/chore/docs)
Claude sẽ follow những rules này trong mọi session, không cần bạn nhắc lại. Xem Bài 2.7: File CLAUDE.md để hiểu cách setup file này.
Áp dụng ngay
Bài tập 1: Full EPCC trong 30 phút
Chọn 1 task vừa phải trong project bạn đang làm. Không quá lớn (không phải refactor toàn bộ architecture), không quá nhỏ (không phải sửa typo). Ví dụ tốt: thêm 1 endpoint mới, implement 1 validation logic mới, refactor 1 function phức tạp.
Áp dụng full EPCC và ghi chép:
Task: _________________________________________________
Thời gian thực tế:
- Explore phase: _____ phút
- Plan phase: _____ phút (bao gồm revise rounds)
- Code phase: _____ phút (Claude execute + bạn verify)
- Commit phase: _____ phút (review + commit message)
- TOTAL: _____ phút
Nhận xét:
- Phase nào tốn nhiều thời gian nhất? _____________
- Có lúc nào muốn skip phase nào không? ___________
- Subagent reviewer catch được issue gì? __________
So sánh với ước tính ban đầu của bạn. Hầu hết người dùng lần đầu ngạc nhiên rằng Plan phase nhanh hơn họ nghĩ.
Bài tập 2: A/B test workflow
Trong 1 sprint, làm 2 task tương tự nhau. 1 task với full EPCC, 1 task không dùng EPCC (làm theo cách cũ).
Đo:
- Time-to-merge (từ lúc bắt đầu đến khi PR được merge)
- Số lần phải rollback hoặc rewrite
- Số bug report sau khi merge (nếu có)
- Cảm giác chủ quan: task nào ít stress hơn?
Hầu hết người dùng báo cáo: EPCC task mất ít thời gian hơn về total (kể cả thời gian Plan), và ít stress hơn nhiều.
Tóm tắt
Explore → Plan → Code → Commit là workflow trung tâm của mọi thứ trong khoá này.
5 takeaways quan trọng nhất:
- EPCC không phải overhead — đây là cái làm cho bạn nhanh hơn, không chậm hơn. 50% thời gian dành cho Explore + Plan là investment, không phải waste.
- Plan Mode là công cụ alignment — nó force bạn và Claude phải agree trước khi code được viết. Đây là nơi rẻ nhất, nhanh nhất để course-correct.
- Test suite là multiplier — có test suite = Code phase tự vận hành. Không có test suite = bạn phải làm QA thủ công sau mỗi bước.
- Subagent reviewer = fresh eyes — Claude có bias từ session. Subagent reviewer không có. 5 phút review có thể catch bug mà 2 tiếng code không thấy.
- Calibrate theo task size — Tiny task: Code + Commit. Medium: full EPCC. Hard: EPCC nhiều vòng, commit nhiều phases. Workflow là công cụ, không phải nghi lễ.
Bài tiếp theo
Bạn vừa học workflow EPCC — vòng lặp cốt lõi khi làm việc với Claude Code. Nhưng khi áp dụng trong thực tế, bạn sẽ gặp ngay vấn đề: context window. Session dài, nhiều file đọc, nhiều tool calls → context bắt đầu đầy và Claude bắt đầu “quên” giữa chừng.
Bài 2.5: Quản lý Context sẽ dạy bạn cách dùng /context, /compact, /clear đúng lúc để session dài mượt hơn — và 5 chiến thuật tiết kiệm context từ đầu. Đây là kỹ năng bạn cần ngay lần đầu chạy EPCC trên task thực.
➡️ Bài tiếp theo: Bài 2.5 — Quản lý Context
Tài liệu tham khảo
Khoá học “Claude Code 101” — bản tiếng Việt v1.0. Bản quyền 2026 Anthropic. Mọi quyền được bảo lưu.