Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 51 — UML Sequence Diagram cho interaction

Kiến Thức Cơ Bản BA: Thu Thập Yêu Cầu Hiệu Quả Bài 51/60

Mở đầu — vì sao bài này quan trọng

Trong các bài trước, bạn đã làm quen với UML (Bài 49) và Activity Diagram (Bài 50) — công cụ để mô tả luồng công việc theo thời gian. Nhưng có một câu hỏi mà Activity Diagram trả lời rất kém: "Ai gọi ai, và theo thứ tự nào?"

Hãy tưởng tượng bạn là BA của một ví điện tử như MoMo hoặc ZaloPay. Khi người dùng bấm nút "Thanh toán", thực tế có cả một dàn nhạc các thành phần phối hợp với nhau: ứng dụng gọi đến server ví, server ví gọi sang ngân hàng để kiểm tra số dư, ngân hàng trả lời, rồi server ví ghi nhận giao dịch, gửi thông báo, cập nhật màn hình... Activity Diagram chỉ cho thấy "có bước thanh toán" nhưng không cho thấy trình tự đối thoại giữa các thành phần.

Đó chính xác là lúc Sequence Diagram (sơ đồ trình tự) tỏa sáng. Đây là loại sơ đồ UML mô tả các thông điệp (message) được trao đổi giữa các thành phần theo đúng thứ tự thời gian. Với BA, đây là vũ khí cực mạnh để:

  • Làm rõ logic tích hợp giữa hệ thống của bạn với hệ thống bên thứ ba (ngân hàng, đối tác, API).
  • Giúp dev và tester hiểu chính xác "ai gọi cái gì, lúc nào, và nếu lỗi thì sao".
  • Phát hiện sớm các yêu cầu còn thiếu: "Nếu ngân hàng không phản hồi trong 30 giây thì sao?" — câu hỏi này gần như chắc chắn nảy ra khi bạn vẽ Sequence Diagram.
Nếu Activity Diagram trả lời "quy trình nghiệp vụ chạy thế nào", thì Sequence Diagram trả lời "các hệ thống nói chuyện với nhau ra sao". Đây là bài học giúp bạn nói cùng ngôn ngữ với đội kỹ thuật.

Khái niệm cốt lõi

Sequence Diagram được đọc theo hai trục: trục ngang là các thành phần tham gia, trục dọc (từ trên xuống) là thời gian. Mọi thứ ở phía trên xảy ra trước mọi thứ ở phía dưới.

Lifeline (đường đời) — các thành phần tham gia

Mỗi thành phần tham gia vào tương tác được biểu diễn bằng một hộp ở trên cùng (gọi là head) và một đường gạch đứt thẳng đứng kéo xuống dưới (gọi là lifeline). Lifeline thể hiện "sự tồn tại của thành phần đó qua thời gian".

Thành phần có thể là:

  • Actor (người dùng): vẽ hình que, ví dụ "Khách hàng".
  • Đối tượng/Hệ thống: vẽ hộp chữ nhật, ví dụ "App MoMo", "Server Ví", "Cổng Ngân hàng (NAPAS)", "Hệ thống Thông báo".
Quy ước đặt tên thường là tên : Lớp (ví dụ momoApp : MobileApp), nhưng với mục đích BA, bạn hoàn toàn có thể dùng tên nghiệp vụ dễ hiểu như "Server Ví" thay vì tên kỹ thuật.

Message (thông điệp) — các mũi tên ngang

Đây là phần "linh hồn" của sơ đồ. Mỗi mũi tên ngang đi từ lifeline này sang lifeline khác là một thông điệp — một lời gọi, một yêu cầu, một phản hồi. Có vài loại message bạn cần phân biệt:

  • Synchronous message (đồng bộ) — mũi tên có đầu mũi tên đặc (filled). Bên gửi chờ bên nhận xử lý xong và trả lời rồi mới đi tiếp. Ví dụ: "Server Ví gọi Ngân hàng kiểm tra số dư" — phải chờ ngân hàng trả lời.
  • Return message (trả về) — mũi tên có đường gạch đứt và đầu mũi tên mở (open). Đây là phản hồi của một lời gọi đồng bộ, ví dụ "Số dư khả dụng: 500.000đ".
  • Asynchronous message (bất đồng bộ) — mũi tên đầu mở (open), nét liền. Bên gửi không chờ, gửi xong là làm việc khác. Ví dụ: "Server Ví gửi yêu cầu push notification" — gửi rồi đi tiếp luôn, không cần chờ thông báo gửi xong.

