+4

Claude Code 101: Hướng dẫn toàn diện từ zero

Claude Code từ Zero: Hướng dẫn toàn diện cho người mới bắt đầu

Bạn đang code theo kiểu cũ — gõ từng dòng, tra Stack Overflow, copy-paste từ ChatGPT, hay "hợp thời" hơn là refer từng file code rồi gõ prompt nhờ AI đọc source để đưa ra gợi ý hoặc nhờ AI code luôn. Không có gì sai cả. Nhưng có một cách làm việc khác, nhanh hơn, thú vị hơn, và thành thật mà nói — đang trở thành kỹ năng bắt buộc trong năm 2026.


Đây sẽ là một blog khá dài, nên trước khi bắt đầu, hãy chuẩn bị cho mình một cốc nước, một tách cà phê, hoặc bất cứ thứ gì khiến bạn thấy thoải mái nhất. Rồi cùng ngồi xuống và tận hưởng hành trình trong bài viết này nhé ☕

Mục lục

  1. Tại sao Claude Code? Mindset shift
  2. Cài đặt & Setup
  3. Vòng lặp cơ bản: Chat, @ mentions, Context
  4. .claude Directory: Bộ não dự án
  5. Permissions System
  6. Context Management
  7. Slash Commands
  8. MCP Tools: Kết nối với thế giới bên ngoài
  9. Hooks & Automation
  10. Sub-agents chuyên biệt
  11. Model Selection & Tối ưu chi phí
  12. Thực chiến: Workflow end-to-end
  13. Troubleshooting: Những lỗi phổ biến
  14. Security Checklist: Dùng Claude Code an toàn

1. Tại sao Claude Code? Mindset shift

Vibe coding là gì?

Hãy tưởng tượng bạn có một junior dev cực kỳ chăm chỉ, không bao giờ mệt, không bao giờ phàn nàn, và có thể đọc toàn bộ codebase của bạn trong vài giây. Đó là Claude Code.

Vibe coding không phải là "AI viết code thay bạn rồi bạn ngồi chơi". Nó là phong cách làm việc mà bạn mô tả ý định ở mức cao, Claude thực thi, bạn review và định hướng. Giống như một senior architect làm việc với một team dev giỏi.

Tại sao đây là thời điểm vàng?

  • Các model AI đang ở đỉnh cao chưa từng có — Claude Sonnet 4.6 viết code tốt hơn 90% developer thực tế
  • Những người học cách làm việc với AI ngay bây giờ sẽ có lợi thế khổng lồ trong 2-3 năm tới
  • Các công ty đang tuyển "AI-native engineer" — người biết dùng AI như công cụ chính, không phải công cụ phụ

Mindset cần thay đổi

Tư duy cũ Tư duy mới
"Tôi phải tự viết từng dòng code" "Tôi mô tả, Claude thực thi, tôi review"
"Dùng AI là gian lận" "Dùng AI là kỹ năng"
"Tôi cần hiểu từng detail" "Tôi cần hiểu đủ để review và định hướng"
"Code mình viết mới tin được" "Code đúng test mới tin được"

Quan trọng: Bạn vẫn cần hiểu code. Claude Code không dành cho người muốn "không cần học gì". Nó dành cho người muốn học nhanh hơn và build nhanh hơn.


2. Cài đặt & Setup

Bước 1: Cài Claude Code CLI

Claude Code chạy trong terminal. Bạn cần Node.js 18+ trước.

# Kiểm tra Node.js
node --version  # phải >= 18

# Nếu chưa cài Node.js, cài tại nodejs.org hoặc dùng nvm:
# curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# nvm install 20

# Cài Claude Code globally (recommended)
npm install -g @anthropic-ai/claude-code

# Hoặc chạy mà không cài (không cần cài, nhưng chạy chậm hơn)
npx @anthropic-ai/claude-code

# Kiểm tra cài thành công
claude --version

Bước 2: Xác thực

Có 2 cách để dùng Claude Code:

Cách 1: Dùng Claude.ai subscription (khuyến nghị cho người mới)

claude
# Lần đầu chạy, Claude Code sẽ mở browser để bạn đăng nhập claude.ai
# Cần plan Pro hoặc Max (xem giá tại claude.ai/pricing)

Cách 2: Dùng Anthropic API key (cho developer)

export ANTHROPIC_API_KEY="sk-ant-..."
claude

Nên chọn cái nào? Nếu bạn dùng nhiều (> 2 tiếng/ngày), plan subscription thường rẻ hơn trả theo lượt API. Nếu dùng ít hoặc cần tích hợp vào CI/CD, dùng API key.

Bước 3: Cài VSCode Extension

  1. Mở VSCode
  2. Tìm extension "Claude Code" (publisher: Anthropic)
  3. Cài và reload
  4. Extension sẽ tự nhận diện Claude Code CLI đã cài

Sau khi cài, bạn sẽ thấy Claude Code panel ở sidebar VSCode. Bạn có thể chat trực tiếp trong IDE thay vì phải chuyển qua terminal.

Bước 4: Khởi động dự án đầu tiên

# Di chuyển vào thư mục dự án
cd my-project

# Khởi động Claude Code
claude

