Mở đầu — vì sao bài này quan trọng
Hãy hình dung một buổi sáng thứ Hai ở văn phòng. Bạn — với tư cách PM — giao cho team một dòng yêu cầu: "Làm cho user đăng nhập bằng Google đi." Ba ngày sau, kỹ sư demo: nút "Đăng nhập với Google" hiện ra, bấm vào thì chuyển hướng sang Google, rồi… quay về trang chủ trống trơn. Không có thông báo lỗi khi user từ chối cấp quyền. Không rõ chuyện gì xảy ra nếu email Google trùng với tài khoản đã đăng ký bằng số điện thoại. Bạn thở dài: "Ý anh không phải vậy." Kỹ sư cũng thở dài: "Anh có nói đâu."
Vấn đề không nằm ở năng lực của ai cả. Vấn đề nằm ở chỗ yêu cầu được phát biểu mơ hồ, không nói rõ ai cần điều này, để làm gì, và thế nào thì gọi là làm xong. Đây chính là khoảng trống mà hai công cụ trong bài học hôm nay sinh ra để lấp đầy: user story (câu chuyện người dùng) và acceptance criteria (tiêu chí nghiệm thu).
User story giúp bạn diễn đạt yêu cầu dưới góc nhìn của người dùng, giữ cho cả team luôn nhớ "chúng ta đang giải quyết vấn đề cho ai". Acceptance criteria thì biến mong muốn mơ hồ thành những điều kiện cụ thể, có thể kiểm chứng được — ranh giới rõ ràng giữa "xong" và "chưa xong". Đây là hai kỹ năng viết nền tảng nhất mà một PM phải thành thạo, vì gần như mọi tính năng bạn đặc tả sau này đều được tạo thành từ các viên gạch user story và AC. Viết tốt hai thứ này, bạn tiết kiệm hàng chục giờ tranh cãi và rework. Viết ẩu, bạn trả giá bằng những buổi sáng thứ Hai như trên.
Khái niệm cốt lõi
User story — câu chuyện của người dùng
User story là một câu mô tả ngắn gọn một nhu cầu của người dùng, viết theo công thức kinh điển:
> As a [loại người dùng], I want [mong muốn], so that [lợi ích/lý do].
Dịch sang tiếng Việt: Là một [ai], tôi muốn [làm gì], để [đạt được điều gì].
Ba thành phần này không phải trang trí. Mỗi phần trả lời một câu hỏi sống còn:
- As a xác định persona — ai là người thực sự cần tính năng này? Một khách mới ghé thăm khác hoàn toàn một khách hàng thân thiết; một quản trị viên khác một người dùng cuối. Khi viết rõ "As a", bạn buộc mình phải nghĩ về con người cụ thể chứ không phải "user" chung chung.
- I want mô tả hành động hoặc khả năng mà người dùng mong có. Lưu ý: phần này nói về điều người dùng muốn, không phải giải pháp kỹ thuật bạn nghĩ ra. "Tôi muốn lưu giỏ hàng để quay lại mua sau" chứ không phải "tôi muốn một bảng cart_items trong database".
- So that là phần quan trọng nhất nhưng hay bị bỏ qua. Nó nói lên lý do, giá trị. Nếu bạn không viết nổi phần "so that" cho ra hồn, rất có thể tính năng đó không đáng làm. Phần này còn giúp kỹ sư và designer hiểu ý đồ để đề xuất giải pháp tốt hơn cả những gì bạn nghĩ ban đầu.
Một mẹo kiểm tra chất lượng user story là tiêu chí INVEST: Independent (độc lập), Negotiable (có thể thương lượng), Valuable (có giá trị), Estimable (ước lượng được công sức), Small (đủ nhỏ để làm trong một sprint), Testable (kiểm chứng được). Nếu một story quá to — "Là một user, tôi muốn một app ngân hàng hoàn chỉnh" — hãy chẻ nhỏ nó ra.
Acceptance criteria — tiêu chí nghiệm thu
Nếu user story là cái gì và tại sao, thì acceptance criteria (AC) là làm sao biết đã xong đúng. AC là tập hợp các điều kiện mà tính năng phải thỏa mãn thì mới được coi là hoàn thành. Chúng là "định nghĩa của xong" (definition of done) ở cấp độ tính năng.
AC tốt có ba đặc điểm: cụ thể (không để chỗ cho diễn giải), có thể kiểm chứng (test được, trả lời được đúng/sai), và viết từ góc nhìn hành vi (cái user thấy, không phải cách code chạy).
Có hai phong cách viết AC phổ biến:
Phong cách danh sách (checklist) — liệt kê các điều kiện dạng gạch đầu dòng:
- Khi user nhập sai mật khẩu, hệ thống hiển thị thông báo "Email hoặc mật khẩu không đúng".
- Sau 5 lần sai liên tiếp, tài khoản bị khóa 15 phút.
- Nút "Đăng nhập" bị vô hiệu hóa cho đến khi cả hai ô được điền.
> Given [bối cảnh ban đầu] > When [hành động xảy ra] > Then [kết quả mong đợi]
Dịch: Cho rằng [tình huống], Khi [sự kiện], Thì [kết quả]. Có thể thêm And (Và) để nối nhiều điều kiện hoặc kết quả.
Ví dụ:
> Given tôi là user đã đăng nhập và đang ở trang giỏ hàng có 2 sản phẩm > When tôi bấm "Xóa" trên sản phẩm thứ nhất > Then sản phẩm đó biến mất khỏi giỏ > And tổng tiền được cập nhật lại > And giỏ hàng còn lại 1 sản phẩm
Vẻ đẹp của Gherkin là nó tách bạch rõ ràng trạng thái đầu vào (Given), tác nhân (When), và kết quả kiểm chứng được (Then). Cấu trúc này dễ đọc cho cả người không kỹ thuật, đồng thời chuyển thẳng thành test case tự động được. Nó đặc biệt mạnh khi mô tả luồng có điều kiện phức tạp, vì mỗi nhánh là một kịch bản Given/When/Then riêng.
Quan hệ giữa hai khái niệm
Một user story thường đi kèm nhiều acceptance criteria. Story đặt ra mục tiêu; AC định nghĩa biên giới của mục tiêu đó. Hãy nghĩ thế này: story là "tôi muốn đi từ Hà Nội vào Sài Gòn", còn AC là "phải đến trước 6h chiều, ngân sách dưới 2 triệu, không quá cảnh quá một lần". Story cho hướng, AC cho ràng buộc kiểm chứng được.
Tình huống thực tế
Ví dụ 1 — Tính năng "Đặt lại đơn hàng" của một app giao đồ ăn
Giả sử bạn là PM tại một startup giao đồ ăn ở TP.HCM, gọi là FoodNow. Data cho thấy 38% đơn hàng là khách đặt lại đúng món họ từng ăn, nhưng họ phải mò lại nhà hàng và chọn từng món — trung bình mất 90 giây. Bạn muốn rút ngắn quá trình này.
User story:
> Là một khách hàng quen của FoodNow, tôi muốn đặt lại nguyên đơn hàng cũ chỉ bằng một chạm, để tiết kiệm thời gian khi tôi đã biết chính xác mình muốn ăn gì.
Acceptance criteria (Gherkin):
> Given tôi có ít nhất một đơn hàng đã hoàn thành trong 30 ngày qua > When tôi mở tab "Lịch sử" và bấm "Đặt lại" > Then toàn bộ món của đơn cũ được thêm vào giỏ với đúng số lượng và tùy chọn (size, topping)
> Given một món trong đơn cũ hiện đã hết hàng hoặc bị gỡ khỏi menu > When tôi bấm "Đặt lại" > Then các món còn lại vẫn được thêm vào giỏ > And hệ thống hiển thị banner "1 món không còn khả dụng và đã được bỏ qua"
Bài học rút ra: Kịch bản thứ hai chính là thứ phân biệt một PM non tay với một PM có kinh nghiệm. Người mới chỉ viết "happy path" — đặt lại thành công. Người có nghề luôn hỏi: "Điều gì xảy ra khi mọi thứ không hoàn hảo?" Việc nhà hàng đổi menu là chuyện cơm bữa, và nếu không đặc tả, kỹ sư có thể làm app crash hoặc đặt một giỏ hàng trống mà không nói lý do. Con số 38% còn cho thấy "so that" của bạn có cơ sở dữ liệu vững, không phải tính năng làm theo cảm tính.
Ví dụ 2 — Khi đặc tả quá chi tiết phản tác dụng (một fintech ở Singapore)
Một PM tại công ty ví điện tử ở Singapore viết user story cho tính năng chuyển tiền cho bạn bè. Lo lắng kỹ sư hiểu sai, anh viết AC dài 4 trang, đặc tả cả màu nút (mã hex #2D7FF9), độ bo góc 8px, font-size 14px, animation chuyển trang 300ms ease-in-out.
Kết quả: designer bực mình vì bị giẫm chân — những quyết định màu sắc, animation lẽ ra là việc của họ và đã có trong design system. Kỹ sư thì sa lầy vào tiểu tiết hình thức mà bỏ qua câu hỏi nghiệp vụ quan trọng: chuyện gì xảy ra nếu người nhận chưa có tài khoản ví? Nếu số tiền vượt hạn mức KYC? Nếu giao dịch bị treo giữa chừng? Những thứ thực sự cần đặc tả thì lại không có trong 4 trang đó.
Bài học rút ra: AC nên tập trung vào hành vi và quy tắc nghiệp vụ, không phải chi tiết trình bày vốn thuộc về thiết kế. Quy tắc ngón tay cái: nếu một AC trả lời cho câu hỏi "hệ thống phải hành xử thế nào trong tình huống X", nó đáng viết. Nếu nó chỉ mô tả "nút trông ra sao", hãy để designer lo, hoặc tham chiếu đến design system. Chi tiết đúng chỗ là vàng; chi tiết sai chỗ là rác làm loãng tài liệu.
Ví dụ 3 — Story to cần chẻ nhỏ (sàn TMĐT giả định Chợ Việt)
PM của sàn thương mại điện tử Chợ Việt nhận yêu cầu: "Làm tính năng đánh giá người bán." Anh định viết một user story khổng lồ bao trùm tất cả. Nhưng story đó vi phạm chữ S (Small) và T (Testable) trong INVEST — nó quá lớn để ước lượng và kiểm chứng.
Anh chẻ thành các story nhỏ:
> Story A: Là người mua đã nhận hàng, tôi muốn chấm sao (1–5) cho người bán, để chia sẻ trải nghiệm với người mua khác. > Story B: Là người mua, tôi muốn viết kèm nhận xét bằng chữ và đính kèm tối đa 3 ảnh, để minh họa cụ thể. > Story C: Là người bán, tôi muốn phản hồi công khai một đánh giá, để giải thích từ phía mình.
Mỗi story giờ có thể làm và nghiệm thu độc lập, ship dần trong vài sprint thay vì chờ một khối lớn.
Bài học rút ra: Khi một story "to đùng", hãy chẻ theo giá trị độc lập — mỗi mảnh phải tự nó mang lại lợi ích và kiểm chứng được riêng. Chấm sao đã hữu ích ngay cả khi chưa có phần nhận xét chữ. Chẻ nhỏ giúp ship nhanh, học sớm, và giảm rủi ro làm cả tháng mới phát hiện đi sai hướng.
Hướng dẫn từng bước
Đây là quy trình bạn có thể áp dụng mỗi khi cần viết user story và AC cho một tính năng:
Bước 1 — Xác định persona thật. Đừng viết "As a user". Hỏi: ai cụ thể? Khách mới hay khách quen? Người mua hay người bán? Admin hay end-user? Persona rõ giúp bạn nghĩ đúng nhu cầu. Nếu một tính năng phục vụ nhiều persona, viết story riêng cho từng nhóm.
Bước 2 — Viết phần "so that" trước. Nghe ngược đời, nhưng bắt đầu từ lý do giúp bạn kiểm tra tính năng có đáng làm không. Nếu "so that" yếu ớt hoặc bạn phải bịa ra, hãy dừng lại suy nghĩ.
Bước 3 — Hoàn thiện câu story theo công thức As a / I want / So that. Giữ nó ngắn, một câu, tập trung vào nhu cầu chứ không phải giải pháp kỹ thuật.
Bước 4 — Liệt kê các kịch bản happy path. Viết AC cho luồng chính khi mọi thứ diễn ra suôn sẻ. Dùng Given/When/Then nếu luồng có điều kiện, hoặc checklist nếu là các quy tắc rời rạc.
Bước 5 — Săn lùng các kịch bản không hoàn hảo. Tự hỏi: dữ liệu rỗng thì sao? Mạng chậm thì sao? User nhập sai thì sao? Quyền hạn không đủ thì sao? Mỗi câu trả lời là một AC mới. (Bài về edge cases và error states sẽ đào sâu phần này; ở đây chỉ cần nhớ phải nghĩ tới chúng.)
Bước 6 — Quyết định mức độ chi tiết. Đây là phán đoán quan trọng. Hãy chi tiết khi: tính năng động đến tiền/bảo mật/dữ liệu, có quy tắc nghiệp vụ phức tạp, hoặc team chưa quen domain. Hãy viết khái quát hơn khi: luồng đơn giản, team giàu kinh nghiệm, hoặc giải pháp còn cần khám phá thêm — viết quá chặt sẽ giết sáng tạo của kỹ sư và designer.
Bước 7 — Kiểm tra bằng INVEST. Soi lại story: nó có độc lập, có giá trị, đủ nhỏ, kiểm chứng được không? Nếu không, chẻ nhỏ hoặc viết lại.
Bước 8 — Đọc to với một kỹ sư. Trước khi chốt, đọc story và AC cho một kỹ sư nghe và hỏi: "Anh đọc cái này có hình dung ra phải làm gì không, có chỗ nào mơ hồ không?" Năm phút này tiết kiệm nhiều ngày rework.
Lỗi thường gặp & mẹo
Lỗi 1 — Viết "As a user, I want…" cho mọi thứ. "User" là không-ai-cả. Mất luôn giá trị của phần As a. Mẹo: luôn ép mình ghi một persona cụ thể, kể cả khi cảm thấy hiển nhiên.
Lỗi 2 — Bỏ qua hoặc viết "so that" giả tạo. Kiểu "so that I can use the feature" — vô nghĩa. Nếu không tìm ra lý do thật, đó là tín hiệu đỏ về độ ưu tiên. Mẹo: phần "để" phải nói về lợi ích cho người dùng hoặc business, không phải mô tả lại tính năng.
Lỗi 3 — Nhét giải pháp kỹ thuật vào story. "Tôi muốn một dropdown để chọn ngày" đã đóng khung giải pháp; biết đâu một date-picker hay nhập tay còn tốt hơn. Mẹo: phần "I want" mô tả nhu cầu, để team đề xuất cách làm.
Lỗi 4 — AC chỉ có happy path. Đây là lỗi phổ biến và đắt giá nhất. Mẹo: với mỗi happy path, ép mình viết ít nhất một kịch bản "khi mọi thứ không như ý".
Lỗi 5 — AC không kiểm chứng được. "Trang phải tải nhanh" — nhanh là bao nhiêu? Mẹo: thay bằng con số. "Trang hiển thị nội dung chính trong vòng 2 giây trên mạng 4G." Một AC tốt phải trả lời được dứt khoát đúng/sai.
Lỗi 6 — Lẫn lộn AC hành vi với chi tiết thiết kế. Như ví dụ fintech Singapore. Mẹo: tự hỏi "đây là quy tắc hành xử của hệ thống, hay chỉ là hình thức?" Hình thức để design system và designer lo.
Mẹo vàng: Một bộ AC tốt chính là bộ test case sẵn sàng cho QA. Nếu viết AC mà QA có thể cầm đi kiểm thử ngay không cần hỏi lại, bạn đã viết đạt chuẩn.
Bài tập thực hành
Chọn một tính năng quen thuộc — ví dụ "Quên mật khẩu" trên một app bạn hay dùng — và làm các bài sau:
Bài 1 — Viết user story. Dùng đúng công thức As a / I want / So that. Đặc biệt đầu tư cho phần "so that": lý do thật là gì? Viết thử 2 phiên bản "so that" khác nhau và chọn cái mạnh hơn.
Bài 2 — Viết AC theo Gherkin. Viết ít nhất 4 kịch bản Given/When/Then, trong đó:
- 1 kịch bản happy path (đặt lại mật khẩu thành công).
- 3 kịch bản "không hoàn hảo": email không tồn tại trong hệ thống; link đặt lại đã hết hạn; user bấm link đặt lại hai lần.
Bài 4 — Bài tập độ chi tiết. Viết lại một AC ở hai mức: một bản quá chi tiết (lẫn cả màu nút, font), một bản đủ chi tiết (chỉ hành vi). So sánh và tự rút ra ranh giới của riêng bạn về "đủ chi tiết".
Hãy lưu lại bài làm — bạn sẽ tái sử dụng kỹ năng này trong gần như mọi bài đặc tả về sau.
Tóm tắt
- User story diễn đạt yêu cầu từ góc nhìn người dùng theo công thức As a / I want / So that — ai, muốn gì, để làm gì. Phần "so that" quan trọng nhất vì nó nói lên giá trị; viết yếu là tín hiệu tính năng không đáng làm.
- Acceptance criteria biến mong muốn mơ hồ thành điều kiện cụ thể, kiểm chứng được — ranh giới giữa "xong" và "chưa xong". Hai phong cách phổ biến là checklist và Gherkin (Given/When/Then).
- Gherkin mạnh khi mô tả luồng có điều kiện và chuyển thẳng thành test case; checklist gọn cho các quy tắc rời rạc.
- Luôn viết AC cho cả kịch bản không hoàn hảo, không chỉ happy path — đây là lỗi đắt giá nhất khi bỏ sót.
- Cân nhắc độ chi tiết theo bối cảnh: chi tiết với tính năng động đến tiền/bảo mật/nghiệp vụ phức tạp; khái quát hơn với luồng đơn giản hoặc team giàu kinh nghiệm. Đừng lấn sân quyết định thiết kế.
- Dùng INVEST để kiểm tra chất lượng story và chẻ nhỏ khi cần.