Mở đầu — vì sao bài này quan trọng
Bạn đã từng vẽ một quy trình "đẹp như mơ" chưa? Khách hàng đặt hàng, hệ thống kiểm tra tồn kho, trừ tiền, tạo đơn, gửi email xác nhận — mọi thứ chạy thẳng một mạch từ trái sang phải. Trong giới làm quy trình, chúng tôi gọi đó là happy path (luồng lý tưởng), nơi mọi thứ diễn ra đúng như kỳ vọng.
Vấn đề là: trong thực tế, happy path chỉ chiếm khoảng 60–80% số lần quy trình chạy. Phần còn lại — 20–40% — là những lần "có chuyện": khách gửi sai giấy tờ, API ngân hàng treo, nhân viên duyệt nhầm rồi nghỉ phép, mạng rớt giữa chừng. Và đây mới là sự thật phũ phàng mà mọi Business Process Analyst cần khắc cốt ghi tâm: chất lượng của một quy trình không nằm ở chỗ nó xử lý happy path tốt thế nào, mà ở chỗ nó xử lý những lúc "có chuyện" ra sao.
Một quy trình không có thiết kế exception handling (xử lý ngoại lệ) tử tế sẽ biểu hiện ra ngoài như thế này: đơn hàng "kẹt" mà không ai biết, khách gọi tổng đài phàn nàn, nhân viên phải mở Excel ra "chữa cháy" thủ công, và quan trọng nhất — không ai chịu trách nhiệm vì quy trình "chưa từng tính đến tình huống này". Bài học hôm nay sẽ dạy bạn cách phân loại, thiết kế và mô hình hóa exception handling một cách có hệ thống, để khi "có chuyện", quy trình của bạn không sụp đổ mà tự biết cách phục hồi hoặc chuyển hướng đúng người.
Khái niệm cốt lõi
Exception (ngoại lệ) là bất kỳ tình huống nào khiến quy trình lệch khỏi happy path. Lưu ý: exception không phải lúc nào cũng là "lỗi". Khách hàng thay đổi ý định và muốn hủy đơn cũng là một exception — nó hợp lệ, nhưng không nằm trong luồng chính. Vì vậy nhiệm vụ của người thiết kế quy trình không phải là "ngăn chặn mọi exception" (điều bất khả thi), mà là dự liệu trước và thiết kế đường đi cho từng loại exception.
Cách hiệu quả nhất để bắt đầu là phân loại exception theo nguồn gốc, vì mỗi loại đòi hỏi một chiến lược xử lý hoàn toàn khác nhau. Có ba loại lớn.
1. Business exception — ngoại lệ nghiệp vụ
Đây là những tình huống xuất phát từ bản chất nghiệp vụ, không liên quan đến công nghệ. Ví dụ kinh điển: khách hàng nộp hồ sơ vay nhưng thiếu sổ hộ khẩu, hoặc gửi ảnh chụp CMND bị mờ không đọc được. Hệ thống vẫn chạy hoàn hảo, không có dòng code nào lỗi — vấn đề nằm ở dữ liệu đầu vào không đạt điều kiện nghiệp vụ.
Đặc điểm của business exception:
- Thường dự đoán được từ trước (bạn biết chắc một tỷ lệ khách sẽ gửi giấy tờ sai).
- Cần con người ra quyết định hoặc cần khách hàng bổ sung/sửa thông tin.
- Thường được xử lý bằng cách vòng lặp về bước trước (yêu cầu khách nộp lại) hoặc chuyển sang một nhánh nghiệp vụ riêng (ví dụ: từ chối hồ sơ, đưa sang xét duyệt thủ công).
2. System exception — ngoại lệ kỹ thuật
Đây là những lỗi thuộc về hạ tầng công nghệ: API của đối tác bị timeout, cơ sở dữ liệu mất kết nối, dịch vụ thanh toán trả về lỗi 500, hàng đợi message bị nghẽn. Nghiệp vụ hoàn toàn hợp lệ — khách gửi đúng giấy tờ, mọi điều kiện đều đạt — nhưng hệ thống không hoàn thành được tác vụ vì lý do kỹ thuật.
Đặc điểm của system exception:
- Thường mang tính tạm thời (transient): API timeout lần này nhưng thử lại sau 30 giây có thể thành công.
- Chiến lược xử lý chủ đạo là retry (thử lại) — thường là retry có giới hạn số lần kèm thời gian chờ tăng dần (exponential backoff).
- Khi retry hết số lần vẫn thất bại, cần có cơ chế fallback (phương án dự phòng) hoặc dead-letter (đưa vào hàng chờ xử lý thủ công) và cảnh báo cho đội kỹ thuật.
3. Human exception — ngoại lệ do con người
Đây là loại tinh vi và dễ bị bỏ sót nhất. Nó xảy ra khi một tác vụ thủ công (manual task / user task) không được hoàn thành đúng như kỳ vọng. Ví dụ: nhân viên duyệt hồ sơ được giao việc nhưng đi nghỉ phép 1 tuần, đơn "ngủ đông" trong inbox của họ; hoặc người duyệt bấm nhầm "Từ chối" thay vì "Chấp thuận"; hoặc một bước cần hai người ký nhưng người thứ hai quên mất.
Đặc điểm của human exception:
- Thường liên quan đến thời gian (việc không được làm trong SLA cam kết) và trách nhiệm (ai chịu trách nhiệm khi việc bị bỏ quên).
- Chiến lược xử lý chủ đạo là escalation (leo thang) — nếu sau X giờ chưa xử lý xong thì tự động chuyển cho cấp trên hoặc người thay thế.
- Cần kết hợp với reminder (nhắc nhở tự động) và đôi khi là reassignment (giao lại việc).
Bốn chiến lược xử lý phổ quát
Dù exception thuộc loại nào, bạn luôn chọn một (hoặc kết hợp) trong bốn chiến lược sau:
- Retry — thử lại tác vụ vừa thất bại (hợp với system exception tạm thời).
- Compensate / Rollback — hoàn tác các bước đã làm để trả hệ thống về trạng thái nhất quán (ví dụ: đã trừ tiền nhưng tạo đơn thất bại thì phải hoàn tiền). Lưu ý: logic undo chi tiết được trình bày sâu ở Bài 23, ở đây chúng ta chỉ coi nó là một lựa chọn xử lý.
- Escalate — chuyển vấn đề lên cấp cao hơn hoặc người khác (hợp với human exception).
- Abort / Cancel — dừng quy trình một cách có kiểm soát, thông báo cho các bên liên quan, và ghi nhận lý do.
Tình huống thực tế
Ví dụ 1 — Sàn TMĐT Tiki: ba loại exception trong một luồng đặt hàng
Hãy hình dung đội vận hành của một sàn thương mại điện tử tại Việt Nam thiết kế lại luồng "Đặt hàng và thanh toán". Happy path rất ngắn: khách chọn hàng → thanh toán qua cổng → trừ kho → tạo đơn → gửi xác nhận. Nhưng khi họ phân tích log 30 ngày, họ phát hiện cả ba loại exception đều xuất hiện.
- Business exception: 4% đơn hàng dùng mã giảm giá đã hết hạn hoặc không đủ điều kiện. Đây không phải lỗi hệ thống — đó là nghiệp vụ. Họ thêm một Exclusive Gateway kiểm tra mã: nếu không hợp lệ, đẩy về màn hình giỏ hàng kèm thông báo rõ ràng "Mã của bạn đã hết hạn", thay vì để đơn treo.
- System exception: 2,5% giao dịch gặp timeout từ cổng thanh toán vào giờ cao điểm (12h trưa và 21h tối). Họ thiết kế cơ chế retry 3 lần với khoảng chờ 5s–15s–45s. Nếu vẫn thất bại, đơn được đưa vào trạng thái "Chờ thanh toán lại" và gửi link thanh toán qua app trong 15 phút, đồng thời cảnh báo đội kỹ thuật nếu tỷ lệ timeout vượt 5% trong 10 phút.
- Human exception: với đơn giá trị trên 20 triệu cần nhân viên xác minh thủ công, có những đơn bị "kẹt" 8 tiếng vì nhân viên ca đó quá tải. Họ thêm Timer Boundary Event: sau 2 giờ chưa xác minh, tự động nhắc; sau 4 giờ, leo thang sang trưởng nhóm.
Ví dụ 2 — Ngân hàng số: khi "nuốt im" exception gây hậu quả thật
Một ngân hàng số tại Đông Nam Á triển khai quy trình mở tài khoản online (eKYC). Trong giai đoạn đầu, đội thiết kế chỉ vẽ happy path và một nhánh "lỗi chung" gom mọi exception về một chỗ: hễ có vấn đề thì hiện thông báo "Có lỗi xảy ra, vui lòng thử lại".
Hậu quả sau một tháng: khoảng 12.000 hồ sơ bị mắc kẹt. Khi đào sâu, đội vận hành phát hiện ba nguyên nhân khác nhau bị trộn lẫn — khách chụp giấy tờ mờ (business), dịch vụ đối chiếu khuôn mặt của bên thứ ba quá tải vào cuối tháng (system), và bộ phận compliance không kịp duyệt các hồ sơ rủi ro cao (human). Vì tất cả đều hiện cùng một thông báo "Có lỗi xảy ra", khách hàng cứ thử lại vô vọng, còn đội vận hành không biết phải sửa từ đâu.
Sau khi tách bạch ba loại: hồ sơ giấy tờ mờ được tự động yêu cầu chụp lại với hướng dẫn cụ thể (tỷ lệ hoàn thành tăng 31%); lỗi đối chiếu khuôn mặt được retry và có nhà cung cấp dự phòng; hồ sơ chờ compliance có SLA và escalation rõ ràng. Tỷ lệ hồ sơ "kẹt" giảm từ 18% xuống còn 3% trong sáu tuần.
Bài học rút ra: gom mọi exception vào một "thùng rác lỗi" chung là phản mẫu (anti-pattern) phổ biến và tốn kém nhất. Phân loại đúng nguồn gốc exception chính là chìa khóa để xử lý đúng.
Ví dụ 3 — Công ty logistics: human exception bị lãng quên
Một công ty giao vận tại TP.HCM có quy trình duyệt hoàn tiền cho đơn giao thất bại. Luồng được thiết kế khá tốt cho business và system exception, nhưng họ bỏ quên human exception. Mỗi yêu cầu hoàn tiền được giao cho một nhân viên CSKH duyệt. Không ai để ý rằng khi nhân viên nghỉ ốm hoặc nghỉ Tết, các yêu cầu giao cho người đó cứ nằm im trong hệ thống — không lỗi, không cảnh báo, chỉ đơn giản là không ai đụng tới.
Đỉnh điểm là dịp Tết, một nhân viên nghỉ phép dài ngày khiến 340 yêu cầu hoàn tiền "đóng băng" suốt 9 ngày. Khách hàng phẫn nộ tràn lên mạng xã hội. Khi rà soát, ban lãnh đạo nhận ra quy trình hoàn toàn "im lặng" về tình huống này.
Cách khắc phục: thêm Timer Boundary Event non-interrupting gắn vào User Task duyệt hoàn tiền — sau 24 giờ chưa xử lý thì gửi nhắc, sau 48 giờ thì interrupting để tự động giao lại cho nhân viên khác đang online, và sau 72 giờ thì leo thang lên quản lý ca. Đồng thời họ thêm logic phát hiện "người nhận việc đang ở trạng thái nghỉ" để không giao việc mới cho người vắng mặt.
Bài học rút ra: human exception là loại dễ bị bỏ sót nhất vì nó không phát ra "tiếng động" như lỗi hệ thống. Bạn phải chủ động thiết kế cơ chế thời gian (timer, SLA, escalation) để biến sự im lặng thành tín hiệu hành động.
Hướng dẫn từng bước
Đây là quy trình sáu bước để thiết kế exception handling cho bất kỳ process nào.
Bước 1 — Vẽ happy path trước, đừng vội nghĩ đến exception. Hãy hoàn thành luồng lý tưởng trọn vẹn từ đầu đến cuối. Việc trộn lẫn happy path và exception ngay từ đầu sẽ khiến sơ đồ rối loạn và bạn dễ bỏ sót cả hai.
Bước 2 — Quét từng bước và đặt câu hỏi "Nếu bước này thất bại thì sao?" Đi qua từng activity, từng gateway và tự hỏi: bước này có thể hỏng theo những cách nào? Ghi lại mọi khả năng — kể cả những cái có vẻ hiếm gặp.
Bước 3 — Phân loại mỗi exception vào ba nhóm. Với mỗi tình huống thất bại đã liệt kê, gắn nhãn: Business, System, hay Human? Việc phân loại này quyết định trực tiếp chiến lược xử lý ở bước sau. Nếu một exception khó phân loại, hãy hỏi: "Nguồn gốc thực sự là dữ liệu nghiệp vụ, hạ tầng kỹ thuật, hay hành vi con người?"
Bước 4 — Chọn chiến lược cho từng exception. Áp dụng quy tắc kinh nghiệm: System → ưu tiên Retry rồi Fallback; Business → ưu tiên Gateway điều hướng hoặc vòng lặp bổ sung dữ liệu; Human → ưu tiên Reminder rồi Escalate. Với mọi loại, luôn xác định "phương án cuối cùng" khi mọi cách đều thất bại (thường là chuyển sang xử lý thủ công có ghi nhận).
Bước 5 — Mô hình hóa bằng đúng ký hiệu BPMN. Dùng Error Boundary Event cho system exception, Timer Boundary Event cho human exception, Exclusive Gateway hoặc Error End Event cho business exception. Quan trọng: mỗi nhánh exception phải dẫn tới một kết thúc rõ ràng, không để treo lơ lửng.
Bước 6 — Gán trách nhiệm và đặt ngưỡng đo lường. Mỗi nhánh exception phải trả lời được: ai nhận thông báo? sau bao lâu? ngưỡng cảnh báo là bao nhiêu? Một exception handling không có người chịu trách nhiệm và không có số đo thì chỉ là trang trí trên sơ đồ.
Lỗi thường gặp & mẹo
Lỗi 1 — Gom mọi exception vào một nhánh "lỗi" duy nhất. Như ví dụ ngân hàng số ở trên, đây là sai lầm phổ biến nhất. Mỗi loại exception cần đường đi riêng. Mẹo: nếu nhánh xử lý lỗi của bạn kết thúc bằng một thông báo chung chung kiểu "Có lỗi xảy ra", đó là dấu hiệu bạn đang gom nhầm.
Lỗi 2 — Retry vô hạn cho system exception. Retry mà không giới hạn số lần sẽ gây "bão retry" — khi dịch vụ đối tác sập, hàng nghìn tiến trình cùng retry liên tục càng làm nó sập sâu hơn. Mẹo: luôn đặt số lần retry tối đa và dùng exponential backoff (thời gian chờ tăng dần), kèm một đích đến cuối cùng khi hết lượt.
Lỗi 3 — Nhầm business exception thành system exception. Khi khách gửi giấy tờ sai, một số đội lập trình "ném lỗi" (throw error) như thể đó là lỗi kỹ thuật, rồi retry. Nhưng retry một giấy tờ mờ 5 lần vẫn ra... giấy tờ mờ. Mẹo: business exception cần con người hoặc khách hàng can thiệp, không bao giờ tự retry mà giải quyết được.
Lỗi 4 — Bỏ quên human exception. Như ví dụ logistics, vì human exception "im lặng" nên rất dễ bị bỏ sót. Mẹo: với mọi User Task có cam kết SLA, hãy mặc định gắn ít nhất một Timer cho reminder và một mức escalation.
Lỗi 5 — Exception handling không có quan sát (observability). Nếu bạn xử lý exception nhưng không log lại và không đo tần suất, bạn sẽ không bao giờ biết nhánh nào đang "nóng". Mẹo: mỗi nhánh exception nên ghi nhận số liệu để bạn biết loại nào xảy ra nhiều nhất mà ưu tiên cải tiến happy path.
Mẹo nâng cao: hãy phân biệt giữa "exception cần con người xử lý ngay" và "exception hệ thống tự phục hồi được". Mục tiêu thiết kế tốt là tối đa hóa loại thứ hai và tối thiểu hóa loại thứ nhất, vì mỗi lần kéo con người vào là một lần tốn thời gian và chi phí.
Bài tập thực hành
Bài tập 1 — Phân loại exception. Cho quy trình "Đăng ký thẻ tín dụng online". Hãy liệt kê ít nhất 6 tình huống có thể khiến quy trình lệch happy path, rồi phân loại mỗi tình huống vào Business / System / Human. Với mỗi tình huống, ghi chiến lược xử lý bạn chọn (Retry / Gateway / Escalate / Abort) và lý do.
Bài tập 2 — Thiết kế nhánh xử lý. Chọn một quy trình thực tế ở nơi bạn làm việc (hoặc một quy trình quen thuộc như đặt vé máy bay). Vẽ happy path, sau đó áp dụng quy trình sáu bước ở phần "Hướng dẫn từng bước" để bổ sung ít nhất một nhánh cho mỗi loại exception. Với nhánh human exception, hãy ghi rõ: nhắc sau bao lâu, leo thang sau bao lâu, leo thang cho ai.
Bài tập 3 — Phản biện một quy trình "im lặng". Tìm một quy trình trong tổ chức của bạn nơi exception đang được xử lý thủ công bằng Excel hoặc "gọi điện hỏi nhau". Viết một đoạn phân tích ngắn (200–300 từ) chỉ ra: exception đó thuộc loại nào, vì sao nó hiện đang bị "nuốt im", và bạn sẽ thiết kế lại như thế nào để hệ thống tự phát hiện và điều hướng.
Tóm tắt
Exception handling là phần phân biệt một quy trình nghiệp dư với một quy trình chuyên nghiệp. Happy path ai cũng vẽ được; bản lĩnh nằm ở chỗ bạn xử lý 20–40% trường hợp "có chuyện" ra sao.
Những điều cần khắc cốt ghi tâm:
- Ba loại exception, ba chiến lược khác nhau. Business exception (dữ liệu nghiệp vụ sai) cần gateway điều hướng hoặc vòng lặp bổ sung; System exception (lỗi kỹ thuật tạm thời) cần retry có giới hạn rồi fallback; Human exception (việc thủ công bị bỏ quên) cần reminder và escalation theo thời gian.
- Phân loại đúng nguồn gốc là chìa khóa. Sai lầm đắt giá nhất là gom mọi exception vào một "thùng rác lỗi" chung, khiến bạn không bao giờ xử lý đúng được loại nào.
- Không để exception rơi vào khoảng không. Mỗi exception phải có đích đến rõ ràng — quay lại, đi tiếp nhánh khác, hoặc dừng có thông báo.
- Human exception nguy hiểm vì nó im lặng. Hãy chủ động dùng Timer, SLA và escalation để biến sự im lặng thành tín hiệu hành động.
- Gán trách nhiệm và đo lường. Mỗi nhánh exception phải có người nhận thông báo, ngưỡng cảnh báo và số liệu theo dõi.