Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là BA của một dự án ví điện tử. Bạn vừa phỏng vấn xong đội vận hành về quy trình "nạp tiền vào ví từ thẻ ngân hàng". Trên giấy bạn ghi được mười mấy gạch đầu dòng: người dùng nhập số tiền, hệ thống kiểm tra hạn mức, gọi cổng thanh toán, nếu thất bại thì thử lại, nếu quá ba lần thì khóa giao dịch, nếu thành công thì ghi sổ và gửi thông báo... Bạn đem mớ gạch đầu dòng đó cho dev đọc. Dev gật gù, rồi code ra một luồng thiếu mất nhánh "thẻ bị từ chối do quá hạn mức trong ngày". Đến lúc UAT mới phát hiện, sửa thì trễ sprint.
Vấn đề không nằm ở việc bạn thu thập thiếu yêu cầu — mà nằm ở chỗ văn bản tuyến tính rất kém trong việc diễn tả những thứ rẽ nhánh, song song và lặp lại. Não người đọc một đoạn văn theo trình tự trên xuống, nhưng quy trình nghiệp vụ thì không chạy như vậy: nó có ngã ba, có vòng lặp, có những việc xảy ra cùng lúc.
Đây chính là lúc UML Activity Diagram (sơ đồ hoạt động) tỏa sáng. Nó là công cụ trực quan để mô tả luồng công việc — workflow — một cách chính xác đến mức dev đọc xong là dựng được logic, tester đọc xong là biết phải kiểm bao nhiêu nhánh, còn stakeholder nghiệp vụ đọc xong là gật đầu "đúng rồi, quy trình của tụi tôi nó chạy y vậy". Trong bộ công cụ của một BA, đây là một trong những diagram được dùng nhiều nhất, và may mắn là cũng dễ học nhất. Bài này tập trung trọn vẹn vào nó: các thành phần cơ bản, cách đọc, cách vẽ, và cách tránh những lỗi kinh điển.
Khái niệm cốt lõi
Activity Diagram là một trong các loại sơ đồ hành vi (behavioral diagram) của UML, dùng để mô tả dòng chảy của một quy trình hay một use case từ đầu đến cuối. Nếu Sequence Diagram trả lời câu hỏi "ai gọi ai, theo thứ tự thời gian nào", thì Activity Diagram trả lời câu hỏi "công việc đi từ bước nào sang bước nào, rẽ nhánh ở đâu, kết thúc thế nào". Nó giống một sơ đồ flowchart truyền thống, nhưng được chuẩn hóa theo ký hiệu UML nên ai trong ngành cũng đọc hiểu giống nhau.
Các thành phần cơ bản
Bạn chỉ cần nắm vững vài ký hiệu là đã vẽ được 90% các sơ đồ thực tế:
- Start node (nút bắt đầu) — một hình tròn được tô đặc (filled circle). Mỗi sơ đồ chỉ có một điểm bắt đầu. Đây là nơi luồng công việc khởi động.
- Action / Activity (hành động) — hình chữ nhật bo tròn góc (rounded rectangle), bên trong ghi một động từ mô tả việc cần làm, ví dụ "Kiểm tra hạn mức", "Gọi cổng thanh toán", "Gửi email xác nhận". Đây là khối xây dựng chính của sơ đồ.
- Decision node (nút quyết định) — hình thoi (diamond) có một đường vào và nhiều đường ra. Mỗi đường ra được gắn một guard condition — điều kiện trong ngoặc vuông, ví dụ
[số dư đủ]và[số dư không đủ]. Đây là nơi luồng rẽ nhánh theo điều kiện.
- Merge node (nút hợp nhánh) — cũng là hình thoi, nhưng ngược lại: nhiều đường vào, một đường ra. Dùng để gom các nhánh đã tách trước đó về lại một dòng chảy chung. Nhiều người mới hay quên nút này, khiến sơ đồ trông như tách mãi không gom lại.
- End node (nút kết thúc) — một hình tròn đặc nằm trong một vòng tròn (filled circle in circle), trông như cái bia bắn. Đánh dấu nơi toàn bộ luồng kết thúc. Một sơ đồ có thể có nhiều End node nếu các nhánh kết thúc ở những chỗ khác nhau.
- Control flow (luồng điều khiển) — mũi tên nối các thành phần, chỉ hướng đi của công việc.
Hai ký hiệu nâng cao rất hữu ích
Khi quy trình phức tạp hơn, bạn sẽ cần thêm:
- Fork và Join (nút song song) — một thanh đậm nằm ngang hoặc dọc (bar). Fork tách một luồng thành nhiều luồng chạy đồng thời; Join chờ tất cả các luồng song song hoàn thành rồi mới đi tiếp. Ví dụ: khi đơn hàng được duyệt, hệ thống đồng thời "trừ kho" và "gửi email cho khách" — hai việc này không phụ thuộc nhau nên chạy song song. Lưu ý phân biệt với Decision: Decision chỉ đi một nhánh, còn Fork đi tất cả các nhánh cùng lúc.
- Swimlane (làn bơi) — các cột (hoặc hàng) chia sơ đồ theo ai chịu trách nhiệm thực hiện hành động: Khách hàng | Hệ thống | Nhân viên kho | Cổng thanh toán. Swimlane biến một sơ đồ kỹ thuật thành một bức tranh nghiệp vụ ai cũng đọc được, đặc biệt giá trị khi trình bày cho stakeholder.
Khi nào BA nên dùng Activity Diagram
Không phải lúc nào cũng vẽ. Hãy dùng nó khi: quy trình có nhiều nhánh điều kiện; có bước lặp lại; có việc chạy song song; có nhiều bên cùng tham gia (cần swimlane); hoặc khi bạn cần làm rõ phần "luồng phụ" và "ngoại lệ" mà văn bản dễ bỏ sót. Với một quy trình đơn giản kiểu "bước 1, bước 2, bước 3" không rẽ nhánh thì một danh sách văn bản có khi lại gọn hơn.
Tình huống thực tế
Ví dụ 1 — Tiki: luồng xử lý đơn hàng có nhánh hủy
Một BA tại Tiki cần mô tả quy trình từ lúc khách "Đặt hàng" đến lúc "Giao thành công". Văn bản ban đầu chỉ ghi đường thẳng: đặt hàng → xác nhận → đóng gói → giao. Nhưng thực tế phức tạp hơn nhiều.
Khi vẽ thành Activity Diagram, BA đặt Start node, rồi tới Action "Khách đặt hàng". Tiếp theo là Decision [thanh toán online?]: nếu có, đi nhánh "Gọi cổng thanh toán" rồi Decision tiếp [thanh toán thành công?]; nếu thất bại quá 3 lần thì về Action "Hủy đơn" rồi End. Nếu thanh toán thành công (hoặc chọn COD), luồng tới Fork: đồng thời "Trừ tồn kho" và "Gửi email xác nhận". Sau Join là "Đóng gói", rồi "Bàn giao đơn vị vận chuyển", rồi Decision [giao thành công?] — nếu thất bại 3 lần thì "Hoàn hàng về kho".
Activity Diagram xử lý đơn hàng Tiki — có quyết định, Fork/Join song song và nhánh hủy:
flowchart TD
A([Bắt đầu]) --> B[Khách đặt hàng]
B --> C{Thanh toán online?}
C -->|COD| H
C -->|Có| D[Gọi cổng thanh toán]
D --> E{Thanh toán thành công?}
E -->|Thất bại quá 3 lần| F[Hủy đơn]
F --> G([Kết thúc])
E -->|Thành công| H[/Fork: chạy song song/]
H --> I[Trừ tồn kho]
H --> J[Gửi email xác nhận]
I --> K[/Join: chờ cả hai/]
J --> K
K --> L[Đóng gói]
L --> M[Bàn giao vận chuyển]
M --> N{Giao thành công?}
N -->|Có| O([Hoàn thành])
N -->|Thất bại 3 lần| P[Hoàn hàng về kho]
P --> Q([Kết thúc])Bài học rút ra: chính việc vẽ ra hình thoi [thanh toán thành công?] buộc BA phải hỏi đội vận hành: "Thử lại tối đa mấy lần? Quá thì sao?" Câu hỏi này không bao giờ nảy ra khi viết văn bản tuyến tính. Sơ đồ không chỉ là tài liệu — nó là công cụ phát hiện yêu cầu còn thiếu.
Ví dụ 2 — Một ngân hàng VN: phê duyệt khoản vay với swimlane
Tại một ngân hàng thương mại ở TP.HCM, BA mô tả quy trình "Phê duyệt vay tiêu dùng dưới 200 triệu". Quy trình này có tới bốn bên tham gia, nên BA dùng swimlane chia thành bốn làn: Khách hàng | Nhân viên tín dụng | Hệ thống chấm điểm | Trưởng phòng.
Luồng bắt đầu ở làn Khách hàng với "Nộp hồ sơ". Sang làn Nhân viên tín dụng: "Kiểm tra hồ sơ" rồi Decision [hồ sơ đủ?] — thiếu thì mũi tên quay ngược về làn Khách hàng để "Bổ sung giấy tờ" (đây là một vòng lặp). Đủ thì sang làn Hệ thống: "Chấm điểm tín dụng tự động", ra một Decision [điểm ≥ 650?]. Nếu đạt, đơn dưới 50 triệu được duyệt tự động; từ 50–200 triệu thì chuyển sang làn Trưởng phòng để "Phê duyệt thủ công".
Bài học rút ra: khi sơ đồ này được chiếu lên trong buổi review, Trưởng phòng phát hiện ngay: "Khoản 50–200 triệu của khách VIP thì tôi không cần duyệt, hệ thống tự chạy." Một quy tắc nghiệp vụ ẩn được khui ra chỉ vì swimlane làm rõ "ai làm gì". Swimlane biến sơ đồ thành ngôn ngữ chung giữa BA và nghiệp vụ.
Ví dụ 3 — Grab: vòng lặp ghép tài xế
BA của một đội sản phẩm gọi xe mô tả luồng "Tìm tài xế cho cuốc xe". Đây là ví dụ kinh điển về vòng lặp. Sau khi khách đặt cuốc, Action "Tìm tài xế gần nhất", rồi Decision [tài xế chấp nhận?]. Nếu không, mũi tên quay lại "Tìm tài xế tiếp theo" — tạo thành vòng lặp. Nhưng vòng lặp này không được vô hạn, nên BA thêm một Decision [đã tìm quá 90 giây?]: nếu quá thời gian, luồng thoát ra Action "Thông báo không có tài xế" rồi End.
Activity Diagram vòng lặp ghép tài xế — mọi vòng lặp phải có điều kiện thoát (quá 90 giây):
flowchart TD
A([Khách đặt cuốc]) --> B[Tìm tài xế gần nhất]
B --> C{Tài xế chấp nhận?}
C -->|Có| D([Ghép cuốc thành công])
C -->|Không| E{Đã tìm quá 90 giây?}
E -->|Chưa| F[Tìm tài xế tiếp theo]
F --> C
E -->|Rồi| G[Thông báo không có tài xế]
G --> H([Kết thúc])Bài học rút ra: mọi vòng lặp trong sơ đồ đều phải có điều kiện thoát rõ ràng. Một vòng lặp không có lối ra trên sơ đồ thường phản ánh một lỗ hổng thật trong thiết kế — hệ thống có thể treo. Activity Diagram giúp bạn nhìn thấy rủi ro đó trước khi nó thành bug.
Hướng dẫn từng bước
Đây là quy trình thực tế để vẽ một Activity Diagram chất lượng:
Bước 1 — Xác định phạm vi. Chọn rõ điểm bắt đầu và điểm kết thúc của quy trình. Ví dụ: bắt đầu "khách bấm Đặt hàng", kết thúc "đơn giao thành công hoặc bị hủy". Phạm vi quá rộng sẽ khiến sơ đồ rối; hãy giữ một sơ đồ cho một quy trình.
Bước 2 — Liệt kê các hành động chính theo dòng "happy path". Trước tiên cứ vẽ luồng lý tưởng, không lỗi: đặt hàng → thanh toán → đóng gói → giao. Mỗi hành động là một động từ + danh từ ngắn gọn. Đừng vội nghĩ đến ngoại lệ.
Bước 3 — Chèn các Decision node. Đi qua từng hành động và tự hỏi: "Ở đây có thể rẽ nhánh không?" Mỗi câu trả lời "có" là một hình thoi. Gắn guard condition rõ ràng cho từng nhánh, và đảm bảo các điều kiện bao phủ hết mọi khả năng (ví dụ có [đủ] thì phải có nhánh [không đủ]).
Bước 4 — Xử lý song song bằng Fork/Join. Tìm những việc không phụ thuộc nhau có thể chạy cùng lúc và tách bằng Fork, gom lại bằng Join. Đừng dùng Fork cho việc thực ra phải tuần tự.
Bước 5 — Thêm vòng lặp và đảm bảo điều kiện thoát. Với mỗi chỗ "thử lại", vẽ mũi tên quay ngược và luôn kèm một điều kiện dừng.
Bước 6 — Chia swimlane nếu có nhiều bên. Khi quy trình liên quan từ ba vai trò trở lên, hãy chia làn để làm rõ trách nhiệm.
Bước 7 — Đặt các End node và rà soát. Đảm bảo mọi nhánh đều dẫn tới một End node — không có mũi tên nào "cụt". Đọc lại sơ đồ một lượt như thể bạn là dòng dữ liệu đang chạy qua nó.
Bước 8 — Validate với stakeholder. Chiếu sơ đồ cho người nghiệp vụ và "chạy thử" vài kịch bản: "Nếu khách thanh toán lỗi thì đi đường nào?" Đây là lúc bạn bắt được phần lớn yêu cầu còn thiếu.
Về công cụ: với BA Việt Nam, các lựa chọn phổ biến là Draw.io / diagrams.net (miễn phí, có sẵn shape UML), Lucidchart, Visual Paradigm, hoặc PlantUML nếu bạn thích viết sơ đồ bằng code để dễ quản lý phiên bản trong Confluence/Git.
Lỗi thường gặp & mẹo
Lỗi 1 — Quên Merge node sau khi Decision. Sau một hình thoi tách hai nhánh, nếu hai nhánh đó cần gặp lại nhau, bạn phải có một hình thoi Merge để gom. Nhiều người để hai nhánh chạy song song mãi rồi mỗi nhánh tự kết thúc, khiến sơ đồ vừa dài vừa khó đọc.
Lỗi 2 — Nhầm Decision với Fork. Decision (hình thoi) chỉ chọn một nhánh để đi dựa trên điều kiện. Fork (thanh đậm) đi tất cả các nhánh cùng lúc. Vẽ nhầm hai cái này là sai logic nghiệp vụ nghiêm trọng — dev sẽ code ra hành vi hoàn toàn khác ý bạn.
Lỗi 3 — Guard condition không bao phủ hết. Nếu bạn ghi [điểm ≥ 650] ở một nhánh mà quên nhánh [điểm < 650], luồng sẽ bị "rơi" khi gặp trường hợp đó. Mẹo: các điều kiện ra từ một Decision phải vừa loại trừ lẫn nhau vừa bao phủ toàn bộ.
Lỗi 4 — Action mơ hồ. Hành động ghi "Xử lý đơn hàng" thì quá chung. Hãy tách thành các action cụ thể: "Kiểm tra tồn kho", "Trừ kho", "Tạo phiếu giao". Sơ đồ tốt là sơ đồ mà mỗi action ánh xạ được tới một việc rõ ràng.
Lỗi 5 — Nhồi nhét quá nhiều vào một sơ đồ. Nếu sơ đồ có hơn 20–25 action, hãy tách thành sơ đồ con. Một số công cụ cho phép dùng "call behavior action" để gọi một sơ đồ con — giúp giữ mỗi sơ đồ ở mức dễ đọc.
Mẹo vàng: luôn vẽ "happy path" trước, kiểm tra nó chạy thông, rồi mới thêm các nhánh ngoại lệ. Vẽ tất cả cùng lúc dễ khiến bạn rối và bỏ sót. Và hãy nhớ: sơ đồ đẹp nhất không phải sơ đồ nhiều ký hiệu nhất, mà là sơ đồ stakeholder đọc một lần là hiểu.
Bài tập thực hành
Bài tập 1 — Rút tiền ATM. Vẽ Activity Diagram cho quy trình rút tiền tại ATM, bắt đầu từ "Đút thẻ" đến "Nhận tiền và lấy thẻ". Yêu cầu: phải có ít nhất hai Decision ([đúng mã PIN?] với giới hạn 3 lần thử, và [số dư đủ?]), một vòng lặp nhập lại PIN, và xử lý trường hợp ATM hết tiền. Đảm bảo mọi nhánh đều có End node.
Bài tập 2 — Đăng bài có kiểm duyệt (có swimlane). Một nền tảng cộng đồng cho phép người dùng đăng bài, nhưng bài có chứa link phải qua kiểm duyệt thủ công. Vẽ sơ đồ với hai swimlane: Người dùng | Quản trị viên. Có Decision [bài chứa link?]: không thì đăng ngay; có thì chuyển sang làn Quản trị viên để duyệt, rồi [được duyệt?] — nếu từ chối thì gửi thông báo lý do về cho người dùng.
Bài tập 3 — Tự đánh giá. Lấy lại một quy trình bạn đã từng viết bằng văn bản trong công việc thật. Chuyển nó sang Activity Diagram. Ghi lại: bạn phát hiện ra bao nhiêu nhánh/điều kiện mà bản văn bản đã bỏ sót? Con số đó chính là giá trị thực mà sơ đồ mang lại.
Tóm tắt
Activity Diagram là công cụ trực quan mạnh nhất của BA để mô tả workflow có rẽ nhánh, vòng lặp và song song — những thứ mà văn bản tuyến tính diễn đạt rất tệ. Bạn chỉ cần nắm vài ký hiệu cốt lõi: Start node (hình tròn đặc), Action (chữ nhật bo góc), Decision/Merge (hình thoi với guard condition), End node (vòng tròn bia bắn), cùng hai ký hiệu nâng cao là Fork/Join cho luồng song song và Swimlane cho trách nhiệm theo vai trò.
Giá trị lớn nhất của sơ đồ này không nằm ở việc nó "đẹp", mà ở chỗ chính quá trình vẽ buộc bạn đặt ra những câu hỏi mà phỏng vấn thường bỏ sót: "Thử lại mấy lần? Quá thì sao? Ai chịu trách nhiệm bước này? Vòng lặp này thoát ở đâu?" Như ba ví dụ Tiki, ngân hàng và Grab cho thấy, mỗi hình thoi và mỗi vòng lặp đều có thể khui ra một yêu cầu hay quy tắc nghiệp vụ còn ẩn. Hãy luyện thói quen: vẽ happy path trước, thêm ngoại lệ sau, đảm bảo mọi nhánh có lối kết thúc, và luôn validate bằng cách "chạy thử" sơ đồ cùng stakeholder. Khi làm chủ được công cụ này, bạn sẽ giao cho dev những tài liệu mà họ đọc xong là dựng được logic — đúng vai trò cốt lõi của một BA giỏi.