# Hoặc dùng trực tiếp với một prompt
claude "giải thích codebase này cho tôi"

3. Vòng lặp cơ bản: Chat, @ mentions, Context

Cách chat cơ bản

Giao diện của Claude Code đơn giản — bạn gõ, Claude trả lời và thực hiện hành động. Nhưng có một số pattern giúp bạn nhận kết quả tốt hơn nhiều.

Không hiệu quả:

"fix bug"

Hiệu quả:

"Hàm calculateDiscount trong src/pricing.ts đang trả về giá âm khi 
discount > 100%. Fix lại để throw error khi discount không hợp lệ 
(< 0 hoặc > 100), và thêm unit test."

Công thức: Cái gì + Ở đâu + Điều kiện + Kết quả mong muốn

@ mentions: Đưa context vào conversation

@ là cách bạn nói với Claude "hãy nhìn vào chỗ này". Dùng trong chat conversation (VSCode panel hoặc terminal), không phải terminal commands:

Trong chat conversation, gõ:

"Review @src/auth/login.ts và tìm security issues"
^ Khi bạn gõ @, VSCode sẽ suggest files/folders

"Giải thích cách hoạt động của @src/components/"

"So sánh cách handle error trong @src/api/users.ts và @src/api/products.ts"

Các lệnh một dòng hữu ích

# Giải thích nhanh một file (dùng đường dẫn thực, không cần @)
claude "giải thích src/utils/parser.ts"

# Tìm bug
claude "tìm tất cả chỗ có thể gây memory leak trong src/"

# Review PR
claude "review các thay đổi trong git diff này"

Lưu ý: Cú pháp @file là tính năng của interactive mode (khi bạn đang trong REPL sau khi gõ claude). Với one-liner CLI, dùng đường dẫn trực tiếp.

Context tips

  • Cụ thể về file: Đừng nói "trong code", hãy nói "trong @src/auth/login.ts dòng 42"
  • Cụ thể về output: "Trả về chỉ code, không giải thích" hoặc "Giải thích từng bước trước khi code"
  • Đặt câu hỏi trước khi làm: Với task phức tạp, hỏi Claude "Em hiểu yêu cầu chưa, giải thích lại cho anh nghe" trước khi để nó bắt tay vào làm

4. .claude Directory: Bộ não dự án

Đây là phần quan trọng nhất để Claude Code hoạt động tốt trong dự án của bạn. Thư mục .claude/ chứa mọi thứ Claude cần để hiểu dự án, tuân thủ quy tắc, và làm việc đúng cách.

Cấu trúc thư mục

.claude/
├── CLAUDE.md                    ← bộ não dự án
├── CLAUDE.local.md              ← bản private, không đẩy lên GitHub
├── settings.json                ← permissions + hooks
├── settings.local.json          ← settings private
├── memory/                      ← bộ nhớ cá nhân của Claude
├── rules/                       ← quy tắc chi tiết
│   ├── workflow.md
│   ├── design.md
│   └── tech-defaults.md
├── agents/                      ← các sub-agent chuyên dụng
│   ├── researcher.md
│   └── reviewer.md
├── skills/
│   ├── shop-amazon.md
│   └── run-security-scan.sh
└── hooks/
    ├── pre-commit.sh
    └── pre-push.sh

CLAUDE.md — File quan trọng nhất

CLAUDE.md là "bộ não" của dự án. Mỗi lần bắt đầu conversation, Claude sẽ đọc file này đầu tiên. Đây là nơi bạn viết mọi thứ Claude cần biết về dự án.

Ví dụ CLAUDE.md cho một dự án Java Spring Boot:

# My E-commerce API (Spring Boot)

## Tech Stack
- Java 21 + Spring Boot 3.x
- Spring Data JPA + Hibernate
- PostgreSQL (production), H2 (test)
- Maven
- JUnit 5 + Mockito + MockMvc cho testing
- Spring Security 6 (JWT)
- Spring Mail cho email

## Quy tắc code
- Theo layered architecture: Controller → Service → Repository
- Dùng constructor injection, KHÔNG dùng field injection (`@Autowired`)
- Mọi public method ở Service phải có unit test
- Exception handling tập trung qua `@RestControllerAdvice`
- Log bằng SLF4J (`private static final Logger log = ...`), KHÔNG dùng `System.out.println`

## Cấu trúc thư mục
- `src/main/java/com/myapp/` — Source code chính
  - `controller/` — REST controllers
  - `service/` — Business logic
  - `repository/` — JPA repositories
  - `entity/` — JPA entities
  - `dto/` — Request/Response DTOs
  - `exception/` — Custom exceptions
- `src/main/resources/` — application.yml, migrations
- `src/test/java/` — Unit và integration tests

## Quy trình làm việc
1. Trước khi code: chạy `mvn compile`
2. Trước khi commit: chạy `mvn test`
3. Dùng conventional commits: feat/fix/chore/docs

## Không được làm
- Không commit trực tiếp lên main
- Không xóa Flyway migration files
- Không để business logic trong Controller
- Không dùng `@Transactional` ở Controller layer

## Database
- Development: `jdbc:postgresql://localhost:5432/myapp_dev`
- Chạy migration: Flyway tự chạy khi start app
- Tạo migration: thêm file `src/main/resources/db/migration/V{n}__description.sql`