Activation bar (thanh kích hoạt)

Đây là hộp chữ nhật hẹp, thẳng đứng đặt chồng lên lifeline. Nó thể hiện khoảng thời gian một thành phần đang bận xử lý một việc gì đó (đang "active"). Khi Server Ví nhận lời gọi và đang xử lý kiểm tra giao dịch, một activation bar xuất hiện trên lifeline của nó. Khi xử lý xong và trả lời, activation bar kết thúc. Activation bar giúp người đọc thấy ngay "ai đang làm việc, trong bao lâu".

Combined fragments — khối điều kiện và lặp

Đời thực không chỉ có luồng thẳng. Sequence Diagram cho phép gói một nhóm message vào một khung (frame) có nhãn ở góc trái trên:

  • alt (alternative): rẽ nhánh if/else. Ví dụ: nếu số dư đủ thì xử lý thanh toán, nếu không đủ thì báo lỗi. Trong khung alt có một đường gạch ngang chia hai vùng, mỗi vùng kèm một điều kiện (guard) trong ngoặc vuông như [số dư đủ].
  • opt (option): khối chỉ chạy khi điều kiện đúng (if không có else).
  • loop: khối lặp lại, ví dụ loop [với mỗi sản phẩm trong giỏ].
  • par (parallel): các luồng chạy song song.
Bốn loại fragment này (alt, opt, loop, par) phủ tới khoảng 90% nhu cầu của một BA. Bạn không cần nhớ hết tất cả các loại fragment khác.

Một vài ký hiệu bổ sung hữu ích

  • Self-message: mũi tên vòng lại chính lifeline đó — khi một thành phần tự gọi hàm của chính nó (ví dụ Server Ví tự "validate dữ liệu đầu vào").
  • Found/Lost message: message đến từ nguồn không xác định (chấm tròn đầu) hoặc đi đến đích không xác định — ít dùng trong tài liệu BA.
  • Destroy (X): đánh dấu một đối tượng bị huỷ — hiếm khi cần cho mục đích nghiệp vụ.

Tình huống thực tế

Ví dụ 1 — Tiki: luồng đặt hàng và trừ tồn kho

Bối cảnh: Bạn là BA tại một sàn TMĐT giả định kiểu Tiki. Đội dev liên tục tranh cãi: "Khi khách đặt hàng, mình trừ tồn kho trước hay sau khi thanh toán?". Mỗi người hiểu một kiểu, dẫn đến bug oversell (bán quá số lượng tồn).

Bạn vẽ một Sequence Diagram với các lifeline: Khách hàng → App → Order Service → Inventory Service → Payment Gateway → Email Service. Luồng theo thứ tự:

  • Khách hàng → App: bấm "Đặt hàng" (sync).
  • App → Order Service: tạo đơn (sync).
  • Order Service → Inventory Service: giữ chỗ tồn kho (reserve) (sync) — không phải trừ hẳn, mà tạm giữ.
  • Một khung alt: [còn hàng] → tiếp tục; [hết hàng] → trả lỗi "Sản phẩm đã hết", kết thúc.
  • Order Service → Payment Gateway: yêu cầu thanh toán (sync).
  • Khung alt thứ hai: [thanh toán thành công] → Inventory Service trừ tồn kho thật + Order Service → Email Service gửi xác nhận (async); [thất bại] → nhả chỗ tồn kho đã giữ, báo lỗi.
Sequence Diagram đặt hàng Tiki — giữ chỗ tồn kho trước, trừ thật sau, có nhánh đường lỗi:

sequenceDiagram
    actor KH as Khách hàng
    participant App
    participant OS as Order Service
    participant INV as Inventory Service
    participant PAY as Payment Gateway
    participant MAIL as Email Service
    KH->>App: Bấm Đặt hàng
    App->>OS: Tạo đơn
    OS->>INV: Giữ chỗ tồn kho (reserve)
    alt Còn hàng
        INV-->>OS: Đã giữ chỗ
        OS->>PAY: Yêu cầu thanh toán
        alt Thanh toán thành công
            PAY-->>OS: Thành công
            OS->>INV: Trừ tồn kho thật
            OS-)MAIL: Gửi email xác nhận
        else Thất bại
            PAY-->>OS: Thất bại
            OS->>INV: Nhả chỗ tồn kho đã giữ
            OS-->>App: Báo lỗi thanh toán
        end
    else Hết hàng
        INV-->>OS: Hết hàng
        OS-->>App: Sản phẩm đã hết
    end

