Ticket trông có vẻ đã ready cho tới khi trong buổi refinement có người hỏi một câu nhỏ: nếu customer đã dùng discount code này một lần rồi thì chuyện gì xảy ra? Cả phòng im một nhịp. User story nói customer có thể apply promotion ở checkout. Design có một ô nhập gọn gàng. API task cũng có endpoint rõ. Nhưng behavior mà mỗi người đang tưởng tượng lại không hoàn toàn giống nhau.
Đó là lúc acceptance criteria trở nên hữu ích. Nó không phải phần trang trí bên dưới user story, cũng không phải checklist riêng của QA ở cuối luồng. Acceptance criteria tốt là bằng chứng chung cho chữ done. Nó làm expected behavior hiện ra trước khi team mất vài ngày xây những phiên bản khác nhau của cùng một ý tưởng.
Một criterion tốt mô tả behavior có thể quan sát được. Nó không nói checkout phải chạy đúng, vì đúng nằm trong đầu mỗi người một kiểu. Nó nói rằng promotion code hợp lệ và chưa dùng sẽ giảm order total trước khi payment được tạo. Nó nói code hết hạn sẽ hiện error rõ ràng và giữ nguyên total. Nó nói code đã được chính account đó dùng thì không được apply lại. Câu chữ đơn giản, nhưng đủ để product, engineering, QA và support review cùng một bề mặt.
Acceptance criteria tốt thường nghe khá bình thường. Khi điều kiện này đúng, hệ thống làm hành động nhìn thấy được này. Khi điều kiện không đúng, hệ thống làm một hành động khác. Cấu trúc đó mạnh vì nó biến một lời hứa mơ hồ thành ví dụ. Developer nhìn ra nhánh logic. Tester nhìn ra case cần verify. Product owner nhìn được rule có khớp business decision không. Reviewer nhìn được scope có còn nằm trong ticket không.
Ví dụ quan trọng vì team hiếm khi hiểu sai happy path. Team thường hiểu lệch phần rìa xung quanh nó. Nếu user không có permission thì sao? Nếu data bị thiếu thì sao? Nếu payment provider timeout thì sao? Nếu cùng một button bị click hai lần thì sao? Nếu màn hình mobile ít chỗ hơn thì sao? Acceptance criteria không cần đoán hết mọi failure có thể xảy ra, nhưng nên gọi tên những edge case có thể làm đổi lời hứa của sản phẩm hoặc tạo rework tốn kém về sau.
Ở đây cần một sự cân bằng. Quá ít criteria làm team phải đoán. Quá nhiều criteria biến một story nhỏ thành một bản hợp đồng không ai muốn đọc. Điểm giữa hữu ích là cover behavior chứng minh story đã complete, các negative case quan trọng, và boundary của scope. Nếu một criterion mô tả một cải tiến hay nhưng có thể để sau, nó nên thành follow-up ticket. Nếu nó mô tả behavior mà thiếu đi thì feature gây hiểu nhầm hoặc không an toàn, nó thuộc về story hiện tại.
Mình thường viết criteria bằng ngôn ngữ đời thường trước, rồi chỉ siết lại vừa đủ. Một dòng như paid users can download invoices có thể là điểm bắt đầu, nhưng vẫn giấu nhiều câu hỏi. Invoice nào? Trong khoảng thời gian nào? Format gì? Nếu invoice vẫn đang generating thì sao? Mục tiêu không phải làm câu chữ giống văn bản pháp lý. Mục tiêu là bỏ đi kiểu mơ hồ khiến ai đó phải ngắt công việc giữa chừng để hỏi lại.
Given/When/Then có thể giúp khi behavior cần một scenario nhỏ. Given một customer có một unpaid invoice, when họ mở billing, then invoice hiện ra với pay action. Given invoice đã paid, when họ mở billing, then invoice hiện trạng thái paid và pay action bị ẩn. Format không phải điểm chính. Điểm chính là ví dụ đó review được. Mọi người có thể disagree với nó khi thay đổi vẫn còn rẻ.
Acceptance criteria tốt cũng bảo vệ scope của review. Một pull request dễ review hơn khi reviewer có thể map diff về một nhóm behavior đã hứa. Code đã xử lý valid code path chưa? Đã reject code hết hạn chưa? Total có giữ nguyên sau failure không? Nếu PR chứa việc không criterion nào nhắc tới, team có thể hỏi scope có đổi có chủ ý không. Nếu criteria nhắc tới behavior mà code chưa cover, gap hiện ra trước release.
Với QA, acceptance criteria không phải toàn bộ test plan, nhưng nó là một cái xương sống tốt. QA vẫn có thể explore khác biệt browser, accessibility, performance, data setup, và những tổ hợp lạ mà story chưa liệt kê. Nhưng criteria rõ giúp việc explore có điểm neo. Nó trả lời câu hỏi đầu tiên: bằng chứng nào khiến mình tin product behavior đã có mặt? Từ đó, testing có thể tìm xem bằng chứng ấy còn thiếu ở đâu.
Thói quen nhỏ mình tin nhất là đọc acceptance criteria thành tiếng trước khi team commit làm việc. Không cần nghi thức. Chỉ cần đủ chậm để ai đó nói: rule này chưa rõ, edge case này còn thiếu, phần này nên tách ticket, hoặc ví dụ này không giống cách user hành xử. Cuộc trò chuyện đó nhiều khi mới là giá trị thật. Criteria viết ra là artifact còn lại sau khi team đã align cách hiểu.
Acceptance criteria không làm delivery trở nên hoàn hảo. Nó làm misunderstanding dễ bị phát hiện hơn khi mọi thứ vẫn còn yên. Lần tới khi một ticket có vẻ ready, hãy thử hỏi bằng chứng nào sẽ khiến team thoải mái gọi nó là done. Câu trả lời không cần dài. Nó cần đủ rõ để nhiều người nhìn vào cùng một behavior và nhận ra cùng một lời hứa.