Tip: Hãy nghĩ CLAUDE.md như là tài liệu onboarding cho một developer mới vào team. Claude sẽ đọc và tuân thủ mọi thứ trong đó.

CLAUDE.local.md — Thông tin riêng tư

Thêm vào .gitignore:

echo ".claude/CLAUDE.local.md" >> .gitignore
echo ".claude/settings.local.json" >> .gitignore

Nội dung ví dụ:

# Local Config (không đẩy lên GitHub)

## Credentials (chỉ dùng trong local dev)
- Stripe test key: sk_test_...
- Database local: postgresql://localhost:5432/myapp_local

## Ghi chú cá nhân
- Branch hiện tại đang làm: feature/payment-flow
- Todo: fix bug #234 trước khi demo thứ 6

rules/ — Quy tắc chi tiết

Khi CLAUDE.md quá dài, hãy tách ra thành các file nhỏ trong rules/:

rules/workflow.md:

# Quy trình làm việc

## Trước khi bắt đầu task mới
1. Đọc task description kỹ
2. Hỏi lại nếu chưa rõ yêu cầu
3. Tạo plan ngắn gọn và confirm với tôi

## Khi viết code
- Viết test trước khi implement (TDD khi có thể)
- Commit nhỏ, thường xuyên
- Mỗi commit chỉ làm một việc

## Khi gặp lỗi
- Đọc error message kỹ trước khi fix
- Không đoán mò, trace từ root cause
- Nếu fix > 30 phút, report lại cho tôi

rules/tech-defaults.md:

# Tech Defaults

## REST API Design
- Response format chuẩn: `{ "data": ..., "message": ..., "status": ... }`
- HTTP status codes: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 404 Not Found
- Pagination: dùng `Pageable` của Spring Data, trả về `Page<T>`
- Validate input bằng `@Valid` + Bean Validation annotations

## Error Handling
- Tất cả exceptions xử lý trong `GlobalExceptionHandler` (`@RestControllerAdvice`)
- Business exceptions: extend `BaseBusinessException` với error code riêng
- Validation errors: trả về danh sách field errors rõ ràng
- KHÔNG để stack trace lộ ra response

## Testing Standards
- Unit test: mock dependencies bằng Mockito, không cần Spring context
- Integration test: dùng `@SpringBootTest` + `MockMvc`, dùng H2 in-memory DB
- Coverage tối thiểu: 80% cho Service layer
- Test method name: `methodName_whenCondition_thenExpectedResult`

## Performance
- Dùng `@Transactional(readOnly = true)` cho query-only methods
- Tránh N+1 query: dùng `JOIN FETCH` hoặc `@EntityGraph`
- Cache với Spring Cache (`@Cacheable`) cho data ít thay đổi

5. Permissions System

Tại sao cần permissions?

Claude Code có thể chạy command, đọc/ghi file, gọi API... Permissions system giúp bạn kiểm soát Claude được phép làm gì mà không cần confirm từng lần.

Lần đầu chạy, bạn sẽ thấy popup như này:

Claude wants to run: npm test
Allow? [y/n/always]
  • y — cho phép lần này
  • n — từ chối
  • always — luôn cho phép (thêm vào allowlist)

Cấu hình permissions trong settings.json

// .claude/settings.json
{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(npx prisma *)",
      "Read(**)",
      "Edit(**)",
      "Write(**)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force *)",
      "Bash(DROP TABLE *)"
    ]
  }
}

Trust levels

Level Ý nghĩa
allow Luôn cho phép, không hỏi
deny Luôn từ chối
(không khai báo) Hỏi từng lần

Ví dụ thực tế: Setup cho dự án web thông thường

{
  "permissions": {
    "allow": [
      "Bash(npm *)",
      "Bash(npx *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(git checkout *)",
      "Bash(git branch *)",
      "Read(**)",
      "Edit(**)",
      "Write(**)"
    ],
    "deny": [
      "Bash(git push --force *)",
      "Bash(git reset --hard *)",
      "Bash(rm -rf *)"
    ]
  }
}

Tip: Bắt đầu conservative, rồi thêm dần khi thấy cần. Đừng allow mọi thứ ngay từ đầu — đặc biệt là các lệnh destructive.


6. Context Management

Context window là gì?

Claude có "bộ nhớ làm việc" có giới hạn — gọi là context window. Khi conversation dài, Claude bắt đầu quên những gì nói ở đầu. Đây là challenge lớn nhất khi làm việc với AI trên dự án lớn.

Dấu hiệu context đang hết

  • Claude bắt đầu "quên" những gì đã thống nhất
  • Câu trả lời trở nên generic, không còn specific với dự án của bạn
  • Claude hỏi lại những thứ đã nói rồi

Chiến lược 1: /compact — Tóm tắt conversation, tiếp tục task hiện tại

Dùng khi conversation dài nhưng bạn vẫn muốn tiếp tục task hiện tại:

/compact

# Claude sẽ tóm tắt lại tất cả conversation và tiếp tục
# Context sẽ bé hơn, nhưng task context vẫn được giữ lại

