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:
PhaseVai trò
ExploreClaude 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.
CodeClaude execute theo plan. Bạn verify, test, điều chỉnh nếu cần.
CommitReview 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ỏiTạ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:
  1. Task là gì? (mô tả rõ ràng, không mơ hồ)
  2. Constraints là gì? (thứ Claude KHÔNG được làm hoặc phải tuân theo)
  3. 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ốtPlan 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àngBước 1, 2, 3 logic, dependency rõ ràngDanh sách không có thứ tự
Có success criteria”Test X pass, endpoint Y return Z""Feature works”
Xử lý edge casesGIF animated, file size limit, error handlingChỉ handle happy path
Không thêm scopeChỉ làm đúng yêu cầu”Và nhân tiện refactor cả module upload”
FeasibleApproach khả thi với codebase hiện tạiAssume 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?
ModeKhi dùngTrade-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.

Yếu tố 2: Add tools phù hợp

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 taskExplorePlanCodeCommitThời gian ước tính
Tiny — sửa typo, đổi 1 constant, rename variableSkipSkipNhanhMinimal2-5 phút
Easy — thêm 1 field vào form, fix bug 1 fileOptionalOptionalNormalMinimal5-15 phút
Medium — feature mới hoàn chỉnh, refactor 1 moduleRequiredRequiredNormal + testFull review20-60 phút
Hard — redesign architecture, cross-cutting changeExtendedMultiple roundsPhased + nhiều testMultiple commits2-8 giờ
Massive — legacy modernization, platform migrationDaysDaysPhased over weeksPer-phase commitWeeks
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:
  1. Install @jimp/plugin-webp, update package.json
  2. Tạo services/image.service.ts với convertToWebP() function
  3. Update middleware/storage.ts — gọi converter trước upload
  4. Update services/upload.service.ts — handle WebP filename
  5. 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:
Double Escape → /rewind
/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:
> /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.