Mở đầu — vì sao bài này quan trọng
Nếu bạn hỏi mười BA đi làm rằng "công việc hằng ngày của em chủ yếu là gì", thì có tới bảy, tám người sẽ trả lời: viết requirement dưới dạng user story và acceptance criteria. Đây không phải là một kỹ năng "học cho biết" — nó là đơn vị công việc cơ bản mà đội phát triển (dev, tester, designer) đọc mỗi ngày để biết phải làm gì. Một user story viết tốt giúp cả team hiểu đúng, làm đúng, và test đúng. Một user story viết ẩu sẽ tạo ra hàng chục cuộc họp giải thích, hàng chục bug "do hiểu nhầm", và cuối cùng là một sản phẩm lệch so với mong đợi của khách hàng.
Với một fresher BA, đây cũng chính là thứ mà nhà tuyển dụng kiểm tra đầu tiên khi họ đưa cho bạn một bài test hoặc yêu cầu bạn kể về portfolio. Họ không hỏi bạn "Agile là gì" — họ đưa cho bạn một tình huống và nói: "Hãy viết vài user story cho tính năng này". Nếu bạn viết được story rõ ràng, kèm acceptance criteria chặt chẽ, bạn đã vượt qua 60% ứng viên fresher khác.
Trong bài này, tôi sẽ không dừng ở công thức "As a... I want... So that...". Tôi sẽ đi sâu vào cách viết một story thật sự dùng được, cách viết acceptance criteria theo hai trường phái phổ biến (checklist và Given-When-Then), và cách áp dụng bộ tiêu chí INVEST để tự chấm điểm story của mình. Xong bài này, bạn sẽ có một khung viết có thể mang thẳng vào ngày đầu tiên đi làm.
Khái niệm cốt lõi
User story là gì — và không phải là gì
User story là một mô tả ngắn gọn về một nhu cầu của người dùng, viết từ góc nhìn của chính người dùng đó. Điểm mấu chốt cần nhớ: user story không phải là tài liệu đặc tả đầy đủ. Nó là một "lời hứa về một cuộc trò chuyện" (a promise for a conversation). Nó ngắn gọn cố ý, để buộc team phải trao đổi thêm, thay vì đọc một bản đặc tả 20 trang rồi tự hiểu theo cách riêng.
Công thức chuẩn được dùng rộng rãi nhất là mẫu của Mike Cohn (Connextra template):
> As a [vai trò / loại người dùng] > I want to [hành động / tính năng mong muốn] > So that [giá trị / lợi ích đạt được]
Ba thành phần này trả lời ba câu hỏi: Ai cần (role), họ muốn làm gì (want), và để làm gì / vì sao (benefit). Phần "So that" là phần fresher hay bỏ qua nhất, nhưng lại quan trọng nhất — nó cho team hiểu giá trị của tính năng, từ đó biết ưu tiên và biết đề xuất giải pháp tốt hơn nếu cần.
Ví dụ tốt:
> As a khách hàng đã đăng nhập, > I want to lưu thẻ tín dụng của tôi vào tài khoản, > So that tôi không phải nhập lại thông tin thẻ ở những lần mua sau.
Ví dụ chưa tốt:
> As a user, I want to có tính năng thanh toán, so that tôi có thể thanh toán.
Cái sau sai ở đâu? "User" quá chung chung (không rõ là khách vãng lai hay đã đăng nhập). "Có tính năng thanh toán" quá to (đây là cả một epic, không phải một story). Và "so that tôi có thể thanh toán" là câu vô nghĩa vì nó chỉ lặp lại chính nó, không nêu được giá trị thật.
Acceptance criteria là gì
Nếu user story trả lời "cần cái gì và vì sao", thì acceptance criteria (AC — tiêu chí chấp nhận) trả lời "khi nào thì coi là làm xong và đúng". Đây là tập hợp các điều kiện cụ thể, có thể kiểm chứng được, mà tính năng phải thỏa mãn thì team mới được đánh dấu story là "Done".
AC phục vụ ba đối tượng cùng lúc:
- Dev: biết chính xác biên của tính năng, tránh làm thiếu hoặc làm dư.
- Tester: dựa vào AC để viết test case và UAT (test chấp nhận).
- BA và PO: có căn cứ để nghiệm thu, không cãi nhau kiểu cảm tính.
Cách 1 — Dạng danh sách (rule-based / checklist). Liệt kê các điều kiện dưới dạng gạch đầu dòng. Phù hợp cho các quy tắc nghiệp vụ, giới hạn dữ liệu, ràng buộc.
Ví dụ cho story "lưu thẻ tín dụng":
- Chỉ khách hàng đã đăng nhập mới thấy nút "Lưu thẻ".
- Số thẻ được mã hóa và không hiển thị đầy đủ; chỉ hiện 4 số cuối.
- Mỗi tài khoản lưu tối đa 5 thẻ.
- Nếu thẻ đã hết hạn, hệ thống hiển thị cảnh báo màu đỏ và không cho dùng để thanh toán.
> Given khách hàng đã đăng nhập và đang ở trang thanh toán, > When khách nhập thông tin thẻ hợp lệ và tích chọn "Lưu thẻ này", > Then hệ thống lưu thẻ vào tài khoản và hiển thị thông báo "Đã lưu thẻ thành công".
Given-When-Then đặc biệt mạnh vì nó gần như dịch thẳng thành test case được. Một mẹo nhỏ: mỗi story nên có ít nhất một kịch bản "happy path" (thành công) và một, hai kịch bản "unhappy path" (lỗi, ngoại lệ) — ví dụ thẻ không hợp lệ, mạng lỗi, vượt quá 5 thẻ.
INVEST — bộ tiêu chí tự chấm story
Bill Wake đề xuất bộ tiêu chí INVEST để kiểm tra chất lượng một user story. Đây là công cụ tự kiểm mà tôi khuyên bạn dán lên màn hình trong 3 tháng đầu:
- I – Independent (Độc lập): story không phụ thuộc chặt vào story khác, có thể làm riêng.
- N – Negotiable (Có thể thương lượng): là gợi ý, không phải hợp đồng cứng; chi tiết được bàn thêm.
- V – Valuable (Có giá trị): mang lại lợi ích rõ cho người dùng hoặc doanh nghiệp — chính là phần "So that".
- E – Estimable (Ước lượng được): team đủ hiểu để ước lượng công sức.
- S – Small (Đủ nhỏ): làm gọn trong một sprint, lý tưởng là vài ngày.
- T – Testable (Kiểm thử được): có AC rõ ràng để verify.
Tình huống thực tế
Tình huống 1 — Tiki và bài học về "So that"
Giả định bạn là BA fresher tại một sàn thương mại điện tử như Tiki. PO giao cho bạn một dòng yêu cầu từ team marketing: "Cho phép khách theo dõi sản phẩm". Bạn viết ngay:
> As a khách hàng, I want to theo dõi sản phẩm, so that tôi theo dõi được sản phẩm.
Trong buổi refinement, một bạn dev hỏi: "Theo dõi để làm gì? Để nhận thông báo khi nào?". Cả phòng im lặng vì không ai biết. Hóa ra ý định thật của marketing là: khách muốn được báo khi sản phẩm giảm giá hoặc có hàng trở lại. Sau khi làm rõ, story được viết lại:
> As a khách hàng đang quan tâm một sản phẩm hết hàng, > I want to bấm "Theo dõi sản phẩm này", > So that tôi nhận được thông báo ngay khi sản phẩm có hàng trở lại hoặc giảm giá.
Chỉ vì phần "So that" được viết đúng, phạm vi tính năng thay đổi hoàn toàn: giờ cần cơ chế thông báo (push/email), cần điều kiện kích hoạt (có hàng lại, đổi giá). Bài học: phần "So that" không phải trang trí — nó định hình phạm vi. Đừng bao giờ viết "so that" kiểu lặp lại vế "I want".
Tình huống 2 — MoMo và giá trị của Given-When-Then
Giả định bạn làm BA cho ví điện tử MoMo, tính năng "chuyển tiền tới số điện thoại". BA cũ chỉ viết một dòng AC: "Người dùng chuyển được tiền". Kết quả sprint đó có 9 bug được báo, phần lớn là "không rõ hành vi mong đợi": chuyển cho số chưa có tài khoản MoMo thì sao? Chuyển vượt số dư thì sao? Nhập sai OTP ba lần thì sao?
Ở sprint sau, bạn viết AC theo Given-When-Then và bao phủ cả unhappy path:
> Kịch bản 1 (happy path): Given người dùng có số dư 500.000đ và người nhận đã có tài khoản MoMo, When người dùng chuyển 200.000đ và nhập đúng OTP, Then hệ thống trừ 200.000đ, cộng cho người nhận và hiển thị biên lai thành công. > > Kịch bản 2: Given người nhận chưa có tài khoản MoMo, When người dùng bấm chuyển, Then hệ thống hiển thị "Số này chưa có ví MoMo. Gửi lời mời?" và không trừ tiền. > > Kịch bản 3: Given số tiền chuyển lớn hơn số dư, When người dùng bấm chuyển, Then hệ thống chặn giao dịch và hiển thị "Số dư không đủ". > > Kịch bản 4: Given người dùng nhập sai OTP 3 lần, When nhập sai lần thứ 3, Then hệ thống khóa giao dịch trong 15 phút và gửi cảnh báo bảo mật.
Số bug ở sprint này giảm còn 1. Bài học: phần lớn bug "do hiểu nhầm" thực chất là do AC thiếu kịch bản ngoại lệ. Given-When-Then buộc bạn nghĩ tới các trường hợp mà happy path che giấu.
Tình huống 3 — Chẻ nhỏ một epic tại một startup logistics
Giả định startup giao hàng Giao Hàng Nhanh muốn "tài xế quản lý đơn hàng trong ngày". Đây rõ ràng là một epic — quá to cho một story. Một fresher hay mắc lỗi nhét tất cả vào một story khổng lồ. Cách làm đúng là chẻ theo hành trình người dùng:
- Story A: As a tài xế, I want to xem danh sách đơn được giao hôm nay, so that tôi biết lộ trình cần đi.
- Story B: As a tài xế, I want to đánh dấu một đơn là "đã giao thành công", so that hệ thống cập nhật trạng thái cho khách.
- Story C: As a tài xế, I want to báo "giao thất bại" kèm lý do, so that tổng đài xử lý và sắp lịch giao lại.
- Story D: As a tài xế, I want to xem tổng thu hộ (COD) cuối ngày, so that tôi đối soát tiền với công ty.
Hướng dẫn từng bước
Đây là quy trình sáu bước bạn có thể áp dụng mỗi khi cần viết một user story kèm AC:
Bước 1 — Xác định đúng vai trò (role). Đừng dùng "user" chung chung. Hỏi: ai thật sự thực hiện hành động này? Khách vãng lai hay khách đã đăng nhập? Admin hay nhân viên vận hành? Vai trò càng cụ thể, story càng rõ. Nếu dự án đã có persona (bài 39 sẽ nói kỹ hơn), hãy dùng đúng tên persona đó.
Bước 2 — Viết vế "I want" ở mức một hành động. Một story = một hành động người dùng làm được. Nếu bạn thấy chữ "và" nối hai hành động khác nhau (ví dụ "lưu thẻ và quản lý danh sách thẻ"), tách thành hai story.
Bước 3 — Viết vế "So that" nêu giá trị thật. Tự hỏi: nếu bỏ tính năng này đi, người dùng mất gì? Câu trả lời chính là "So that". Nếu bạn chỉ viết được câu lặp lại vế "I want", nghĩa là bạn chưa hiểu giá trị — quay lại hỏi stakeholder.
Bước 4 — Viết acceptance criteria. Chọn dạng phù hợp: checklist cho quy tắc/ràng buộc, Given-When-Then cho luồng tương tác. Luôn có tối thiểu một happy path và một, hai unhappy path. Bao phủ: dữ liệu hợp lệ, dữ liệu không hợp lệ, giới hạn (min/max), phân quyền, và thông báo lỗi.
Bước 5 — Kiểm tra bằng INVEST. Chạy story qua sáu chữ. Đặc biệt soi hai chữ Small và Testable — hai lỗi phổ biến nhất của fresher.
Bước 6 — Đưa ra refinement để "3 amigos" review. Ba vai trò BA + Dev + Tester (three amigos) cùng đọc story. Dev soi tính khả thi, tester soi tính test được. Đây là lúc "cuộc trò chuyện" mà story hứa hẹn thật sự diễn ra. Sửa story theo phản hồi trước khi đưa vào sprint.
Lỗi thường gặp & mẹo
Lỗi 1 — Nhồi giải pháp kỹ thuật vào story. Fresher hay viết "As a user, I want hệ thống dùng Redis cache để load nhanh". Story mô tả nhu cầu, không mô tả cách làm. Hãy viết "so that trang tải trong dưới 2 giây" — còn dùng Redis hay gì là việc của dev.
Lỗi 2 — AC mơ hồ, không đo được. "Trang phải load nhanh" là AC tồi. "Trang load trong ≤ 2 giây với kết nối 4G" mới đo được. Mọi tiêu chí đều phải trả lời được câu hỏi "làm sao tester chứng minh điều này đúng/sai?".
Lỗi 3 — Quên unhappy path. Đây là nguồn bug lớn nhất. Với mỗi story, luôn hỏi: điều gì xảy ra khi dữ liệu sai, khi vượt giới hạn, khi không có quyền, khi mất mạng?
Lỗi 4 — Story quá to (thực ra là epic). Nếu không ước lượng được, hoặc không làm xong trong một sprint, hãy chẻ nhỏ theo hành động người dùng.
Lỗi 5 — Lẫn lộn AC với test case. AC là điều kiện chấp nhận ở mức nghiệp vụ; test case là các bước kiểm thử chi tiết. AC ít hơn và ở mức cao hơn. Đừng viết AC dài như một kịch bản test 30 bước.
Mẹo vàng: viết AC trước hoặc song song với việc chốt story, đừng để tới lúc dev sắp code mới viết. AC viết sớm giúp phát hiện lỗ hổng yêu cầu từ khi còn rẻ để sửa.
Mẹo về ngôn ngữ: trong công ty Việt Nam làm cho khách nước ngoài, story thường viết tiếng Anh. Hãy quen với mẫu tiếng Anh, nhưng khi làm việc nội bộ với team Việt, viết tiếng Việt rõ ràng vẫn tốt hơn tiếng Anh nửa vời.
Bài tập thực hành
Bài 1 — Sửa story hỏng. Cho story sau, hãy chỉ ra ít nhất ba điểm sai và viết lại: "As a user, I want tính năng đăng nhập và quên mật khẩu, so that tôi đăng nhập được."
Bài 2 — Viết đầy đủ. Chọn một tính năng bạn quen thuộc (ví dụ: "đặt lại mật khẩu qua email" trên một app học tiếng Anh). Viết một user story theo mẫu chuẩn, kèm 4–6 acceptance criteria trong đó có ít nhất hai unhappy path. Viết một AC dưới dạng Given-When-Then.
Bài 3 — Chẻ epic. Cho epic: "Sinh viên quản lý hồ sơ đăng ký học phần trên cổng thông tin trường". Chẻ thành tối thiểu bốn user story độc lập, mỗi story kèm một câu "So that" nêu giá trị.
Bài 4 — Tự chấm INVEST. Lấy ba story bạn vừa viết ở Bài 3, chấm từng story theo sáu tiêu chí INVEST. Story nào chưa đạt chữ nào, ghi rõ lý do và cách khắc phục. Lưu kết quả này vào portfolio của bạn — đây là bằng chứng tuyệt vời cho nhà tuyển dụng thấy bạn biết tư duy chất lượng requirement.
Tóm tắt
User story và acceptance criteria là đơn vị công việc bạn sẽ chạm vào mỗi ngày với tư cách BA. Một story tốt trả lời ba câu hỏi qua mẫu "As a [role] / I want [action] / So that [value]", trong đó phần "So that" định hình cả phạm vi tính năng — đừng bao giờ viết cho có. Acceptance criteria biến story mơ hồ thành thứ đo được và nghiệm thu được, viết theo dạng checklist cho quy tắc hoặc Given-When-Then cho luồng tương tác, và luôn phải bao phủ cả trường hợp lỗi chứ không chỉ happy path. Cuối cùng, bộ tiêu chí INVEST là tấm gương để bạn tự soi chất lượng: độc lập, thương lượng được, có giá trị, ước lượng được, đủ nhỏ, và kiểm thử được.
Khi mới vào nghề, bạn không cần viết story hoàn hảo ngay — bạn cần viết story đủ rõ để khởi động một cuộc trò chuyện đúng hướng với dev và tester. Hãy luyện sáu bước trong bài này trên những tính năng đời thường bạn dùng hằng ngày, tự chấm bằng INVEST, và lưu lại thành mẫu. Chỉ sau vài chục story, bạn sẽ thấy tay mình nhanh và chắc hơn hẳn — và đó chính là kỹ năng phân biệt một fresher đáng tuyển với phần còn lại.