Khi nào dùng: Sau khi context đầy khoảng trên 80%, khi thấy Claude bắt đầu "quên" setup ban đầu.

Chiến lược 2: /clear — Bắt đầu task hoàn toàn mới

Xóa toàn bộ conversation, bắt đầu fresh. Dùng khi chuyển sang task khác:

/clear

# Sau đó đưa context cụ thể cho task mới
"Context: Tôi đang build feature thanh toán cho e-commerce app.
Tech stack: Next.js + Stripe + Prisma.
File liên quan: @src/app/checkout/ @src/lib/stripe.ts

Task: ..."

Khi nào dùng: Khi chuyển sang feature/bug hoàn toàn khác. Tiết kiệm context window.

/compact /clear
Xóa conversation? Không
Giữ task context? Không
Dùng khi nào? Task dài, giữ momentum Task mới

Chiến lược 3: Dùng memory/ directory

Thư mục memory/ là nơi bạn lưu thông tin quan trọng để reference giữa các conversation:

.claude/memory/
├── user_preferences.md      ← sở thích làm việc của bạn
├── project_decisions.md     ← các quyết định đã đưa ra
└── ongoing_tasks.md         ← task đang làm dở

Quan trọng: Claude không tự động đọc thư mục này. Bạn cần reference rõ ràng trong chat (@.claude/memory/project_decisions.md) hoặc import trong CLAUDE.md:

@import .claude/memory/project_decisions.md

Ví dụ .claude/memory/project_decisions.md:

# Quyết định dự án

## Authentication
- Dùng Spring Security 6 + JWT (stateless)
- Token expiry: access token 15 phút, refresh token 7 ngày
- Không dùng Spring Session (đã quyết định tháng 3/2025)

## Database Schema
- User có thể có nhiều addresses (1-n, FetchType.LAZY)
- Order status: PENDING → CONFIRMED → SHIPPED → DELIVERED → CANCELLED
- Soft delete cho tất cả entities: thêm `deleted_at` column, dùng `@SQLRestriction`

## API Design
- RESTful API thuần túy, versioning qua URL `/api/v1/...`
- Không dùng GraphQL (đã quyết định — overhead không cần thiết với scale hiện tại)
- Internal service calls dùng Feign Client (đã setup trong `infrastructure/client/`)

Chiến lược 4: CLAUDE.md là anchor

Mọi thông tin quan trọng nên nằm trong CLAUDE.md. File này luôn được đọc đầu tiên, dù context đã bị reset hay conversation mới.


7. Slash Commands

Slash commands là gì?

Slash commands là các lệnh đặc biệt bắt đầu bằng /. Chúng được chia thành 4 nhóm:

Nhóm 1: Quản lý conversation

Lệnh Tác dụng
/clear Xóa toàn bộ conversation, bắt đầu mới
/compact Tóm tắt conversation, giải phóng context
/undo Hoàn tác hành động vừa thực hiện

Nhóm 2: Cấu hình

Lệnh Tác dụng
/config Xem và thay đổi settings
/model Chuyển đổi model (Opus/Sonnet/Haiku)
/fast Bật Fast mode (Opus nhanh hơn)

Nhóm 3: Thông tin & Debug

Lệnh Tác dụng
/doctor Kiểm tra health của Claude Code installation
/cost Xem chi phí đã dùng trong session
/help Danh sách tất cả commands

Nhóm 4: Skills (Custom commands)

/review          # Review code theo chuẩn dự án
/security-review # Kiểm tra bảo mật
/init            # Khởi tạo CLAUDE.md cho dự án mới

3 lệnh dùng hàng ngày

1. /compact — Dùng khi conversation dài

Sau một số  lượng tin nhắn nhất định, context bắt đầu hết. 
/compact giúp Claude tóm tắt lại và tiếp tục với bộ nhớ "sạch" hơn.

2. /clear — Bắt đầu task mới

Khi chuyển sang task hoàn toàn khác, bắt đầu conversation mới 
sẽ hiệu quả hơn là tiếp tục conversation cũ.

3. /cost — Theo dõi chi phí

Nếu dùng API key, /cost cho bạn biết đã tiêu bao nhiêu trong session.
Giúp tránh shock bill cuối tháng.

Tạo Custom Slash Command (Skills)

Bạn có thể tạo slash command riêng cho dự án. Ví dụ tạo /deploy-check:

<!-- .claude/skills/deploy-check.md -->
Kiểm tra tất cả điều kiện trước khi deploy:

1. Chạy `npm run typecheck` — phải pass 100%
2. Chạy `npm test` — phải pass 100%
3. Kiểm tra không có `console.log` trong `src/`
4. Kiểm tra không có hardcoded credentials
5. Review `CHANGELOG.md` đã được cập nhật chưa
6. Báo cáo kết quả theo format:
   - ✅ Pass: [tên check]
   - ❌ Fail: [tên check] — [lý do]

Sau đó dùng:

/deploy-check

8. MCP Tools: Kết nối với thế giới bên ngoài

MCP là gì?

MCP (Model Context Protocol) là cách Claude kết nối với các dịch vụ bên ngoài — database, Slack, GitHub, Google Drive... Thay vì phải copy-paste qua lại, Claude có thể trực tiếp đọc, ghi, gọi API.