Diễn giải: Chỉ riêng việc vẽ ra hai bước "giữ chỗ" rồi mới "trừ thật" đã giải quyết tranh cãi và lộ ra một yêu cầu mới: cần cơ chế nhả tồn kho nếu thanh toán thất bại hoặc timeout. Bài học rút ra: Sequence Diagram biến một cuộc tranh luận mơ hồ thành một hợp đồng tương tác rõ ràng, đồng thời phát hiện luồng "đường lỗi" mà trước đó không ai nghĩ tới.

Ví dụ 2 — VPBank: đăng nhập với OTP và xử lý timeout

Bối cảnh: Một ngân hàng giả định kiểu VPBank xây tính năng đăng nhập internet banking có xác thực OTP qua SMS. BA cũ chỉ viết user story "Người dùng nhập OTP để đăng nhập", và dev hỏi dồn dập: OTP sống bao lâu? Nhập sai mấy lần thì khoá? SMS không tới thì sao?

BA vẽ Sequence Diagram: Khách → App → Auth Server → SMS Gateway (Viettel/MobiFone).

  • Khách → App → Auth Server: gửi username/password (sync), Auth Server có activation bar dài thể hiện đang xác thực.
  • [đúng mật khẩu] (trong khung alt): Auth Server → SMS Gateway: gửi OTP (async — gửi rồi không chờ SMS thực sự đến tay khách).
  • Một khung loop [tối đa 3 lần]: Khách nhập OTP → Auth Server kiểm tra.
  • Bên trong loop là alt: [OTP đúng & còn hạn 90s] → trả token, thoát loop; [OTP sai] → báo lỗi, tăng biến đếm; [hết 90s] → báo "OTP hết hạn".
  • Sau loop, một khung opt [sai quá 3 lần]: khoá tài khoản 15 phút + gửi cảnh báo.
Sequence Diagram đăng nhập OTP VPBank — khung loop/alt/opt ép lộ mọi edge case và con số:

sequenceDiagram
    actor KH as Khách
    participant App
    participant AUTH as Auth Server
    participant SMS as SMS Gateway
    KH->>App: Nhập username/password
    App->>AUTH: Xác thực
    alt Đúng mật khẩu
        AUTH-)SMS: Gửi OTP (async)
        loop Tối đa 3 lần
            KH->>AUTH: Nhập OTP
            alt OTP đúng và còn hạn 90s
                AUTH-->>App: Trả token, đăng nhập
            else OTP sai
                AUTH-->>KH: Báo lỗi, tăng đếm
            else Hết 90s
                AUTH-->>KH: OTP hết hạn
            end
        end
        opt Sai quá 3 lần
            AUTH->>AUTH: Khóa tài khoản 15 phút
            AUTH-)KH: Gửi cảnh báo
        end
    else Sai mật khẩu
        AUTH-->>App: Từ chối đăng nhập
    end

Con số cụ thể: OTP hết hạn sau 90 giây, khoá sau 3 lần sai, mở lại sau 15 phút. Diễn giải: Những con số này bắt buộc phải xuất hiện khi bạn vẽ sơ đồ, vì khung loopalt ép bạn định nghĩa điều kiện. Bài học rút ra: Sequence Diagram là công cụ "ép" BA hỏi đúng câu hỏi về biên (edge case) và quy tắc nghiệp vụ — những thứ mà văn xuôi thường bỏ sót.

Ví dụ 3 — Grab: phân tích tích hợp định vị tài xế

Bối cảnh: Một ứng dụng gọi xe kiểu Grab gặp lỗi: thỉnh thoảng app báo "không tìm thấy tài xế" dù khu vực có xe. BA được nhờ phân tích để viết lại yêu cầu cho rõ.

