Bài viết

Biết giới hạn của Vibe Coding để không ship rác lên production

Vibe Coding rất hữu ích để tăng tốc prototype, nhưng nếu không đặt guardrail kỹ thuật, bạn sẽ biến LLM thành nguồn sinh bug rất nhanh.

Biết giới hạn của Vibe Coding để không ship rác lên production

Vibe Coding đang tiện, nhưng cũng đang làm nhiều team mất cảnh giác

“Vibe Coding” — mô tả nhanh là kiểu code bằng cảm giác, mô tả ý tưởng cho AI rồi để nó generate phần lớn implementation — đang trở thành workflow quen thuộc với developer dùng Cursor, Claude Code, GitHub Copilot, Windsurf hay ChatGPT. Nó cực kỳ hiệu quả khi bạn cần dựng prototype, viết script, refactor nhỏ, tạo test case ban đầu hoặc đọc codebase lạ.

Vấn đề là nhiều người đang nhầm “AI viết được code chạy” với “AI hiểu đủ context để ship production”. Hai thứ này khác nhau rất xa.

Một ví dụ gần đây trong cộng đồng AI Việt Nam: có người nhận xét một dataset tiếng Việt được tạo từ video/âm thanh nhưng cắt tự động, tạp âm đầu-cuối chưa xử lý, transcript không khớp audio. Đây là lỗi rất điển hình của workflow “để tool tự làm rồi tin kết quả”. Với code cũng vậy: LLM có thể generate API endpoint, migration, query, test — nhưng nếu input context bẩn hoặc thiếu guardrail, output nhìn có vẻ hợp lý nhưng sai ở tầng domain, data, security hoặc vận hành.

Giới hạn kỹ thuật của Vibe Coding: LLM không có “ý thức hệ thống”

Vibe Coding hoạt động tốt vì LLM đã học được rất nhiều pattern từ code public: REST controller nên viết thế nào, SQL query thường có cấu trúc gì, unit test mock ra sao, Dockerfile Node.js/Python/Go thường gồm những bước nào. Khi bạn prompt “viết API tạo user bằng FastAPI + PostgreSQL”, model có thể ghép các pattern phổ biến thành một đoạn code khá ổn.

Nhưng đó cũng chính là giới hạn: LLM chủ yếu dự đoán đoạn tiếp theo hợp lý theo context, không thật sự biết hệ thống của bạn đang chịu constraint gì nếu bạn không cung cấp. Nó không tự biết:

  • Bảng users của bạn có unique constraint nào
  • Transaction boundary đang nằm ở service hay repository
  • Tenant isolation dùng tenant_id, schema riêng hay RLS
  • API public có cần rate limit không
  • PII có được log hay không
  • Query có thể full scan trên bảng 200 triệu rows không
  • Migration có lock bảng production không
  • Test hiện tại chỉ pass vì mock quá lỏng

Đây là lý do Vibe Coding thường thất bại ở các phần không nằm trong “pattern code phổ biến”, gồm business rule, dữ liệu thật, vận hành production, bảo mật và backward compatibility.

Một anti-pattern phổ biến: developer yêu cầu AI “implement feature X”, sau đó đọc lướt thấy code đẹp, build pass, test pass, rồi merge. Nhưng build pass chỉ chứng minh syntax và dependency tạm ổn. Nó không chứng minh code đúng domain.

Ví dụ, prompt kiểu này rất dễ sinh code nguy hiểm:

1
2
3
Implement an endpoint to delete an organization.
Use NestJS, TypeORM and PostgreSQL.
Include service, controller and repository code.

LLM có thể generate delete from organizations where id = .... Nghe đúng, nhưng thực tế endpoint xoá organization trong SaaS thường cần nhiều thứ hơn:

  • Kiểm tra user có quyền owner/admin không
  • Không cho xoá organization đang có active subscription
  • Soft delete thay vì hard delete
  • Xoá hoặc archive tài nguyên liên quan theo policy
  • Ghi audit log
  • Idempotency nếu request retry
  • Transaction nếu có nhiều bảng liên quan
  • Không leak thông tin organization tồn tại hay không với user không có quyền

Prompt tốt hơn phải biến “vibe” thành spec có kiểm soát:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
You are implementing a production backend feature.

Context:
- Stack: NestJS 10, TypeORM, PostgreSQL 15
- Multi-tenant SaaS. Every table has organization_id.
- organizations table uses soft delete: deleted_at timestamp nullable.
- Only organization owners can delete an organization.
- Organization cannot be deleted if it has active subscriptions.
- Must write audit log into audit_events table.
- Must be idempotent: deleting an already deleted org returns 204.
- Do not hard delete any row.
- All writes must run inside one transaction.

Task:
1. Propose the service-level algorithm first.
2. List edge cases and failure modes.
3. Then implement controller + service code.
4. Add unit tests for:
   - non-owner forbidden
   - active subscription conflict
   - already deleted org returns 204
   - successful soft delete writes audit event
5. Point out assumptions instead of inventing schema silently.