Cài MCP server

Có 2 cách cài MCP:

Cách 1: Dùng CLI command (recommended)

# Thêm MCP server qua terminal (ngoài Claude Code)
claude mcp add github -- npx -y @modelcontextprotocol/server-github

# Kiểm tra MCP đã cài chưa
claude mcp list

Cách 2: Manual setup qua settings.json

// .claude/settings.json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

Lưu ý: Trước khi dùng MCP GitHub, Slack, Google Drive... bạn cần setup authentication (API key, PAT token, etc.). Claude sẽ hướng dẫn khi cần.

Ví dụ thực tế: MCP + GitHub

Sau khi cài MCP GitHub:

"Lấy danh sách issues đang open trong repo này và sort theo priority"

"Tạo PR từ branch feature/payment sang main với description tự động 
generate từ git diff"

"Review PR #42 và comment những chỗ cần sửa"

Ví dụ thực tế: MCP + Slack

"Gửi message vào #dev-team channel: 'Deploy v2.1.0 lên staging thành công'"

"Đọc thread trong #bugs về lỗi login hôm qua và tóm tắt cho tôi"

Ví dụ thực tế: MCP + Database (PostgreSQL)

# Sau khi cài MCP database
"Lấy top 10 user có nhiều orders nhất trong tháng 4/2025"

"Có bao nhiêu orders ở trạng thái 'pending' quá 24 giờ?"

"Generate migration để thêm column `referral_code` vào bảng users"

Cấu hình MCP trong settings.json

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}"
      }
    }
  }
}

Lưu ý bảo mật: Không hard-code API keys trong settings.json. Dùng environment variables như ví dụ trên.


9. Hooks & Automation

Hooks là gì?

Hooks là các script tự động chạy trước hoặc sau một hành động của Claude. Ví dụ: mỗi lần Claude sửa file, tự động chạy formatter. Mỗi lần Claude commit, tự động chạy tests.

Cách hoạt động

Hooks được cấu hình trong settings.json và trỏ đến script trong thư mục hooks/:

// .claude/settings.json
{
  "hooks": {
    "postToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/format-on-save.sh"
          }
        ]
      }
    ],
    "preToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/pre-commit.sh"
          }
        ]
      }
    ]
  }
}

Hook events

Event Khi nào chạy
preToolUse Trước khi Claude dùng tool
postToolUse Sau khi Claude dùng tool
stop Khi Claude kết thúc response

Ví dụ 1: Auto format sau khi edit

Lưu ý kỹ thuật: Claude Code hooks nhận thông tin qua stdin dưới dạng JSON, không phải command-line arguments. Script cần đọc stdin để biết file nào vừa được chỉnh sửa.

# .claude/hooks/format-on-save.sh
#!/bin/bash
# Claude Code truyền context qua stdin dưới dạng JSON
INPUT=$(cat)
FILE=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('file_path',''))" 2>/dev/null)

if [[ "$FILE" == *.java ]]; then
  # Dùng google-java-format để format Java (cần cài trước)
  # Download: https://github.com/google/google-java-format/releases
  java -jar ~/.local/bin/google-java-format.jar --replace "$FILE"
  echo "✅ Formatted: $FILE"
fi

Ví dụ 2: Pre-commit checks

# .claude/hooks/pre-commit.sh
#!/bin/bash
set -e

echo "🔍 Chạy pre-commit checks..."

# Compile check
echo "Compiling..."
mvn compile -q
if [ $? -ne 0 ]; then
  echo "❌ Compilation failed. Commit aborted."
  exit 1
fi

# Tests
echo "Running tests..."
mvn test -q
if [ $? -ne 0 ]; then
  echo "❌ Tests failed. Commit aborted."
  exit 1
fi

# Check for System.out.println
if grep -r "System\.out\.println" src/main/ --include="*.java"; then
  echo "⚠️  Found System.out.println in production code. Dùng SLF4J logger thay thế."
  exit 1
fi

echo "✅ All checks passed!"

Ví dụ 3: Pre-push safety check

# .claude/hooks/pre-push.sh
#!/bin/bash
BRANCH=$(git branch --show-current)

# Không cho push thẳng lên main
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
  echo "❌ Không được push trực tiếp lên $BRANCH!"
  echo "Hãy tạo PR thay vì push trực tiếp."
  exit 1
fi

echo "✅ Branch $BRANCH OK to push"

Cách đăng ký hooks

// .claude/settings.json
{
  "hooks": {
    "preToolUse": [
      {
        "matcher": "Bash(git push*)",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/pre-push.sh"
          }
        ]
      }
    ]
  }
}

10. Sub-agents chuyên biệt

Sub-agents là gì?

Sub-agents là các "trợ lý chuyên biệt" mà Claude chính (orchestrator) có thể gọi ra để xử lý các task cụ thể. Mỗi sub-agent có expertise và quy tắc riêng.

Nghĩ như thế này: Claude chính là project manager, sub-agents là các specialist trong team.

Tạo sub-agent

Tạo file .md trong thư mục .claude/agents/. File này là prompt + metadata cho sub-agent:

agents/researcher.md:

# Researcher Agent