BA vẽ Sequence Diagram cho luồng tìm tài xế: App khách → Matching Service → Location Service → Driver App. Khi vẽ, BA dùng par để mô tả Matching Service gọi đồng thời nhiều Driver App. Đến message "Location Service trả về vị trí tài xế", BA đặt câu hỏi: vị trí này được cập nhật mỗi bao lâu? Hoá ra Driver App chỉ gửi vị trí mỗi 30 giây (async), nên dữ liệu có thể "cũ" tới 30 giây — đủ để tài xế đã đi khỏi vùng.

Diễn giải: Chính việc nhìn message bất đồng bộ "cập nhật vị trí" trên sơ đồ giúp BA chỉ ra gốc rễ vấn đề và đề xuất yêu cầu mới: giảm chu kỳ cập nhật xuống 10 giây khi tài xế đang ở trạng thái tìm khách. Bài học rút ra: Sequence Diagram không chỉ để thiết kế cái mới — nó còn là công cụ điều tra (reverse-engineer) hệ thống đang chạy để tìm nguồn gốc lỗi tích hợp.

Hướng dẫn từng bước

Đây là quy trình 7 bước để vẽ một Sequence Diagram chất lượng:

Bước 1 — Xác định phạm vi (scope). Chọn đúng một kịch bản cụ thể, ví dụ "Khách thanh toán đơn hàng bằng ví". Đừng cố vẽ cả hệ thống vào một sơ đồ. Một sơ đồ = một use case scenario.

Bước 2 — Liệt kê các participant. Ghi ra mọi thành phần tham gia: actor (người dùng) và các hệ thống/dịch vụ. Sắp xếp chúng theo thứ tự tương tác từ trái sang phải — actor thường ở ngoài cùng bên trái.

Bước 3 — Vẽ message của luồng chính (happy path) trước. Đi từ trên xuống, mỗi message là một mũi tên. Đặt tên message bằng động từ + đối tượng rõ ràng: "kiểm tra số dư", "tạo đơn hàng", chứ không phải "msg1", "process".

Bước 4 — Thêm return message khi cần. Với mỗi lời gọi đồng bộ quan trọng, vẽ mũi tên trả về (gạch đứt) kèm nội dung trả về: "OK", "số dư = 500.000đ", "mã lỗi 402". Không cần vẽ return cho mọi message — chỉ những cái mang thông tin quan trọng.

Bước 5 — Thêm activation bar. Đánh dấu khoảng thời gian mỗi thành phần đang xử lý. Phần lớn công cụ vẽ (PlantUML, draw.io, Lucidchart) tự sinh activation bar khi bạn nối message.

Bước 6 — Bổ sung các nhánh và vòng lặp. Bây giờ mới thêm alt (lỗi/thành công), opt, loop, par. Đây là lúc các edge case và quy tắc nghiệp vụ lộ ra — hãy ghi chú lại mọi câu hỏi nảy sinh để xác nhận với stakeholder.

Bước 7 — Rà soát và xác nhận. Đọc lại sơ đồ cùng dev/tester. Hỏi: "Có message nào thiếu return không? Có nhánh lỗi nào chưa xử lý không? Có timeout không?".

Về công cụ: với BA Việt Nam, PlantUML (viết bằng text, dễ version control, dễ nhúng vào Confluence) và draw.io / diagrams.net (kéo thả miễn phí) là hai lựa chọn phổ biến nhất. Mermaid cũng tốt nếu bạn làm việc nhiều với Markdown và Jira/Confluence hiện đại.

Lỗi thường gặp & mẹo

Lỗi 1 — Nhồi quá nhiều vào một sơ đồ. Nếu sơ đồ có hơn 8-10 lifeline hoặc dài hơn một trang A4, người đọc sẽ "ngợp". Mẹo: tách thành nhiều sơ đồ theo scenario, hoặc gom một nhóm hệ thống con thành một lifeline ở mức trừu tượng cao hơn.

Lỗi 2 — Nhầm Sequence Diagram với Activity Diagram. Activity Diagram tập trung vào luồng quy trình và quyết định nghiệp vụ; Sequence Diagram tập trung vào ai gọi ai theo thứ tự. Nếu bạn thấy mình đang vẽ nhiều ô quyết định (diamond), có lẽ bạn cần Activity Diagram. Nếu trọng tâm là sự đối thoại giữa các hệ thống, dùng Sequence Diagram.

