Mở đầu — vì sao bài này quan trọng
Trong những bài trước, bạn đã học cách dùng từng "viên gạch" của BPMN: pool, lane, event, task, gateway, sequence flow, message flow, data object. Nói cách khác, bạn đã có đủ từ vựng. Nhưng có từ vựng không có nghĩa là viết được một câu văn hay. Tôi đã chấm hàng trăm sơ đồ BPMN do học viên và cả nhân viên ngân hàng, công ty sản xuất vẽ ra, và sự thật phũ phàng là: phần lớn lỗi không nằm ở chỗ "không biết ký hiệu", mà nằm ở chỗ ghép các ký hiệu đúng cú pháp lại với nhau theo một cách khiến sơ đồ trở nên sai về mặt logic, hoặc đúng nhưng không ai đọc nổi.
Đây chính là lý do bài học về anti-patterns (mẫu sai lặp đi lặp lại) tồn tại. Một anti-pattern không phải là một lỗi ngẫu nhiên — nó là một cách làm sai mà rất nhiều người mắc phải vì nó "trông có vẻ hợp lý". Khi bạn nhận diện được những mẫu sai này, bạn tiết kiệm được hàng giờ tranh cãi trong các buổi review, tránh được những sơ đồ bị từ chối khi đưa vào hệ thống automation (Camunda, Bizagi sẽ báo lỗi hoặc chạy sai), và quan trọng nhất: bạn xây được uy tín như một process analyst thực thụ chứ không phải người chỉ biết "vẽ hộp và mũi tên".
Bài này khác với Bài 2 (BPMN Notation) ở chỗ: Bài 2 dạy ký hiệu đúng là gì, còn Bài 29 dạy bạn cách người ta dùng sai ký hiệu đúng đó, và cách sửa.
Khái niệm cốt lõi
Tôi nhóm các anti-patterns BPMN thành bốn nhóm để bạn dễ nhớ: lỗi về độ phức tạp, lỗi về cú pháp dòng chảy, lỗi về logic gateway, và lỗi về ngữ nghĩa/diễn đạt.
Nhóm 1 — Sơ đồ quá lớn, quá rậm rạp
Đây là anti-pattern phổ biến nhất. Một sơ đồ có từ 50 element trở lên trên một trang là sơ đồ "không ai đọc được". Mắt người không xử lý nổi mật độ thông tin đó; người xem sẽ bỏ cuộc sau 10 giây. Quy tắc thực tế tôi khuyên dùng: nếu sơ đồ vượt quá 20–30 element trên một sheet, hãy refactor (tái cấu trúc) bằng cách gói các nhóm hoạt động liên quan vào sub-process (Bài 14). Sub-process cho phép bạn "thu gọn" (collapse) một cụm phức tạp thành một hình chữ nhật duy nhất ở level cao, rồi mở rộng chi tiết ở một sheet riêng. Đây là nguyên tắc phân tầng — gắn liền với process hierarchy bạn đã học ở Bài 8.
Một biến thể của lỗi này là "spaghetti diagram" — các sequence flow cắt chéo nhau loạn xạ vì người vẽ không sắp xếp lại layout. Dòng chảy BPMN nên đi theo hướng đọc tự nhiên: trái sang phải, trên xuống dưới. Khi mũi tên phải quặt ngược hoặc cắt qua nhau, đó là tín hiệu cần sắp xếp lại.
Nhóm 2 — Lỗi cú pháp dòng chảy (sequence flow vs message flow)
Đây là lỗi nghiêm trọng nhất về mặt kỹ thuật, vì nó làm sơ đồ sai theo đúng đặc tả BPMN 2.0, và engine sẽ từ chối.
Quy tắc bất di bất dịch: Sequence flow KHÔNG được vượt qua ranh giới pool. Sequence flow (mũi tên liền nét) chỉ biểu diễn thứ tự thực thi bên trong một participant. Khi hai participant (hai pool) trao đổi với nhau, bạn PHẢI dùng message flow (mũi tên nét đứt, đầu mũi tên rỗng). Lý do sâu xa: mỗi pool là một "process" độc lập với token riêng (bạn sẽ hiểu rõ token ở Bài 26). Token không "nhảy" giữa các pool — chúng giao tiếp bằng thông điệp. Vẽ một sequence flow nối từ task trong pool "Khách hàng" sang task trong pool "Ngân hàng" là sai hoàn toàn, dù phần mềm vẽ (như draw.io) có thể cho phép bạn làm vậy về mặt hình ảnh.
Ngược lại cũng đúng: dùng message flow giữa hai lane trong CÙNG một pool cũng sai. Các lane chỉ là phân vai trong cùng một process — chúng nối với nhau bằng sequence flow.
Nhóm 3 — Lỗi logic gateway
Gateway là nơi sản sinh nhiều lỗi tinh vi nhất:
- Gateway vừa làm việc vừa rẽ nhánh: Gateway là thuần túy điều khiển dòng chảy, nó KHÔNG thực hiện công việc. Viết "Kiểm tra hồ sơ" bên trong hình thoi gateway là sai. Việc kiểm tra phải là một task (hình chữ nhật) đặt TRƯỚC gateway; gateway chỉ rẽ nhánh dựa trên kết quả.
- Mở XOR nhưng đóng bằng AND (hoặc ngược lại): Khi bạn mở nhánh bằng Exclusive Gateway (XOR) thì chỉ một nhánh chạy; nếu đóng lại bằng Parallel Gateway (AND join), AND sẽ chờ TẤT CẢ các nhánh đến — nhưng chỉ có một nhánh từng chạy, nên token chờ mãi mãi. Process bị "deadlock" treo cứng. Quy tắc: mở bằng loại nào, gom lại nên cân nhắc đúng ngữ nghĩa loại đó.
- Gateway không có điều kiện hoặc thiếu nhánh default: Một XOR gateway mà các điều kiện không bao phủ hết mọi trường hợp sẽ khiến token "rơi vào hư không". Luôn có một nhánh default (mặc định) để hứng các trường hợp còn lại.
- Implicit gateway (gateway ngầm): Vẽ hai mũi tên đi ra trực tiếp từ một task mà không có gateway. BPMN coi đây là phân nhánh song song không điều kiện (uncontrolled flow) — gần như không bao giờ là điều bạn thực sự muốn. Luôn dùng gateway tường minh.
Nhóm 4 — Lỗi ngữ nghĩa và diễn đạt
- Event thiếu hoặc thừa: Mọi process phải có ít nhất một start event và một end event. Sơ đồ "lửng lơ" không có điểm bắt đầu/kết thúc rõ ràng là chưa hoàn chỉnh. Ngược lại, không nên có nhiều start event không cần thiết gây mơ hồ.
- Đặt tên kém: Task nên đặt tên theo công thức Động từ + Danh từ ("Phê duyệt khoản vay", "Gửi email xác nhận"), không phải danh từ trơ ("Khoản vay") hay câu mơ hồ ("Xử lý"). Event nên đặt tên theo trạng thái đã hoàn thành ("Hồ sơ đã nhận", "Đơn bị từ chối").
- Nhầm cấp độ chi tiết: Trộn lẫn hoạt động ở mức rất chi tiết ("Nhấn nút Submit") với mức rất cao ("Thẩm định tín dụng") trong cùng một sơ đồ. Mỗi sheet nên giữ một mức trừu tượng nhất quán.
Tình huống thực tế
Ví dụ 1 — Ngân hàng số tại TP.HCM và cú deadlock 0 đồng
Một ngân hàng số (tôi gọi là "Bank A") thuê đội ngũ ngoài vẽ quy trình mở thẻ tín dụng online để đưa vào Camunda. Sơ đồ có một XOR gateway tách thành hai nhánh: "Hồ sơ đầy đủ → thẩm định" và "Hồ sơ thiếu → yêu cầu bổ sung". Sau đó, người vẽ muốn gom hai nhánh lại nên dùng một Parallel Gateway (AND) để join. Khi deploy lên Camunda và chạy thử với 200 hồ sơ test, toàn bộ instance đều bị treo ở bước join — không hồ sơ nào hoàn tất.
Nguyên nhân: AND join chờ token từ CẢ HAI nhánh, nhưng vì mở bằng XOR nên mỗi instance chỉ đi một nhánh, token thứ hai không bao giờ tới. Process kẹt vĩnh viễn. Đội vận hành mất gần một ngày để truy ra, chi phí cơ hội ước tính hàng chục triệu đồng vì lùi lịch go-live.
Bài học: Khi mở bằng XOR, hãy gom lại bằng XOR (merge), không phải AND. Một merge XOR chỉ cần một token tới là cho đi tiếp. Đây là cặp lỗi "mở-đóng không khớp" kinh điển — và là lỗi mà engine sẽ trừng phạt ngay lập tức, không tha thứ như khi bạn chỉ vẽ trên giấy.
Ví dụ 2 — Công ty logistics và sơ đồ "120 hộp trên một trang"
Một công ty giao nhận quy mô vừa ở Bình Dương (gọi là "FastShip") muốn chuẩn hóa quy trình xử lý đơn hàng từ lúc khách đặt đến lúc giao thành công. Một bạn analyst hăng hái vẽ tất tần tật vào MỘT sơ đồ duy nhất: 6 lane, hơn 120 element, mũi tên cắt chéo như mạng nhện. Khi đem ra họp với 8 trưởng bộ phận để duyệt, không ai đọc được. Buổi họp 2 tiếng trôi qua trong tranh cãi vụn vặt, không chốt được gì.
Tôi tư vấn refactor theo phân tầng: tạo một sơ đồ Level cao chỉ gồm 5 sub-process lớn — "Tiếp nhận đơn", "Đóng gói", "Điều phối tuyến", "Giao hàng", "Đối soát". Mỗi sub-process được mở chi tiết ở một sheet riêng, mỗi sheet dưới 25 element. Lần họp sau, mỗi trưởng bộ phận chỉ review đúng sheet thuộc phạm vi của mình. Buổi duyệt rút còn 45 phút và chốt được.
Bài học: Sơ đồ là công cụ giao tiếp, không phải bằng chứng cho thấy bạn chăm chỉ. "Một sheet — một mức trừu tượng — dưới 30 element". Sub-process là người bạn thân nhất của bạn khi quy trình phình to.
Ví dụ 3 — Cú nối sai pool ở một fintech Đông Nam Á
Một startup fintech (gọi là "PayLink") vẽ quy trình thanh toán có hai pool: "Người dùng" và "Hệ thống PayLink". Bạn dev vẽ một mũi tên sequence flow liền nét nối thẳng từ task "Nhập mã OTP" (pool Người dùng) sang task "Xác thực OTP" (pool Hệ thống). Sơ đồ trông rất "mượt" trên Lucidchart. Nhưng khi import vào công cụ kiểm chuẩn BPMN, nó báo hàng loạt lỗi validation, và quan trọng hơn, nó che giấu một thiếu sót thực sự: trên thực tế, giữa hai bên có một bước truyền tin qua mạng (gửi OTP đi, nhận kết quả về) có thể thất bại, timeout.
Khi sửa lại đúng chuẩn — dùng message flow nét đứt giữa hai pool — đội ngũ buộc phải nghĩ đến: "Nếu message gửi đi mà không có hồi đáp trong 30 giây thì sao?". Câu hỏi đó dẫn tới việc bổ sung một boundary timer event (Bài 42) để xử lý timeout. Một lỗi cú pháp tưởng nhỏ, khi sửa đúng, lại lộ ra một lỗ hổng nghiệp vụ thật.
Bài học: Sequence flow không bao giờ vượt ranh giới pool. Ép mình dùng message flow đúng chỗ không chỉ là để "đúng chuẩn" — nó buộc bạn suy nghĩ về sự bất định của giao tiếp giữa các bên, vốn là nơi rủi ro thật sự ẩn nấp.
Hướng dẫn từng bước
Đây là quy trình "soát lỗi anti-pattern" tôi áp dụng mỗi khi nhận một sơ đồ BPMN để review. Bạn hãy biến nó thành checklist của riêng mình:
- Đếm element. Mở sơ đồ, đếm nhanh số hộp/sự kiện/gateway. Nếu vượt 30 trên một sheet, đánh dấu cần refactor thành sub-process trước khi xét tiếp.
- Soi từng đường nối cắt pool. Rà mọi mũi tên đi qua biên giới giữa hai pool. Mỗi đường như vậy BẮT BUỘC phải là message flow (nét đứt). Thấy sequence flow liền nét cắt pool → lỗi, sửa ngay.
- Kiểm tra start/end event. Đảm bảo có điểm bắt đầu và điểm kết thúc rõ ràng. Mỗi nhánh kết thúc đều phải dẫn tới một end event, không để mũi tên "cụt".
- Kiểm tra từng cặp gateway split–join. Với mỗi gateway mở nhánh, tìm gateway gom tương ứng và xác nhận ngữ nghĩa khớp nhau (XOR mở thì XOR/merge đóng; AND mở thì AND đóng). Đánh dấu mọi cặp lệch.
- Xác minh gateway không "làm việc". Đảm bảo mọi gateway chỉ rẽ nhánh. Nếu thấy động từ hành động bên trong hình thoi, tách nó ra thành task đặt trước gateway.
- Kiểm tra nhánh default của XOR. Với mỗi XOR data-based gateway, xác nhận các điều kiện bao phủ hết, và có một nhánh default để hứng phần còn lại.
- Soát tên gọi. Task theo công thức Động từ + Danh từ; event theo trạng thái đã hoàn thành. Sửa mọi tên mơ hồ.
- Kiểm tra mức trừu tượng nhất quán. Đảm bảo trong cùng một sheet không trộn lẫn hoạt động siêu chi tiết với hoạt động tổng quát.
Lỗi thường gặp & mẹo
- "Phần mềm cho phép nên chắc là đúng." Sai lầm chết người. draw.io, Lucidchart cho bạn nối sequence flow xuyên pool thoải mái vì chúng là công cụ vẽ tổng quát, không ép chuẩn BPMN nghiêm ngặt. Mẹo: nếu định đưa sơ đồ vào automation, hãy vẽ bằng công cụ có validation BPMN thật (Camunda Modeler, Bizagi) để nó bắt lỗi cho bạn.
- Lạm dụng Inclusive Gateway (OR). OR gateway mạnh nhưng logic gom (join) của nó phức tạp và dễ gây hiểu nhầm. Mẹo: nếu chỉ cần một-trong-nhiều, dùng XOR; nếu cần tất-cả-song-song, dùng AND. Chỉ dùng OR khi thật sự cần "một hoặc nhiều nhánh tùy điều kiện".
- Dùng màu sắc và icon tùy hứng. Có người tô màu hộp theo cảm xúc, làm người đọc tưởng màu mang ý nghĩa. Mẹo: nếu dùng màu, hãy có chú giải (legend) rõ ràng và nhất quán toàn dự án.
- Quên annotation cho phần khó hiểu. Khi một bước có logic nghiệp vụ đặc thù, đừng để người đọc đoán. Mẹo: dùng text annotation (Bài 20) để ghi chú ngắn gọn, nhưng đừng lạm dụng đến mức sơ đồ đầy chữ.
- Vẽ "happy path" rồi quên đường lỗi. Rất nhiều sơ đồ chỉ vẽ trường hợp mọi thứ suôn sẻ. Mẹo: với mỗi gateway, tự hỏi "nhánh xấu đi đâu?" để không bỏ sót xử lý ngoại lệ.
Bài tập thực hành
- Săn lỗi: Lấy một sơ đồ BPMN bất kỳ bạn từng vẽ (hoặc tìm một mẫu trên mạng) và chạy đủ checklist 8 bước ở trên. Ghi ra danh sách mọi anti-pattern bạn tìm thấy, phân loại theo 4 nhóm.
- Tự gây deadlock rồi sửa: Vẽ một quy trình "Duyệt đơn nghỉ phép" cố tình mở bằng XOR và đóng bằng AND. Mô tả bằng lời tại sao nó deadlock, rồi vẽ lại bản đúng.
- Refactor sơ đồ phình to: Cho một quy trình "Xử lý khiếu nại khách hàng" gồm 40 bước bạn tự liệt kê. Hãy nhóm chúng thành 4–5 sub-process ở Level cao, đảm bảo mỗi sub-process khi mở ra dưới 25 element.
- Sửa lỗi cắt pool: Vẽ tương tác giữa pool "Khách hàng" và pool "Cửa hàng online" cho quy trình đặt hàng, dùng đúng message flow ở mọi điểm giao tiếp, và thêm ít nhất một xử lý cho trường hợp thông điệp không được phản hồi.
Tóm tắt
Anti-patterns BPMN không phải lỗi vặt — chúng là những cái bẫy lặp đi lặp lại khiến sơ đồ của bạn hoặc sai về logic, hoặc đúng nhưng vô dụng vì không ai đọc nổi. Hãy nhớ bốn nhóm: (1) sơ đồ quá lớn — refactor bằng sub-process, giữ dưới 30 element/sheet; (2) lỗi dòng chảy — sequence flow không bao giờ vượt pool, message flow chỉ dùng giữa các pool; (3) lỗi gateway — gateway không làm việc, mở loại nào gom đúng ngữ nghĩa loại đó, luôn có nhánh default, đừng dùng gateway ngầm; (4) lỗi diễn đạt — đủ start/end event, đặt tên Động từ + Danh từ, giữ mức trừu tượng nhất quán.
Ba câu chuyện thực tế — cú deadlock 0 đồng ở Bank A, sơ đồ 120 hộp ở FastShip, và cú nối sai pool ở PayLink — đều cho thấy cùng một điều: một anti-pattern tưởng nhỏ trên giấy có thể biến thành chi phí thật khi đưa vào vận hành hoặc automation. Hãy biến checklist 8 bước thành thói quen, và bạn sẽ vẽ ra những sơ đồ mà cả engine lẫn con người đều đọc được. Ở bài tiếp theo, chúng ta chuyển sang đo độ trưởng thành của quy trình với mô hình CMMI.