Chuyên gia research và phân tích. Dùng khi cần tìm hiểu về thư viện, 
so sánh options, hoặc phân tích codebase.

---

Bạn là một kỹ sư senior chuyên về research và phân tích kỹ thuật.

## Nhiệm vụ
- Phân tích và so sánh các giải pháp kỹ thuật
- Research thư viện, framework, và best practices
- Đọc và tóm tắt documentation
- Phân tích codebase hiện tại

## Cách làm việc
1. Luôn đọc source code trước khi đưa ra nhận xét
2. Đưa ra pros/cons cụ thể, có số liệu khi có thể
3. Recommend rõ ràng, giải thích lý do
4. Nếu không chắc, nói rõ "tôi không chắc về điều này"

## Output format
- Bắt đầu bằng TL;DR (1-2 câu)
- Theo sau là phân tích chi tiết
- Kết thúc bằng recommendation rõ ràng

agents/reviewer.md:

# Reviewer Agent

Code reviewer nghiêm khắc. Dùng khi cần review code trước khi merge. 
Tìm bugs, security issues, và vi phạm conventions.

---

Bạn là một senior engineer review code cực kỳ kỹ lưỡng.

## Tiêu chí review
1. **Security**: SQL injection, XSS, auth bypass, data exposure
2. **Performance**: N+1 queries, unnecessary re-renders, memory leaks
3. **Correctness**: Logic errors, edge cases chưa handle
4. **Conventions**: Tuân thủ CLAUDE.md và coding standards
5. **Tests**: Coverage đủ chưa, test có meaningful không

## Output format
Với mỗi issue tìm được:
- 🔴 Critical: phải fix trước khi merge
- 🟡 Warning: nên fix, có thể merge nhưng cần track
- 🟢 Suggestion: optional improvement

Kết thúc bằng: APPROVED / NEEDS CHANGES / REJECTED

Gọi sub-agent

# Claude chính sẽ tự quyết định khi nào dùng sub-agent
"Research và so sánh React Query vs SWR cho dự án này"
# → Claude sẽ gọi researcher agent

"Review toàn bộ thay đổi trong PR này"
# → Claude sẽ gọi reviewer agent

Hoặc gọi trực tiếp:

"Dùng researcher agent để phân tích @src/auth/ và tìm potential issues"

Ví dụ workflow với multiple agents

# Task: Migrate từ REST sang GraphQL

# Bước 1: Research phase
"Dùng researcher agent: phân tích codebase hiện tại và đánh giá 
effort để migrate sang GraphQL"

# Bước 2: Claude chính lên plan dựa trên research
"Dựa trên research, tạo migration plan theo phases"

# Bước 3: Implement
"Implement Phase 1: setup GraphQL server"

# Bước 4: Review
"Dùng reviewer agent: review toàn bộ code vừa implement trong @src/graphql/"

11. Model Selection & Tối ưu chi phí

Các model Claude

Model Tốc độ Giá Dùng khi nào
Claude Haiku 4.5 Nhanh nhất Rẻ nhất Task đơn giản, lặp đi lặp lại
Claude Sonnet 4.6 Cân bằng Trung bình Đa số công việc hàng ngày
Claude Opus 4.7 Chậm hơn Đắt nhất Task phức tạp, cần reasoning cao

Chiến lược chọn model

Dùng Haiku khi:

  • Format code (prettier, eslint fix)
  • Rename variables hàng loạt
  • Generate boilerplate code
  • Translate comments/docs

Dùng Sonnet khi (mặc định):

  • Viết feature mới
  • Debug code
  • Review code
  • Giải thích codebase

Dùng Opus khi:

  • Thiết kế architecture phức tạp
  • Debug lỗi khó, nhiều file liên quan
  • Refactor lớn
  • Security audit

Chuyển model

# Trong conversation
/model

# Hoặc set mặc định trong config
/config

Fast Mode

/fast
# Bật Fast Mode: dùng Opus với output nhanh hơn
# Không downgrade sang model nhỏ hơn

Lưu ý: Fast Mode yêu cầu Claude Pro hoặc Max subscription. Không có với API key.

Tips tiết kiệm chi phí

1. Dùng đúng model cho đúng task

# Đừng dùng Opus để format code
# Đừng dùng Haiku để thiết kế architecture

2. Context ngắn = ít tokens hơn

# Sau khi xong 1 task lớn, /clear và bắt đầu mới
# Đừng kéo dài conversation không cần thiết

3. Cụ thể trong prompt

# Bad: "fix code của tôi"  → Claude phải đọc nhiều, hỏi nhiều
# Good: "fix bug trong hàm X, file Y, dòng Z"  → ít tokens hơn

4. Theo dõi chi phí

/cost  # Xem đã dùng bao nhiêu trong session

5. Subscription vs API

Nếu bạn dùng Claude Code > 2 tiếng/ngày:

  • Claude Max subscription: unlimited Sonnet, nhiều Opus hơn
  • Rẻ hơn nhiều so với pay-per-token với lượng dùng cao
  • Xem giá hiện tại tại claude.ai/pricing

12. Thực chiến: Workflow end-to-end

Hãy xem một ví dụ thực tế: Build feature "Forgot Password" API trong Spring Boot từ đầu đến cuối.

