Sai lầm phổ biến nhất khi vibe coding là ném một prompt khổng lồ vào tool và chờ một app hoàn chỉnh. “Build me a marketplace with auth, seller dashboard, buyer checkout, payment, admin, analytics, notification, review system.” Mười phút sau bạn có một app nhìn rất bận rộn. Ba mươi phút sau bạn phát hiện login giả, checkout không xử lý lỗi, dashboard dùng mock data, admin sửa gì cũng mất sau refresh. Hai giờ sau bạn không còn biết sửa từ đâu.
AI yếu hay mạnh chưa phải câu hỏi chính. Bạn vừa tạo review debt quá lớn. Một prompt quá rộng sinh ra quá nhiều thứ cần kiểm tra cùng lúc. Khi có bug, bạn không biết bug nằm ở requirement, UI, data, state, auth, API hay prompt.
Build theo lát mỏng là cách giảm nợ đó. Mỗi vòng chỉ tạo một phần nhỏ nhưng phải nhìn thấy được, click được, test được, và quay lại được.
Lát mỏng là gì
Một lát mỏng không nên là task kỹ thuật bé xíu như “tạo component Button”. Với vibe coding, lát mỏng nên là một miếng sản phẩm end-to-end đủ nhỏ để người dùng kiểm tra.
Ví dụ app booking:
- Lát quá mỏng theo kiểu kỹ thuật: tạo database model booking.
- Lát quá dày: build toàn bộ booking app với payment, calendar, email.
- Lát mỏng đúng: tạo màn hình danh sách booking với sample data rõ ràng, có filter theo ngày và status.
Lát đúng có bốn tiêu chí:
- Visible: mở app lên thấy kết quả.
- Clickable: có interaction thật, không chỉ layout tĩnh.
- Testable: bạn biết cách kiểm tra đúng/sai.
- Reversible: nếu sai, rollback hoặc bỏ lát đó mà không phá toàn app.
Nếu một vòng build không thỏa bốn tiêu chí này, nó quá mơ hồ hoặc quá lớn.
Vì sao full-app prompt tạo review debt
Full-app prompt hấp dẫn vì nó cho cảm giác đi nhanh. Bạn nói một lần, AI làm nhiều màn hình. Nhưng càng nhiều màn hình, càng nhiều giả định ẩn.
AI phải đoán:
- Data model gồm những field nào.
- Auth có cần role không.
- Flow nào là chính.
- Empty state hiển thị gì.
- Error state xử lý ra sao.
- Mobile layout ưu tiên phần nào.
- Feature nào version 1, feature nào sau này.
Mỗi giả định sai là một lỗi. Nhưng lỗi không hiện ngay vì app vẫn chạy. Bạn nhìn dashboard đẹp và tưởng ổn. Tới lúc dùng thật mới thấy form thiếu trường quan trọng hoặc data không lưu.
Review debt là phần kiểm tra bạn nợ sau khi AI build quá nhiều. Debt này không tự biến mất. Nó chuyển thành bug, rewrite, hoặc cảm giác “AI làm nhanh nhưng sao cuối cùng vẫn mất thời gian”.
Cách chia app thành lát
Hãy chia theo flow người dùng, không chia theo module kỹ thuật trước.
Với app SaaS nhỏ, tôi thường đi theo nhóm logic thay vì liệt kê từng bước:
Đầu tiên là entry point, tức public screen hoặc landing tối thiểu đủ để biết app làm gì. Tiếp theo là core data loop: form tạo record, list xem record, rồi detail/edit. Ba lát này liên kết chặt, cần chạy đúng trước khi làm bất cứ thứ gì khác.
Khi core loop ổn, mới tới auth thật nếu trước đó dùng fake gate, rồi dashboard hoặc summary nếu cần. Admin và payment luôn nằm cuối. Không phải vì ít quan trọng mà vì chúng phụ thuộc vào toàn bộ data model và permission logic, build sớm thì gần như chắc chắn phải viết lại.
Ví dụ app quản lý lead du lịch:
Slice 1:
Build the lead list screen with clearly labeled sample data.
Show customer name, destination, travel date, group size, budget, status, note.
Add filter by status.
Do not add create/edit yet.
After building, tell me how to test the filter.
Slice 2:
Add a create lead form.
Fields: customer name, WhatsApp, destination, travel date, group size, budget, status, note.
After submit, the new lead should appear in the list without page reload.
Keep data in local state for now and label it as temporary prototype data.
Do not add backend yet.
Slice 3:
Add lead detail editing.
User can update status and note only.
Do not change the create form fields.
Do not add delete.
Ba lát này cho phép bạn kiểm tra từng phần. Nếu filter sai, sửa trước khi thêm form. Nếu form sai, sửa trước khi thêm edit. Nếu edit sai, bạn biết phạm vi bug.
Homepage, auth, form, dashboard, payment, admin
Một cách chia cụ thể hơn:
Homepage hoặc landing chỉ cần nếu app có public visitor. Internal tool thì bỏ qua, đừng tốn vòng đầu làm hero section. Test đơn giản: người dùng nhìn vào biết app làm gì và bấm gì tiếp không?
Auth:
- Nếu prototype chưa nối auth thật, ghi rõ đây là placeholder. Đừng để AI tạo “fake login” rồi cả team dùng tưởng thật.
- Nếu dùng auth thật, phải test đủ ba trường hợp hay bị bỏ qua: logout, expired session, và wrong role redirect.
Form là lát quan trọng nhất trong hầu hết app. Tôi test theo thứ tự: required fields và validation trước, rồi cancel flow, rồi duplicate submit, rồi mobile keyboard. Lý do test theo thứ tự đó là mỗi bước sau phụ thuộc bước trước. Form thiếu field nghiệp vụ thì dashboard có đẹp cũng không cứu được.
Dashboard/list:
- Bắt đầu bằng table hoặc list scan được, đừng vội làm chart.
- Chart chỉ có ý nghĩa khi có data thật. Với sample data, chart chỉ là noise.
- Test sort, filter, empty state, và long text. Long text hay bị bỏ qua nhất.
Payment cần xử lý riêng, không trộn vào form đầu tiên. Một lát payment đúng bao gồm sandbox account, webhook handler, error state, refund flow, receipt, và security review. Nếu không có đủ thời gian làm hết, chưa nên làm.
Admin để sau khi user flow chính ổn. Admin đụng permission và destructive action, test role boundary kỹ trước khi tin vào output của AI.
Prompt cho từng lát
Một prompt lát mỏng nên có cấu trúc:
Continue from the current prototype.
Goal for this slice:
- [One user-visible outcome]
Allowed changes:
- [Area allowed]
Do not change:
- [Known good parts]
Acceptance checks:
1. [Manual check]
2. [Manual check]
3. [Manual check]
After building:
- Summarize changed files or changed areas.
- List anything still mock/temporary.
Ví dụ:
Continue from the current booking prototype.
Goal for this slice:
- Add edit deposit status from the booking detail panel.
Allowed changes:
- Booking list row action.
- Booking detail panel.
- Booking state update.
Do not change:
- Booking creation form fields.
- Date filter behavior.
- Visual style of the table.
Acceptance checks:
1. Open a booking and change deposit status from unpaid to paid.
2. Close detail panel and confirm table status updates.
3. Refresh page and confirm data persistence behavior is clearly labeled. If data is not persisted, say so in UI or summary.
Đây là prompt boring nhưng hiệu quả. Nó giảm khả năng AI sửa lại cả app vì hiểu nhầm “improve booking”.
Khi nào tiếp tục chat, khi nào mở chat mới
Continue chat khi bạn đang sửa cùng một lát, context còn ngắn và rõ, AI vẫn nhớ đúng constraint, và những lần sửa gần nhất có chất lượng tốt.
Mở chat mới khi chat đã quá dài và các quyết định cũ gây nhiễu, AI bắt đầu nhắc lại lỗi đã sửa, hoặc bạn chuyển sang lát real API/auth sau khi prototype UI ổn rồi. Cũng nên mở chat mới nếu muốn một agent khác review độc lập, hoặc khi cần reset scope sau khi AI tự mở rộng quá nhiều.
Khi mở chat mới, đừng paste toàn bộ lịch sử. Tạo handoff ngắn:
Current state:
- Booking list, create form, edit deposit status are working with sample data.
- Payment, staff, email automation are intentionally not built.
- Data is still local state.
Next slice:
- Replace local sample data with existing bookings API.
Do not change:
- Form fields.
- Table layout.
- Status values.
Known issue:
- Mobile filter row wraps awkwardly at 390px.
Chat mới vẫn giữ được context nếu bạn handoff tốt. Đổi chat đúng lúc còn giúp giảm nhiễu.
Failure modes cần nhận ra sớm
AI rewrite lại phần đã đúng. Dấu hiệu: bạn yêu cầu thêm filter, nó đổi layout, đổi field, đổi color, đổi navigation. Cách xử lý: yêu cầu revert phần không liên quan hoặc rollback checkpoint, rồi prompt lại với do not change.
AI thêm feature ngoài scope. Dấu hiệu: bạn yêu cầu form, nó thêm analytics. Cách xử lý: ghi defer list rõ hơn. Đừng khen app “đầy đủ” rồi cố dùng tiếp, vì feature thừa vẫn phải maintain.
AI sửa bug bằng cách che bug. Dấu hiệu: error biến mất nhưng flow không còn chạy, validation bị bỏ, button disabled luôn. Cách xử lý: yêu cầu giải thích root cause và acceptance check.
AI dùng mock để làm app xanh. Dấu hiệu: refresh mất data, login luôn pass, API call không xuất hiện, status update chỉ đổi local state. Cách xử lý: label mock rõ hoặc chuyển sang lát real data riêng.
Checklist sau mỗi lát
- Tôi có biết lát này thêm gì không? Có phần nào ngoài scope bị đổi theo không?
- Tôi đã click flow chính chưa?
- Tôi đã thử mobile chưa?
- Tôi đã thử empty/loading/error nếu liên quan chưa?
- Data đang mock hay real? Nếu mock, đã label rõ chưa?
- Có checkpoint hoặc Git state để quay lại nếu lát tiếp theo làm hỏng không?
Nếu lát hiện tại chưa ổn, đừng thêm lát mới. Vibe coding nhanh nhất khi mỗi vòng đủ nhỏ để sửa ngay.
Một bước biết đúng hay sai, quan trọng hơn mười bước không biết
Full-app prompt tạo cảm giác đi nhanh. Nhưng chi phí không biến mất, nó dịch chuyển sang review debt và rewrite sau đó. Lát mỏng chậm hơn ở phút đầu và nhanh hơn ở tháng sau. Không cần biến nó thành Scrum thu nhỏ hay quy trình phức tạp, chỉ cần một nguyên tắc vận hành: mỗi vòng tạo ra thứ bạn tự biết là đúng hay sai trước khi tiếp.