Business Analyst

Phân tích quy trình (Process Modeling): Kỹ thuật vẽ BPMN và sơ đồ luồng dữ liệu (Data Flow) để tối ưu vận hành

7/19/2026 · 12p đọc

Sau buổi hỏi "5 Whys" với chị Lan Anh, Minh đã có thứ mình cần: vấn đề thật không phải "thiếu một cái app", mà là Serene Hotels đang chảy máu 15-20% doanh thu mỗi đặt phòng cho hoa hồng OTA, và không sở hữu một dòng dữ liệu khách hàng nào để bán thêm dịch vụ. Nhưng biết vấn đề là một chuyện — biết chính xác quy trình hiện tại đang vận hành ra sao, và quy trình mới cần thay đổi ở đâu, lại là chuyện khác.

Minh mang câu hỏi này ra hỏi Huy — Tech Lead của dự án: "Nếu Reso xử lý đặt phòng thay cho lễ tân, luồng dữ liệu sẽ đi qua đâu?" Huy trả lời đúng một câu khiến Minh khựng lại: "Vẽ ra đi, rồi mình cùng xem có khớp với PMS không." Minh nhận ra: mình đang nói về một quy trình mà chưa ai trong phòng từng vẽ nó ra giấy — kể cả quy trình cũ đang chạy mỗi ngày ở 5 khách sạn.

Đây là lúc lý thuyết suông dừng lại và tay phải cầm bút (hoặc chuột) lên vẽ.

Sự thật cơ bản (First Principle)

Một quy trình không được vẽ ra và nhìn thấy rõ ràng thì không thể tối ưu được — con người không thể cải thiện thứ họ không nhìn thấy dưới dạng cụ thể.

Nghe có vẻ hiển nhiên, nhưng phần lớn các dự án thất bại ở đúng chỗ này. Khi Minh hỏi lễ tân ở khách sạn Đà Nẵng "quy trình xác nhận đặt phòng diễn ra thế nào?", câu trả lời là một đoạn mô tả rời rạc: "thì khách gọi, em check phòng, rồi báo lại email". Nghe thì hợp lý, nhưng nó bỏ sót ít nhất ba câu hỏi sống còn: check ở đâu, ai xác nhận cuối cùng, và nếu hai khách cùng chọn một phòng trong 10 phút thì ai thắng?

Ngôn ngữ nói che giấu độ phức tạp thật. Một sơ đồ buộc bạn phải trả lời từng nhánh rẽ, từng vai trò, từng điểm dữ liệu đi vào đi ra — không có chỗ để mơ hồ. Đây chính là lý do BPMN (Business Process Model and Notation — ký hiệu mô hình hóa quy trình nghiệp vụ) và Data Flow Diagram (DFD — sơ đồ luồng dữ liệu) tồn tại: không phải để "làm đẹp tài liệu", mà để ép cả đội — BA, khách hàng, dev — nhìn cùng một bức tranh và cãi nhau (nếu có) về cùng một chi tiết cụ thể, thay vì cãi nhau về những gì mỗi người tưởng tượng trong đầu.

Phân tích

Minh bắt tay vẽ quy trình đặt phòng hiện tại của Serene Hotels trước, dựa trên phỏng vấn lễ tân ba khách sạn (Đà Nẵng, Hội An, Đà Lạt). Quy trình lộ ra như sau:

  1. Khách liên hệ qua điện thoại hoặc nhắn tin qua OTA (Booking.com, Agoda...).
  2. Lễ tân mở hệ thống PMS (Property Management System — hệ thống quản lý vận hành khách sạn) nội bộ, tìm phòng trống bằng cách nhìn qua lịch đặt phòng thủ công.
  3. Lễ tân báo giá miệng hoặc qua email, khách xác nhận lại.
  4. Lễ tân cập nhật trạng thái phòng trên PMS sau khi đã báo giá — có độ trễ vài phút đến vài giờ.
  5. Nếu hai khách hỏi cùng một phòng trong khoảng trễ đó → double-booking, lễ tân phải gọi lại xin lỗi một trong hai khách.

Khi vẽ ra thành sơ đồ, ba lỗ hổng hiện rõ ngay lập tức mà nghe kể miệng sẽ không thấy: (a) bước kiểm tra phòng trống là thủ công, phụ thuộc trí nhớ/mắt nhìn của lễ tân — đây là nguồn gốc double-booking; (b) không có bước nào tự động đồng bộ trạng thái phòng theo thời gian thực; (c) toàn bộ dữ liệu khách hàng (số điện thoại, sở thích, lịch sử) nằm rải rác trong email/tin nhắn, không tập trung — đúng như vấn đề cốt lõi ban giám đốc Serene đang lo.