Setup ban đầu

# 1. Di chuyển vào dự án
cd my-ecommerce-api

# 2. Khởi động Claude Code
claude

# 3. Kiểm tra context (Claude sẽ tự đọc CLAUDE.md)
"Em đã đọc CLAUDE.md chưa? Tóm tắt lại cho anh biết dự án này dùng gì"

Bước 1: Research & Planning

"Phân tích src/main/java/com/myapp/auth/ và cho anh biết:
1. Hiện tại authentication đang implement như thế nào (Spring Security config, JWT flow)
2. Cần thêm gì để làm Forgot Password API
3. Estimate effort (giờ)
Đừng code gì trước, chỉ phân tích thôi"

Claude trả lời với phân tích chi tiết. Bạn review, thêm requirement:

"OK, thêm yêu cầu:
- Reset token chỉ valid 1 giờ
- Gửi email bằng Spring Mail (config đã có, xem src/main/java/com/myapp/infrastructure/email/)
- Rate limit: tối đa 3 request/giờ per email (dùng Bucket4j hoặc Redis)
Bây giờ tạo plan theo từng bước nhỏ theo đúng layered architecture"

Bước 2: Implement từng phần nhỏ

# Step 1: Entity + Migration
"Implement Step 1: 
- Tạo JPA Entity PasswordResetToken với các field: id, user (ManyToOne), token, expiresAt, usedAt
- Tạo Flyway migration file tương ứng trong src/main/resources/db/migration/"

Claude tạo entity và migration. Bạn review, rồi verify compile được:

"Compile project để kiểm tra không có lỗi"
# → Claude chạy: mvn compile

# Nếu có lỗi, Claude tự fix
# Step 2: Repository + Service
"Implement Step 2:
- PasswordResetTokenRepository (Spring Data JPA)
- ForgotPasswordService với các method:
  + initiatePasswordReset(email): validate, tạo token, gửi email
  + validateToken(token): check tồn tại, chưa dùng, chưa hết hạn
  + resetPassword(token, newPassword): validate token rồi update password
- Viết unit test cho ForgotPasswordService với Mockito"
# Step 3: Controller
"Implement Step 3 - REST Controller với 2 endpoints:
- POST /api/v1/auth/forgot-password  body: { email }
- POST /api/v1/auth/reset-password   body: { token, newPassword, confirmPassword }
Thêm Bean Validation annotations cho request DTOs
Xử lý exceptions qua GlobalExceptionHandler đã có"

Bước 3: Review trước khi tiếp tục

# Manual review (hay dùng)
"Review toàn bộ code vừa viết trong src/main/java/com/myapp/auth/password/
tập trung vào security issues: token entropy, timing attack, information leakage"

# Hoặc dùng reviewer agent nếu đã tạo
"Dùng reviewer agent để check code vừa implement"

Note: Slash command /review không phải built-in. Nếu muốn dùng /review shortcut, bạn cần tạo file .claude/skills/review.md tương tự ví dụ ở Phần 7.

Bước 4: Integration Tests

"Viết integration test với @SpringBootTest + MockMvc cho toàn bộ forgot password flow:
1. POST /forgot-password với email hợp lệ → 200 OK (không reveal user tồn tại hay không)
2. POST /forgot-password với email không hợp lệ → 400 Bad Request
3. POST /forgot-password quá 3 lần trong 1 giờ → 429 Too Many Requests
4. POST /reset-password với token hợp lệ → 200 OK, password được update
5. POST /reset-password với token expired → 400 Bad Request
6. POST /reset-password với token đã dùng rồi → 400 Bad Request
Dùng H2 in-memory DB, mock email service để không gửi email thật"

Bước 5: Chạy full test suite

"Chạy toàn bộ test suite và fix nếu có lỗi"
# → Claude chạy: mvn test

Bước 6: Commit & Push

# Step 1: Commit với conventional commits
"Commit toàn bộ thay đổi. Message format:
feat: Thêm forgot password API
- PasswordResetToken entity + Flyway migration
- ForgotPasswordService với rate limiting
- REST endpoints POST /forgot-password và /reset-password
- Unit tests + integration tests"

# Step 2: Push lên branch
"git push origin feature/forgot-password"
# → Claude sẽ chạy lệnh này

Bước 7: Tạo PR (nếu dùng GitHub)

Nếu dùng GitHub và cài MCP GitHub:

"Tạo PR từ feature/forgot-password sang main với description:
- **What:** Thêm forgot password API hoàn chỉnh
- **Why:** Cho user khôi phục account khi quên password
- **API:**
  + POST /api/v1/auth/forgot-password
  + POST /api/v1/auth/reset-password
- **Testing:** 
  1. mvn test — tất cả tests pass
  2. Test thủ công bằng Postman (collection đã có trong /docs/postman/)
- **Checklist:**
  - [ ] Tests pass (mvn test)
  - [ ] Compile clean (mvn compile)
  - [ ] Không có System.out.println
  - [ ] Flyway migration được đặt tên đúng convention"

Nếu không cài MCP hoặc không dùng GitHub, bạn push branch và tạo PR bằng web UI GitHub.

Kết quả