Điểm khác biệt nằm ở chỗ: prompt thứ hai không chỉ yêu cầu “viết code”, mà buộc model phải đi qua algorithm, edge case, assumption và test. Bạn đang ép AI lộ suy luận thiết kế trước khi nó generate implementation. Đây là guardrail cơ bản nhất khi dùng Vibe Coding.

Một workflow thực tế hơn cho Vibe Coding nên gồm 5 bước:

  1. Context dump có chọn lọc: đưa schema, interface, convention, error handling, auth model. Không paste cả repo; paste phần liên quan.
  2. Yêu cầu plan trước code: bắt model mô tả approach, edge case, risk.
  3. Generate patch nhỏ: mỗi lần chỉ 1 module hoặc 1 behavior. Patch càng lớn, review càng khó.
  4. Chạy test + static check: unit test, integration test, typecheck, lint, migration dry-run.
  5. Human review theo checklist: domain correctness, security, data consistency, observability, rollback.

Nếu thiếu bước 5, bạn không còn là engineer dùng AI nữa; bạn trở thành người copy-paste code từ một autocomplete rất tự tin.

Một checklist ngắn có thể dùng ngay khi review code do AI generate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
## AI-generated code review checklist

### Domain
- [ ] Có đúng business rule không?
- [ ] Có case nào model tự bịa assumption không?
- [ ] Có xử lý idempotency/retry không?

### Data
- [ ] Query có dùng index phù hợp không?
- [ ] Migration có lock bảng lớn không?
- [ ] Có transaction cho multi-step write không?

### Security
- [ ] AuthN/AuthZ kiểm tra ở đúng tầng chưa?
- [ ] Có leak PII vào log/error response không?
- [ ] Input validation có đủ chặt không?

### Operations
- [ ] Có log/metric/tracing cho failure path không?
- [ ] Có backward compatibility với client cũ không?
- [ ] Có rollback plan nếu deploy lỗi không?

### Tests
- [ ] Test có cover negative cases không?
- [ ] Có integration test với database thật không?
- [ ] Test có assert behavior thay vì chỉ assert function được gọi không?

Ứng dụng thực tế: dùng Vibe Coding đúng chỗ trong backend team

Một backend team nhỏ có thể dùng Vibe Coding rất hiệu quả nếu phân loại task trước khi giao cho AI. Không phải task nào cũng có cùng mức rủi ro.

Nhóm task phù hợp:

  • Viết boilerplate controller/service/repository theo convention có sẵn
  • Tạo DTO, validation schema, OpenAPI spec
  • Viết unit test cho behavior đã rõ
  • Refactor lặp lại: đổi tên field, tách function, chuyển callback sang async/await
  • Viết script nội bộ: parse CSV, gọi API, generate report
  • Giải thích code legacy hoặc tìm luồng xử lý trong module lạ

Nhóm task phải cực kỳ cẩn thận:

  • Migration trên bảng lớn
  • Auth/permission
  • Payment/subscription
  • Multi-tenant isolation
  • Xử lý dữ liệu y tế, tài chính, PII
  • Query analytics trên dữ liệu lớn
  • Concurrency, lock, queue, retry, distributed transaction

Ví dụ một team đang làm API import dữ liệu khách hàng từ CSV. Vibe Coding có thể giúp generate parser, validate email/phone, map column, viết test cho file lỗi format. Nhưng phần quyết định “nếu email trùng thì merge hay reject”, “khách hàng thuộc tenant nào”, “log dữ liệu lỗi có chứa PII không”, “import 100k rows có timeout không” phải do engineer thiết kế.

Kết quả tốt nhất thường đến từ mô hình “AI làm junior implementer, engineer làm reviewer + architect”. Bạn để AI sinh bản nháp nhanh, nhưng không giao quyền quyết định domain. Với workflow này, team có thể giảm thời gian viết boilerplate và test case lặp lại, trong khi vẫn giữ được quality gate trước production.

Một mẹo thực tế: với task rủi ro trung bình trở lên, hãy yêu cầu AI tạo test trước implementation. Nếu test cũng do AI viết, bạn vẫn phải review test, nhưng ít nhất bạn có một artifact cụ thể để thảo luận: behavior mong muốn là gì. Test sai dễ phát hiện hơn một đoạn implementation sai nhưng chạy được.

Kết luận: Vibe Coding là accelerator, không phải autopilot

Vibe Coding không xấu. Nó chỉ nguy hiểm khi bạn dùng nó như một autopilot cho hệ thống production.

Ba takeaway cụ thể:

  1. Luôn bắt AI viết plan, assumption và edge case trước khi viết code. Nếu nó không nêu được rủi ro, đừng tin implementation.
  2. Chia task nhỏ và review bằng checklist. Patch AI generate càng lớn, xác suất bug ẩn càng cao.
  3. Không giao domain, security, data consistency cho “cảm giác”. Những phần này cần spec, test, log và review nghiêm túc.

Biết giới hạn của Vibe Coding không làm bạn code chậm hơn. Nó giúp bạn dùng AI nhanh hơn mà vẫn tỉnh táo khi đứng trước production.

Bài viết này được cấp phép bởi tác giả theo giấy phép CC BY 4.0 .