Từ đây, Minh phác thảo quy trình mới với Reso: khách vào thẳng Reso → Reso gọi API kiểm tra phòng trống real-time (thời gian thực) từ PMS → hệ thống xác nhận tự động tức thì, không qua con người trung gian. Về lý thuyết, quy trình mới giải quyết gọn cả ba lỗ hổng trên.

Nhưng có một cái bẫy: Minh suýt đưa thẳng ý tưởng "hiển thị giá phòng real-time trên Reso" vào tài liệu yêu cầu — nghe rất hợp lý, vì đây là chuẩn ngành. Nếu Minh không dừng lại đọc tài liệu API của PMS trước khi viết yêu cầu này, anh sẽ đề xuất một tính năng không thể làm được với hệ thống hiện tại của Serene. Đây chính là lát cắt quan trọng nhất của bài này.

Đọc hiểu API Document & Database Schema cơ bản

Đây là kỹ năng phân biệt một BA "chỉ ghi lại lời khách nói" với một BA "hiểu được giới hạn kỹ thuật thật sự" — và đây là kỹ năng khiến Minh trở thành người đội Dev tin tưởng, thay vì người đội Dev phải sửa lưng.

Huy gửi cho Minh tài liệu API của PMS mà Serene đang dùng. Minh không cần biết viết code gọi API đó — nhưng anh bắt buộc phải đọc hiểu được ba thứ:

1. Endpoint và ý nghĩa nghiệp vụ của nó. Ví dụ tài liệu có endpoint GET /rooms/availability — Minh cần hiểu đây là API trả về tình trạng phòng, không phải để đặt phòng (đặt phòng là endpoint khác, POST /bookings).

2. Các trường dữ liệu (fields) trong response. Đây là phần quan trọng nhất. Khi đọc response mẫu, Minh thấy các trường như:

  • room_status — trạng thái phòng (available/occupied/maintenance)
  • rate_plan_id — mã gói giá áp dụng, không phải giá cuối cùng
  • booking_reference — mã tham chiếu đặt phòng để đối chiếu ngược lại PMS
  • last_synced_atthời điểm dữ liệu này được đồng bộ lần cuối

Chính trường cuối cùng last_synced_at là chi tiết cứu Minh khỏi một sai lầm lớn. Khi hỏi Huy, Minh phát hiện: PMS của Serene chỉ đồng bộ giá phòng (rate) một lần mỗi ngày (batch job chạy lúc 2h sáng), trong khi trạng thái phòng trống thì đồng bộ gần như real-time (mỗi 5 phút). Nếu Minh không đọc kỹ tài liệu API và cứ ghi thẳng yêu cầu "hiển thị giá phòng real-time" vào tài liệu, đội Dev hoặc sẽ phải báo lại giữa sprint là "không làm được", hoặc tệ hơn — cứ làm theo và Reso hiển thị giá sai lệch so với PMS, gây tranh cãi với khách khi thanh toán.

3. Status code và ý nghĩa khi có lỗi. Ví dụ 409 Conflict khi hai request đặt cùng một phòng cùng lúc — đây chính là cơ chế PMS dùng để chống double-booking, và Minh cần đưa case này vào gateway quyết định trong sơ đồ BPMN quy trình mới.

Song song đó, Huy đưa cho Minh sơ đồ Database Schema (lược đồ cơ sở dữ liệu) đơn giản của PMS — không phải để Minh viết SQL, mà để hiểu quan hệ giữa các bảng dữ liệu chính:

  • Bảng Rooms (phòng) — mỗi phòng có một room_id (khóa chính).
  • Bảng Bookings (đặt phòng) — mỗi đặt phòng có room_id (khóa ngoại, trỏ về bảng Rooms) và guest_id (khóa ngoại, trỏ về bảng Guests). Một phòng có thể có nhiều bản ghi Bookings theo thời gian (quan hệ 1-nhiều).
  • Bảng Guests (khách hàng) — thông tin khách, một khách có thể có nhiều Bookings (quan hệ 1-nhiều).
  • Bảng Rates (bảng giá) — gắn với rate_plan_id, độc lập với trạng thái phòng — đây chính là lý do giá và trạng thái phòng đồng bộ ở hai tần suất khác nhau, chúng nằm ở hai luồng dữ liệu tách biệt trong hệ thống.

Chỉ cần hiểu quan hệ 1-nhiều này, Minh nhận ra ngay: dữ liệu khách hàng (Guests) mà Serene đang thiếu để "chăm sóc/bán thêm dịch vụ" thực ra đã tồn tại sẵn trong PMS — vấn đề không phải là "không có dữ liệu", mà là dữ liệu đó chưa bao giờ được đồng bộ ra một nơi Serene có thể chủ động khai thác (vì trước giờ khách đặt qua OTA, OTA giữ luôn thông tin khách). Đây là insight Minh sẽ cần dùng lại ở bài phân tích dữ liệu sau này.

Giải pháp

Để biến quan sát trên thành tài liệu mà cả khách hàng (chị Lan Anh) và đội kỹ thuật (Huy) đều đọc hiểu được, Minh dùng hai công cụ song song:

A. BPMN — ký hiệu cơ bản cần nắm (không cần học hết chuẩn đầy đủ, 5 ký hiệu này là đủ cho 90% trường hợp BA gặp):

Ký hiệu Hình dạng Ý nghĩa
Start Event Vòng tròn viền mảnh Điểm bắt đầu quy trình (vd: "Khách mở app Reso")
Task/Activity Hình chữ nhật bo góc Một hành động cụ thể (vd: "Kiểm tra phòng trống")
Gateway (quyết định) Hình thoi (◇) Điểm rẽ nhánh có điều kiện (vd: "Còn phòng trống?")
End Event Vòng tròn viền đậm Điểm kết thúc quy trình (vd: "Xác nhận đặt phòng thành công")
Swimlane Dải ngang/dọc Phân vai trò — mỗi vai trò (Khách, Reso, PMS, Lễ tân) một làn riêng, task nằm trong làn của ai thực hiện task đó

B. Data Flow Diagram — 4 thành phần cần phân biệt:

  • Nguồn/Đích dữ liệu (hình chữ nhật) — ai gửi/nhận dữ liệu (vd: Khách, PMS).
  • Luồng dữ liệu (mũi tên có nhãn) — dữ liệu gì di chuyển (vd: "yêu cầu kiểm tra phòng trống").
  • Tiến trình xử lý (hình tròn/bo góc) — nơi dữ liệu được biến đổi (vd: "Reso xử lý yêu cầu đặt phòng").
  • Kho lưu trữ dữ liệu (hai đường thẳng song song) — nơi dữ liệu được lưu lại (vd: bảng Bookings trong PMS).

Quy trình đọc nhanh một API document khi vào dự án mới (áp dụng lại được cho mọi hệ thống, không riêng PMS):

  1. Tìm mục "Endpoints" hoặc "Resources" — liệt kê xem hệ thống có những "cửa" nào để lấy/gửi dữ liệu.
  2. Với mỗi endpoint cần dùng, đọc kỹ request fields (cần gửi gì) và response fields (nhận lại gì) — đặc biệt chú ý các trường timestamp kiểu last_synced_at, updated_at vì chúng tiết lộ tần suất cập nhật thật của dữ liệu.
  3. Đọc bảng status code — nắm ít nhất 3 mã: thành công (2xx), lỗi do dữ liệu đầu vào (4xx, vd 409 Conflict), lỗi hệ thống (5xx).
  4. Hỏi ngay Tech Lead một câu duy nhất nếu tài liệu không ghi rõ: "Trường X này cập nhật bao lâu một lần?" — đây là câu hỏi cứu cả dự án khỏi cam kết sai với khách hàng.

Quy trình đọc nhanh Database Schema:

  1. Xác định các bảng "thực thể chính" (Rooms, Bookings, Guests, Rates) trước khi quan tâm bảng phụ.
  2. Với mỗi bảng, chỉ cần biết khóa chính (primary key — định danh duy nhất của bảng) và khóa ngoại (foreign key — trường trỏ sang bảng khác).
  3. Xác định quan hệ là 1-1, 1-nhiều hay nhiều-nhiều — vì điều này quyết định một nghiệp vụ có khả thi hay không (vd: "một khách có nhiều đặt phòng" là 1-nhiều, nên tính năng "lịch sử đặt phòng của khách" là khả thi vì dữ liệu đã có sẵn cấu trúc để truy vấn).

📎 Actionable Template

Template 1 — Sơ đồ BPMN mô tả bằng văn bản (quy trình CŨ vs MỚI của Reso):

QUY TRÌNH CŨ — Đặt phòng thủ công qua Lễ tân
════════════════════════════════════════════

Swimlane: KHÁCH
  [Start] Khách gọi điện / nhắn OTA
     │
     ▼
Swimlane: LỄ TÂN
  [Task] Mở PMS, xem lịch đặt phòng thủ công
     │
     ▼
  ◇ [Gateway] Còn phòng trống theo mắt nhìn?
     │ Có                    │ Không
     ▼                       ▼
  [Task] Báo giá qua      [Task] Báo hết phòng
  điện thoại/email           │
     │                       ▼
     ▼                    [End] Từ chối khách
  [Task] Khách xác nhận lại (có độ trễ)
     │
     ▼
  [Task] Cập nhật trạng thái phòng trên PMS
     │
     ▼
  ◇ [Gateway] Phòng đã bị đặt trong lúc trễ?
     │ Không                 │ Có (double-booking)
     ▼                       ▼
  [End] Xác nhận thành công  [Task] Gọi lại xin lỗi khách
                                 │
                                 ▼
                             [End] Xử lý khiếu nại


QUY TRÌNH MỚI — Đặt phòng tự động qua Reso
════════════════════════════════════════════

Swimlane: KHÁCH
  [Start] Khách mở Reso, chọn phòng + ngày
     │
     ▼
Swimlane: RESO (hệ thống)
  [Task] Gọi API GET /rooms/availability tới PMS
     │
     ▼
Swimlane: PMS
  [Task] Trả về room_status real-time (theo last_synced_at ~5 phút/lần)
     │
     ▼
Swimlane: RESO
  ◇ [Gateway] room_status = "available"?
     │ Có                          │ Không
     ▼                             ▼
  [Task] Hiển thị giá theo      [Task] Hiển thị "Hết phòng"
  rate_plan_id (đồng bộ 1 lần/ngày)  │
     │                              ▼
     ▼                          [End] Khách chọn phòng khác
  [Task] Khách xác nhận & thanh toán
     │
     ▼
  [Task] Gọi API POST /bookings tới PMS
     │
     ▼
Swimlane: PMS
  ◇ [Gateway] Response = 409 Conflict?
     │ Không (201 Created)         │ Có
     ▼                             ▼
  [Task] Tạo booking_reference   [Task] Reso báo khách chọn lại
  trong bảng Bookings               │
     │                              ▼
     ▼                          [End] Quay lại bước chọn phòng
  [End] Xác nhận tức thì, không qua con người

Template 2 — Bảng tóm tắt các trường dữ liệu cần hỏi đội kỹ thuật PMS (dùng khi bắt đầu tích hợp bất kỳ hệ thống nào, không riêng Reso):

Trường dữ liệu Thuộc bảng/API nào Câu hỏi cần hỏi Tech Lead/đội PMS Trả lời thực tế (case Reso)
room_status GET /rooms/availability Đồng bộ bao lâu một lần? ~5 phút/lần — đủ nhanh để coi là "real-time"
rate_plan_id / giá GET /rooms/availability Giá có đồng bộ real-time không hay theo batch? Batch 1 lần/ngày lúc 2h sáng — KHÔNG thể hiển thị "giá real-time"
booking_reference POST /bookings response Dùng để đối chiếu ngược PMS khi khách khiếu nại, format ra sao? Mã dạng chuỗi 10 ký tự, unique theo booking
409 Conflict POST /bookings status code Khi nào trả về, Reso cần xử lý UX ra sao? Khi 2 request đặt cùng phòng cùng thời điểm — Reso phải báo khách chọn lại ngay
Guests (bảng) Database Schema Dữ liệu khách hàng từ OTA có được lưu vào bảng này không? KHÔNG — OTA giữ riêng, đây chính là lỗ hổng dữ liệu Serene đang thiếu

🧠 Tư duy phản biện: Khách hàng nói muốn "giá phòng hiển thị real-time giống mấy app lớn" — nhưng nếu PMS chỉ đồng bộ giá 1 lần/ngày, thứ họ thực sự cần có phải là "giá luôn đúng và nhất quán" chứ không phải "giá cập nhật từng giây"? Bạn có đang lẫn lộn giữa "công nghệ nghe hay" và "yêu cầu thật sự khả thi" trong chính tài liệu bạn sắp viết?

🔗 Case Study & Bài viết liên quan

Đây là một chương trong hành trình xuyên suốt 12 bài phân tích dự án Reso của Minh — nếu bạn mới bắt đầu theo dõi, nên đọc lại Kỹ năng "Đặt câu hỏi" (The Art of Questioning) để hiểu vì sao vấn đề OTA/direct booking lộ ra trước khi Minh bắt tay vẽ sơ đồ ở bài này.

Việc vẽ được hai quy trình cũ-mới rõ ràng mới chỉ là bước xác định "hệ thống sẽ vận hành ra sao" — câu hỏi tiếp theo Minh phải trả lời là "khách hàng thực sự cần Reso làm được điều gì trong đời sống của họ", điều mà BPMN một mình không trả lời được.


Bài trước: Kỹ năng "Đặt câu hỏi" (The Art of Questioning) · Bài tiếp theo: Thấu hiểu người dùng với Jobs-to-be-Done

Phân tích quy trình (Process Modeling): Kỹ thuật vẽ BPMN và sơ đồ luồng dữ liệu (Data Flow) để tối ưu vận hành