Một feature Forgot Password API hoàn chỉnh với:

  • ✅ Flyway migration + JPA Entity
  • ✅ Service layer với business logic + rate limiting
  • ✅ REST Controller với validation + error handling
  • ✅ Spring Mail integration (email không hardcode)
  • ✅ Unit tests (Mockito) + Integration tests (MockMvc + H2)
  • ✅ Git commits + PR tạo sẵn

Thời gian: ~45 phút (thay vì 1-2 ngày làm thủ công) Chất lượng: Production-ready, full test coverage theo Spring Boot best practices


13. Troubleshooting: Những lỗi phổ biến

"Claude keeps asking for permission"

Problem: Mỗi lần Claude chạy command, bạn bị hỏi lại.

Solution: Setup permissions trong .claude/settings.json:

{
  "permissions": {
    "allow": [
      "Bash(mvn *)",
      "Bash(git status)",
      "Read(**)",
      "Edit(**)"
    ]
  }
}

"Claude forgot what we discussed earlier"

Problem: Conversation dài, Claude bắt đầu "quên".

Solution: Dùng /compact để tóm tắt, hoặc /clear + tạo conversation mới.

Prevention: Lưu thông tin quan trọng vào .claude/memory/ directory.

"MCP tools không hoạt động"

Problem: Sau khi cài MCP, Claude không thể dùng.

Checklist:

# 1. Kiểm tra MCP đã cài chưa
claude mcp list

# 2. Kiểm tra auth token (nếu cần)
echo $GITHUB_TOKEN  # hoặc API key khác

# 3. Restart Claude Code
# Đóng session, chạy lại: claude

"Compilation errors không được fix"

Problem: Claude sửa code nhưng vẫn có compile errors.

Solution: Khi gõ task, nhắc Claude:

"Fix bug này, đảm bảo mvn compile pass 100%"
# Claude sẽ chạy compile để verify

"Permissions keep getting reset"

Problem: Mỗi lần restart, permissions bị reset.

Solution: Dùng .claude/settings.json (persistent) thay vì inline always:

// Đúng
{
  "permissions": {
    "allow": ["Bash(mvn *)", "Read(**)", "Edit(**)"]
  }
}

// Sai (chỉ nhớ trong session này)
// Respond "always" khi bị hỏi

14. Security Checklist: Dùng Claude Code an toàn

Khi dùng Credentials & Secrets

✅ Làm:

  • Lưu credentials trong .env.local (thêm vào .gitignore)
  • Dùng environment variables: process.env.DATABASE_URL
  • Thêm .claude/CLAUDE.local.md vào .gitignore

❌ Không làm:

  • Không hard-code API keys trong code
  • Không paste secret vào conversation Claude
  • Không commit .env file hoặc settings.local.json lên GitHub

Khi dùng MCP Tools

✅ Làm:

  • Dùng environment variables cho auth tokens
  • Giới hạn permissions của Claude (deny destructive commands)
  • Review code trước khi cho Claude chạy git push

❌ Không làm:

  • Không cho Claude toàn quyền (không dùng allow: ["*"])
  • Không kết nối MCP đến production database khi dev
  • Không để Claude commit trực tiếp lên main

Khi dùng Hooks

✅ Làm:

# Good: Hook chạy format, không change logic
#!/bin/bash
npx prettier --write "$FILE"

❌ Không làm:

# Bad: Hook có thể fail silently
npx prettier --write "$FILE" || true  # Dangerous!

Khi dùng Sub-agents

✅ Làm:

  • Sub-agent chỉ dùng read-only tools (Read, Bash for inspection)
  • Sub-agent không thể commit/push trực tiếp
  • Main agent review output từ sub-agent trước khi apply

❌ Không làm:

  • Không cho sub-agent toàn quyền Edit + Bash
  • Không kết nối sub-agent trực tiếp tới production

Tổng kết

Bạn vừa học 14 phần toàn diện về Claude Code:

Phần Bộ công cụ
1-3 Mindset + Setup + Cách chat
4-7 .claude directory, Permissions, Context, Slash commands
8-11 MCP, Hooks, Sub-agents, Model selection
12 Workflow thực tế end-to-end
13-14 Troubleshooting + Security

Red flags: Khi nào KHÔNG dùng Claude Code

  • Không dùng khi bạn chưa hiểu requirement rõ ràng
  • Không dùng để "tránh học" — sẽ ship bugs
  • Không dùng làm work từ trái phép (security testing không authorized, etc.)
  • Không dùng khi bạn không có thời gian review code Claude viết

Mindset quan trọng nhất

Cuối bài, mình muốn kết luận rằng: Claude Code không phải là cây đũa thần. Nó là force multiplier — nó nhân lên năng lực của bạn. Nếu bạn hiểu vấn đề rõ ràng, biết cách đặt câu hỏi đúng, và biết cách review output — bạn sẽ productive gấp 5-10 lần.

Ngược lại, nếu bạn dùng nó để "tránh phải hiểu code" — bạn sẽ ship bugs nhanh hơn, không productive hơn.

Học cách làm việc với AI. Đó là kỹ năng quan trọng nhất của developer trong thập kỷ này.


Có câu hỏi hoặc muốn chia sẻ kinh nghiệm? Để lại comment bên dưới.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí