Mở đầu — vì sao bài này quan trọng
Khi bạn còn làm QA/Tester, có một việc bạn làm mỗi ngày mà có thể chính bạn cũng không nhận ra: bạn tư duy theo "kịch bản". Mỗi test case là một kịch bản — người dùng làm gì, hệ thống phản ứng ra sao, kết quả mong đợi là gì. Bạn quen với việc đi từ bước 1, bước 2, bước 3 cho đến kết thúc, và bạn ám ảnh với câu hỏi "nếu bước này lỗi thì sao?".
Tin vui là: đó chính xác là bộ não của một người viết Use Case giỏi.
Use Case Modeling (mô hình hóa ca sử dụng) là một trong những kỹ thuật đặc tả yêu cầu lâu đời và mạnh mẽ nhất của nghề BA. Nó mô tả cách một tác nhân (actor) tương tác với hệ thống để đạt được một mục tiêu cụ thể, qua một chuỗi các bước có thứ tự. Nếu User Story (bạn sẽ học sâu ở Bài 18) là "ảnh chụp nhanh" một nhu cầu nhỏ, thì Use Case là "bộ phim" đầy đủ — có nhân vật, có cốt truyện chính, có những tình tiết rẽ nhánh khi mọi thứ không diễn ra như kế hoạch.
Với người từ QA chuyển sang, Use Case Modeling là "vùng đất quen thuộc" để bạn ghi điểm sớm. Bạn vốn đã giỏi nhìn ra các luồng thay thế (alternative flows) và luồng ngoại lệ (exception flows) — thứ mà nhiều BA "thuần" hay quên. Bài học này sẽ chỉ cho bạn cách chuyển cái bản năng test ấy thành một artifact BA chuyên nghiệp, đúng template, đủ độ chi tiết để dev và QA cùng đọc và hiểu giống nhau.
Khái niệm cốt lõi
Use Case là gì, và khác gì với một test case?
Một Use Case mô tả một mục tiêu hoàn chỉnh mà người dùng muốn đạt được khi tương tác với hệ thống. Ví dụ: "Khách hàng đặt đơn hàng", "Nhân viên kho xác nhận xuất kho", "Khách hàng hủy giao dịch chuyển tiền". Điểm mấu chốt: mỗi Use Case phải mang lại giá trị quan sát được cho một actor — nó kết thúc khi actor đạt (hoặc không đạt) được điều họ cần.
Sự khác biệt với test case nằm ở mục đích. Test case tồn tại để kiểm chứng rằng hệ thống đã làm đúng. Use Case tồn tại để mô tả hệ thống nên làm gì, trước khi nó được xây. Test case đi vào chi tiết dữ liệu cụ thể ("nhập email abc@test.com, mật khẩu 123456"). Use Case đi ở mức nghiệp vụ ("Khách hàng cung cấp thông tin đăng nhập"). Nhưng cấu trúc tư duy thì giống hệt: một luồng chính, nhiều luồng rẽ nhánh, và các điều kiện.
Các thành phần của một Use Case
- Actor (tác nhân): người hoặc hệ thống bên ngoài kích hoạt hoặc tham gia Use Case. Phân biệt primary actor (người khởi xướng, ví dụ Khách hàng) và supporting actor (hệ thống hỗ trợ, ví dụ Cổng thanh toán VNPay).
- Preconditions (điều kiện tiên quyết): trạng thái phải đúng trước khi Use Case bắt đầu. Ví dụ: "Khách hàng đã đăng nhập", "Giỏ hàng có ít nhất 1 sản phẩm".
- Postconditions (điều kiện kết thúc): trạng thái hệ thống sau khi Use Case thành công. Ví dụ: "Đơn hàng được tạo với trạng thái Chờ thanh toán", "Tồn kho được trừ tương ứng".
- Main flow (luồng chính / happy path): chuỗi bước khi mọi thứ diễn ra suôn sẻ.
- Alternative flows (luồng thay thế): các cách khác để đạt mục tiêu (ví dụ: thanh toán bằng ví thay vì thẻ).
- Exception flows (luồng ngoại lệ): khi có lỗi khiến mục tiêu không đạt được (ví dụ: thẻ bị từ chối, hết hàng giữa chừng).
- Business rules (quy tắc nghiệp vụ): các ràng buộc logic áp dụng (bạn sẽ học tách riêng ở Bài 23).
Template chuẩn của Use Case Specification
Đây là khung mà tôi khuyên bạn dùng cho mọi Use Case. Bạn có thể dán thẳng vào Confluence hay Word:
| Field | Mô tả |
|---|---|
| UC ID | Mã định danh, ví dụ UC-001 |
| Use Case Name | Tên động từ + danh từ, ví dụ "Customer Place Order" |
| Primary Actor | Khách hàng |
| Supporting Actors | Cổng thanh toán, Hệ thống quản lý kho |
| Description | 1–2 câu mô tả mục tiêu |
| Preconditions | Điều kiện cần thỏa trước khi bắt đầu |
| Trigger | Sự kiện kích hoạt Use Case |
| Main Flow | Các bước 1, 2, 3… của happy path |
| Alternative Flows | Các nhánh rẽ thay thế (A1, A2…) |
| Exception Flows | Các nhánh lỗi (E1, E2…) |
| Postconditions | Trạng thái sau khi thành công |
| Business Rules | BR-01, BR-02… liên quan |
Use Case Diagram và mối quan hệ include / extend
Bên cạnh phần đặc tả bằng chữ, Use Case còn có dạng sơ đồ (UML Use Case Diagram): các actor là hình người que ở ngoài, các Use Case là hình bầu dục bên trong ranh giới hệ thống, nối với nhau bằng đường thẳng.
Hai mối quan hệ bạn cần nắm:
<<include>>: một Use Case luôn dùng lại một Use Case con. Ví dụ "Đặt hàng" luôn<<include>>"Đăng nhập" — bắt buộc, lúc nào cũng xảy ra.<<extend>>: một Use Case con chỉ xảy ra trong một số điều kiện. Ví dụ "Đặt hàng" có thể<<extend>>"Áp dụng mã giảm giá" — chỉ khi khách hàng có voucher.
include như một bước "luôn chạy" trong mọi test run, còn extend như một nhánh điều kiện "chỉ chạy khi flag bật".Tình huống thực tế
Ví dụ 1 — Tiki và Use Case "Đặt hàng" trong giai đoạn làm tính năng mua trước trả sau
Giả định một đội sản phẩm tại một sàn thương mại điện tử lớn ở Việt Nam (lấy bối cảnh kiểu Tiki) cần bổ sung phương thức "Mua trước trả sau" vào luồng đặt hàng đang có. Chị Lan, một QA có 4 năm kinh nghiệm test luồng thanh toán, vừa chuyển sang BA và được giao viết Use Case Specification cho luồng đặt hàng mới.
Phần Main Flow chị viết khá nhanh: khách chọn sản phẩm → vào giỏ → chọn địa chỉ → chọn phương thức thanh toán → xác nhận → hệ thống tạo đơn. Nhưng điều khiến trưởng nhóm sản phẩm ấn tượng là phần Exception Flows. Vì từng test luồng thanh toán, chị Lan liệt kê ngay được những tình huống mà các BA khác bỏ sót:
- E1: Hạn mức "Mua trước trả sau" của khách không đủ cho giá trị đơn → hệ thống đề xuất thanh toán một phần bằng thẻ.
- E2: Sản phẩm hết hàng giữa lúc khách đang thanh toán → giữ chỗ đơn trong 10 phút hay hủy ngay?
- E3: Nhà cung cấp dịch vụ trả sau timeout → đơn ở trạng thái gì, ai chịu trách nhiệm?
Bài học: Sức mạnh khác biệt của BA xuất thân QA không nằm ở happy path — ai cũng viết được — mà ở độ phủ của các luồng ngoại lệ. Hãy biến điểm đó thành thương hiệu cá nhân của bạn.
Ví dụ 2 — Một ngân hàng số và lỗi viết Use Case quá to
Tại một ngân hàng số (giả định kiểu Timo hoặc Cake), anh Dũng — cựu tester core banking — được giao viết Use Case cho mảng chuyển tiền. Anh hào hứng viết một Use Case duy nhất tên "Quản lý giao dịch", nhồi vào đó cả chuyển tiền nội bộ, chuyển liên ngân hàng qua Napas, lên lịch chuyển định kỳ, và hủy lệnh. Kết quả: Main Flow dài 40 bước, không ai đọc nổi, và khi ước lượng thì đội dev không biết chia task thế nào.
BA lead góp ý tách thành nhiều Use Case riêng: "Chuyển tiền nội bộ" (UC-101), "Chuyển tiền liên ngân hàng" (UC-102), "Lên lịch chuyển tiền định kỳ" (UC-103), "Hủy lệnh chuyển tiền" (UC-104). Phần xác thực OTP — vốn lặp lại ở cả ba — được tách thành "Xác thực OTP" (UC-100) và dùng <<include>>.
Diễn giải: Mỗi Use Case nên ứng với một mục tiêu của một người dùng tại một thời điểm. "Quản lý" là một từ báo động — nó thường gói nhiều mục tiêu khác nhau. Sau khi tách, mỗi Use Case gọn còn 8–12 bước, đội dev ước lượng được, QA viết test case bám theo từng UC một cách 1-1.
Bài học: Đừng để bản năng "test cho hết một module" khiến bạn gộp mọi thứ. Use Case có ranh giới rõ ràng: một mục tiêu, một kết thúc.
Ví dụ 3 — Công ty outsource và bài toán "đồng bộ ngôn ngữ" với khách Nhật
Một công ty outsource ở TP.HCM (kiểu FPT Software hoặc một studio tầm trung) làm dự án cho khách hàng Nhật trong lĩnh vực logistics. Khách hàng yêu cầu đặc tả bằng Use Case vì đội dev offshore và đội QA ở hai múi giờ khác nhau, không thể họp trực tiếp nhiều. BA của dự án — bạn Mai, từng là QA automation — viết Use Case "Tài xế xác nhận giao hàng".
Điểm hay: vì Mai viết Postconditions và Business Rules rất rõ, đội QA ở Việt Nam đọc Use Case là dẫn xuất ra được bộ test case mà gần như không cần hỏi lại. Ví dụ Postcondition ghi "Trạng thái đơn chuyển sang Delivered, ảnh ký nhận được lưu, thông báo đẩy tới người gửi trong vòng 30 giây" — mỗi mệnh đề này lập tức thành một điểm kiểm thử.
Diễn giải: Trong mô hình outsource (chủ đề Bài 10 và 51), Use Case đóng vai trò "hợp đồng kỹ thuật" giữa các bên không ngồi cùng phòng. Người viết Use Case xuất thân QA có lợi thế: bạn biết một QA cần gì để viết test, nên bạn viết Postconditions có thể "đo được".
Bài học: Viết Postconditions theo cách có thể kiểm chứng được — đó là món quà bạn tặng cho đội QA, và là dấu ấn của một BA hiểu cả hai phía.
Hướng dẫn từng bước
Đây là quy trình tôi dùng để viết một Use Case Specification từ con số không:
- Xác định actor. Hỏi: "Ai là người cần đạt mục tiêu này?" Đó là primary actor. "Hệ thống nào hỗ trợ?" Đó là supporting actor. Với người từ QA, hãy nhìn lại các "vai" bạn từng đóng khi test (admin, khách vãng lai, khách VIP) — chúng thường chính là các actor.
- Đặt tên Use Case theo công thức Động từ + Danh từ. "Place Order", "Cancel Booking", "Approve Refund". Tránh danh từ chung chung như "Order Management". Tên tốt giúp bạn biết ngay Use Case kết thúc ở đâu.
- Viết Description và Trigger. Một hai câu mục tiêu, và sự kiện kích hoạt ("Khách bấm nút Thanh toán").
- Liệt kê Preconditions. Đặt câu hỏi: "Để bước 1 chạy được, hệ thống phải ở trạng thái nào?" Đây gần như chính là phần "Setup/Prerequisite" trong test case của bạn ngày xưa.
- Viết Main Flow (happy path). Đánh số từng bước, mỗi bước một câu, xen kẽ hành động của actor và phản ứng của hệ thống. Quy tắc: 5–12 bước là vừa. Nếu vượt 15 bước, hãy nghi ngờ Use Case đang quá to.
- Rút ra Alternative Flows. Tại mỗi bước của Main Flow, hỏi: "Có cách hợp lệ nào khác để làm bước này không?" Ví dụ ở bước thanh toán: ngoài thẻ, còn ví điện tử, còn COD.
- Rút ra Exception Flows. Đây là sân nhà của bạn. Tại mỗi bước, hỏi: "Nếu bước này thất bại thì sao? Hệ thống phản ứng thế nào, dữ liệu ở trạng thái gì?" Đừng để trống.
- Viết Postconditions có thể đo được. Mô tả trạng thái cuối ở mức cụ thể đủ để QA viết được assertion.
- Tách Business Rules ra một danh sách riêng (BR-01, BR-02…) và tham chiếu chúng trong các bước, thay vì nhồi logic vào giữa luồng. Việc này giúp khi quy tắc đổi (ví dụ ngưỡng miễn phí ship đổi từ 300k thành 500k) bạn chỉ sửa một chỗ.
- Vẽ Use Case Diagram nếu hệ thống có nhiều Use Case liên quan, dùng
<<include>>và<<extend>>để thể hiện phần dùng chung và phần điều kiện.
- Rà soát chéo: đọc lại như một QA — "tôi có viết được test case từ đặc tả này mà không cần hỏi thêm không?". Nếu chưa, đặc tả còn thiếu.
Lỗi thường gặp & mẹo
Lỗi 1 — Viết Use Case như test case chi tiết. Người mới chuyển hay nhồi dữ liệu cụ thể ("nhập 0901234567") vào Main Flow. Sai. Use Case mô tả ở mức nghiệp vụ ("Khách cung cấp số điện thoại"). Dữ liệu cụ thể thuộc về test case và acceptance criteria, không thuộc Use Case.
Lỗi 2 — Use Case quá to (như ví dụ ngân hàng). Một từ "Quản lý" trong tên là dấu hiệu cảnh báo. Mỗi Use Case = một mục tiêu, một kết thúc.
Lỗi 3 — Mô tả giao diện thay vì hành vi. Tránh viết "Khách bấm nút màu xanh ở góc phải". Hãy viết "Khách xác nhận đặt hàng". Use Case tồn tại lâu hơn thiết kế UI; đừng buộc nó vào màu nút.
Lỗi 4 — Bỏ trống Exception Flows. Trớ trêu là người từ QA đôi khi lại mắc lỗi này vì sợ "viết dài quá". Đừng. Đây chính là phần làm bạn khác biệt.
Lỗi 5 — Postconditions mơ hồ. "Đơn hàng được xử lý" là vô nghĩa. Hãy viết "Đơn hàng ở trạng thái Đã thanh toán, tồn kho bị trừ, email xác nhận đã gửi".
Mẹo vàng: Hãy giữ một quy ước đánh số nhánh nhất quán — Alternative đánh A1, A2 và ghi rõ "tại bước 3 của Main Flow"; Exception đánh E1, E2 tương tự. Khi dev hỏi "nhánh nào", bạn trả lời được trong một giây.
Mẹo về độ chi tiết: Quy tắc ngón tay cái — một bước Use Case nên là một câu mà actor hoặc hệ thống "làm một việc". Nếu một bước có chữ "và" nối hai hành động độc lập, cân nhắc tách đôi.
Bài tập thực hành
Hãy chọn một nghiệp vụ quen thuộc — ví dụ "Khách hàng đặt bàn tại một nhà hàng qua app" — và hoàn thành các việc sau:
- Điền đầy đủ template Use Case Specification (12 trường như bảng ở trên) cho Use Case "Customer Reserve Table" (UC-001). Đặt tên đúng công thức Động từ + Danh từ.
- Viết Main Flow từ 6 đến 10 bước, xen kẽ hành động khách và phản ứng hệ thống.
- Liệt kê ít nhất 2 Alternative Flows (ví dụ: đặt bàn cho nhóm lớn cần đặt cọc; chọn khung giờ khác khi khung giờ mong muốn đã đầy).
- Liệt kê ít nhất 3 Exception Flows — đây là phần tận dụng thế mạnh QA của bạn (ví dụ: nhà hàng đã kín chỗ; thanh toán cọc thất bại; mất kết nối khi đang xác nhận).
- Viết Postconditions có thể đo được — sao cho từ mỗi mệnh đề bạn rút ra được một điểm kiểm thử.
- Vẽ một Use Case Diagram nhỏ có ít nhất một quan hệ
<<include>>(gợi ý: "Đặt bàn" include "Đăng nhập") và một quan hệ<<extend>>(gợi ý: "Đặt bàn" extend "Đặt cọc giữ chỗ").
- Tự kiểm tra: đưa đặc tả cho một đồng nghiệp (hoặc tự đóng vai QA) và thử viết test case chỉ từ tài liệu đó. Nếu phải hỏi lại nhiều, hãy bổ sung cho đến khi đặc tả "tự đứng được".
Tóm tắt
Use Case Modeling là kỹ thuật đặc tả mô tả cách một actor đạt được một mục tiêu thông qua chuỗi các bước, với happy path và các nhánh thay thế, ngoại lệ rõ ràng. Với người chuyển từ QA, đây là vùng đất thân thuộc: tư duy kịch bản, ám ảnh "nếu lỗi thì sao", và thói quen mô tả trạng thái kết thúc đo được — tất cả đều là vốn liếng sẵn có của bạn.
Hãy nhớ ba điều cốt lõi: một, mỗi Use Case ứng với một mục tiêu duy nhất (tên Động từ + Danh từ, tránh chữ "Quản lý"); hai, Exception Flows là vũ khí khác biệt của BA xuất thân QA — đừng bao giờ bỏ trống; ba, viết Postconditions sao cho QA đọc xong là rút ra được test case. Khi làm chủ được ba điều này, bạn không chỉ viết Use Case đúng template — bạn viết Use Case mà cả đội dev lẫn đội QA đều biết ơn. Ở các bài tiếp theo, bạn sẽ thấy Use Case kết nối tự nhiên với User Story chuẩn INVEST (Bài 18) và với việc phân loại yêu cầu Functional/Non-Functional (Bài 19).