Lỗi 3 — Quên đường lỗi (error path). Đa số BA mới chỉ vẽ happy path. Nhưng giá trị lớn nhất của sơ đồ nằm ở nhánh alt [thất bại]: timeout, mất kết nối, dữ liệu sai. Mẹo: với mỗi lời gọi ra hệ thống bên ngoài, luôn tự hỏi "Nếu nó không trả lời, hoặc trả lời lỗi, thì sao?".

Lỗi 4 — Đặt tên message mơ hồ. "xử lý", "handle", "do it" không cho người đọc biết điều gì. Dùng động từ nghiệp vụ cụ thể: "trừ tồn kho", "tính phí ship", "gửi OTP".

Lỗi 5 — Lẫn lộn sync và async. Vẽ sai loại mũi tên dẫn đến hiểu sai hành vi hệ thống — dev có thể code chờ (blocking) trong khi đáng lẽ phải gọi bất đồng bộ. Mẹo nhớ: đầu mũi tên đặc = đồng bộ = phải chờ; đầu mũi tên mở = bất đồng bộ = không chờ; gạch đứt = trả về.

Mẹo vàng: Đừng vẽ Sequence Diagram một mình rồi mới đưa cho dev. Hãy vẽ cùng dev hoặc kiến trúc sư hệ thống trong một buổi 30 phút. Sơ đồ chỉ là cái cớ để cả hai cùng làm rõ logic — và đó mới là phần giá trị nhất.

Bài tập thực hành

Bài tập 1 (cơ bản): Vẽ Sequence Diagram cho luồng "Khách hàng đăng ký tài khoản qua email" với các participant: Khách hàng, App, Auth Service, Email Service. Yêu cầu: có ít nhất một message async (gửi email xác nhận), một return message, và một khung alt cho trường hợp email đã tồn tại.

Bài tập 2 (vận dụng): Lấy ví dụ ví điện tử ở phần mở đầu. Vẽ Sequence Diagram cho luồng "Nạp tiền vào ví từ thẻ ngân hàng", bao gồm: kiểm tra hạn mức, gọi cổng NAPAS, xử lý timeout 30 giây, và gửi thông báo khi thành công. Đánh dấu rõ message nào sync, async, return.

Bài tập 3 (nâng cao — phân tích): Chọn một tính năng trong hệ thống bạn đang làm việc (hoặc một app bạn hay dùng). Vẽ Sequence Diagram cho luồng chính, sau đó liệt kê tối thiểu 3 câu hỏi về edge case mà sơ đồ giúp bạn phát hiện ra. Mục tiêu của bài này là cảm nhận sức mạnh "ép hỏi đúng câu hỏi" của Sequence Diagram.

Gợi ý: dùng PlantUML hoặc draw.io. Với PlantUML, cú pháp A -> B : message cho sync, A --> B : return cho return, và khối alt ... else ... end cho nhánh.

Tóm tắt

Sequence Diagram là loại sơ đồ UML mô tả các thông điệp trao đổi giữa các thành phần theo thứ tự thời gian — trục ngang là participant, trục dọc là thời gian. Bốn yếu tố cốt lõi bạn cần nắm vững:

  • Lifeline: đường thẳng đứng thể hiện mỗi thành phần (actor hoặc hệ thống).
  • Message: mũi tên ngang thể hiện lời gọi/phản hồi — phân biệt sync (đầu đặc, phải chờ), async (đầu mở, không chờ), và return (gạch đứt).
  • Activation bar: hộp dọc thể hiện thành phần đang bận xử lý.
  • Combined fragments (alt, opt, loop, par): để diễn tả rẽ nhánh, điều kiện, lặp và song song.
Với BA, giá trị thực sự của Sequence Diagram không nằm ở việc "vẽ đẹp", mà ở chỗ nó ép bạn hỏi đúng câu hỏi: ai gọi ai, chờ hay không chờ, lỗi thì sao, timeout bao lâu. Như ba ví dụ Tiki, VPBank và Grab đã cho thấy, chỉ riêng quá trình vẽ đã làm lộ ra những yêu cầu bị thiếu và những edge case bị bỏ quên. Hãy vẽ nó cùng đội kỹ thuật, tập trung vào một scenario mỗi sơ đồ, và đừng bao giờ quên nhánh đường lỗi. Ở bài tiếp theo, chúng ta sẽ bước sang BPMN 2.0 — ngôn ngữ chuẩn để mô hình hoá quy trình nghiệp vụ ở quy mô lớn hơn.