anh lam web image

Dùng AI Agent để code như một senior dev — Hướng dẫn thực tế


Bạn đã bao giờ hỏi AI "viết cho tôi API đăng nhập" và nhận về một đống code — nhưng không có test, không validation đúng chuẩn, và security thì... tùy hên?

Đó là vì bạn đang dùng AI như chatbot, không phải như developer.

Bài này hướng dẫn cách dùng AI có quy trình — giống một dev thật, không phải một cái máy copy-paste.

Ý tưởng cốt lõi: Workflow thay vì "hỏi đáp"

Thay vì hỏi AI "làm cái này cho tôi", hãy chia công việc thành 6 bước rõ ràng, mỗi bước có mục tiêu riêng:

  /spec → /plan → /build → /test → /review → /deploy

Nghe có vẻ nhiều — nhưng mỗi bước chỉ mất vài phút và giúp bạn tránh được hàng giờ debug sau đó.

Hãy xem qua một ví dụ thực tế: xây dựng tính năng đăng ký tài khoản.

Bước 1 — /spec: Nói rõ muốn gì trước khi làm

Gõ vào Claude Code:

  /spec Tính năng đăng ký tài khoản

AI sẽ không code ngay — thay vào đó nó tạo file SPEC.md để xác nhận bạn muốn gì:

  Mục tiêu
  Người dùng có thể tạo tài khoản bằng email và mật khẩu.

  Phạm vi
  - Input: email, password, confirm password
  - Validate email hợp lệ, password tối thiểu 8 ký tự
  - Hash password trước khi lưu
  - Trả về JWT sau khi đăng ký thành công

  Không nằm trong scope này
  - Đăng ký bằng Google/Facebook
  - Xác thực email

  Tiêu chí hoàn thành
  - POST /api/auth/register trả về 201 + token khi thành công
  - Trả về 400 nếu email đã tồn tại
  - Trả về 400 nếu password không đủ mạnh

Tại sao cần bước này? Không có spec, AI thường tự quyết — đôi khi implement OAuth luôn khi bạn chỉ cần email/password, hoặc bỏ qua validation vì "không thấy yêu cầu rõ".

Bước 2 — /plan: Chia nhỏ trước khi code

/plan

AI tạo ra todo.md — danh sách việc cần làm theo thứ tự, từng cái nhỏ đủ để làm trong một lần:

  - [ ] Tạo Zod schema validate input (email, password)
  - [ ] Viết test: đăng ký thành công → 201 + token
  - [ ] Viết test: email đã tồn tại → 400
  - [ ] Viết test: password yếu → 400
  - [ ] Implement POST /api/auth/register
  - [ ] Hash password với bcrypt (12 rounds)
  - [ ] Tạo JWT và trả về response

Đây không phải "plan cho vui" — AI sẽ follow đúng danh sách này trong bước tiếp theo, không tự ý thêm thứ ngoài scope.

Bước 3 — /build: Code theo TDD

/build

Đây là bước thú vị nhất. AI không code ngay — nó theo cycle RED → GREEN → REFACTOR.

--- RED: Viết test trước (test sẽ fail) ---

  describe('POST /api/auth/register', () => {
    it('trả về 201 và token khi đăng ký thành công', async () => {
      const res = await request(app)
        .post('/api/auth/register')
        .send({ email: '[email protected]', password: 'password123' })

      expect(res.status).toBe(201)
      expect(res.body).toHaveProperty('token')
    })

    it('trả về 400 nếu email đã tồn tại', async () => {
      await request(app).post('/api/auth/register')
        .send({ email: '[email protected]', password: 'password123' })

      const res = await request(app).post('/api/auth/register')
        .send({ email: '[email protected]', password: 'password123' })

      expect(res.status).toBe(400)
      expect(res.body.error).toMatch(/email already exists/i)
    })
  })

--- GREEN: Viết code tối thiểu để test pass ---

  export const register = async (req: Request, res: Response) => {
    const parsed = registerSchema.safeParse(req.body)
    if (!parsed.success) {
      return res.status(400).json({ error: parsed.error.message })
    }

    const exists = await prisma.user.findUnique({
      where: { email: parsed.data.email }
    })
    if (exists) {
      return res.status(400).json({ error: 'Email already exists' })
    }

    const hashed = await bcrypt.hash(parsed.data.password, 12)
    const user = await prisma.user.create({
      data: { email: parsed.data.email, password: hashed }
    })

    const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!, {
      expiresIn: '15m'
    })
    res.status(201).json({ token })
  }

--- REFACTOR ---

Sau khi test xanh hết, AI clean code — đặt tên rõ hơn, tách logic nếu cần — nhưng không thêm tính năng mới.

Lưu ý: Tối đa 100 dòng code giữa hai lần chạy test. Viết quá nhiều mà không test — dừng lại.

Bước 4 — /test: Kiểm tra coverage

 /test

AI chạy toàn bộ test và kiểm tra coverage. Ngưỡng tối thiểu là 80%:

  ✓ POST /auth/register - đăng ký thành công     PASS
  ✓ POST /auth/register - email đã tồn tại        PASS
  ✓ POST /auth/register - password yếu            PASS
  ✓ POST /auth/register - email không hợp lệ      PASS

  Coverage: 91% statements | 85% branches | 100% functions

Nếu coverage dưới 80%, AI sẽ tự viết thêm test cho các path còn thiếu trước khi tiếp tục.

Bước 5 — /review: Review 5 góc độ 

  /review

AI review theo 5 tiêu chí:

  Correctness   → Edge cases nào chưa handle?
  Readability   → Đọc code có hiểu ngay không?
  Architecture  → Đúng layer chưa? Logic nằm đúng chỗ không?
  Security      → Input validated chưa? Có hardcode secret không?
  Performance   → Query có bị N+1 không?

Ví dụ comment từ security review:

  ⚠ Không nên để JWT secret trong code — dùng process.env.JWT_SECRET
    (đã thấy trong implementation, cần verify .env.example có key này)

  ⚠ Password validation hiện chỉ check độ dài — nên thêm check
    có chứa chữ hoa/số để tăng độ bảo mật


== Bước 6 — /deploy: Deploy có kiểm soát ==

  /deploy

AI không chỉ push code — nó chạy theo quy trình:

  1. Build Docker image
  2. Chạy smoke test
  3. Health check: GET /health phải trả về 200
  4. Deploy lên production
  5. Kiểm tra error rate 5 phút đầu


Tóm lại

Thay vì hỏi AI "viết cho tôi cái này", làm việc có quy trình:

  Viết spec rõ → Chia nhỏ task → TDD → Verify coverage → Review kỹ → Deploy an toàn

Kết quả: code có test, có security check, có review — không phải may rủi.

---

Bạn đang dùng AI như thế nào trong workflow hàng ngày? Comment bên dưới nhé.


References

Class-AI-Agent framework (Claude Code governance framework):
https://github.com/fdhhhdjd/Class-AI-Agent