Kiến trúc · Tiêu chí chia module · 20/7/2026

Phương pháp chia module là gì?MỚI

Trả lời câu hỏi: ranh giới một module đặt ở đâu, dựa trên tiêu chí nào? Rút tiêu chí đang dùng từ Sơ đồ WS/Module §0, rồi đối chiếu DDD · SAP · Dynamics 365 · Salesforce · Odoo · ERPNext. Bổ trợ cho Quan hệ module (bài đó bàn join chéo, bài này bàn đặt ranh giới).

0

"Chia module" ở đây nghĩa là gì

Hệ dùng cây phân rã 5 tầng. "Phương pháp chia module" = tiêu chí đặt ranh giới ở tầng Module — nằm giữa Workspace (pháp nhân) và Feature (nhóm quyền).

CONTROL PLANE ─► WORKSPACE ─► MODULE ─► FEATURE ─► BUSINESS OBJECT ─► ACTION nền tảng pháp nhân+DB đóng gói/bán nhóm quyền chứng từ/đối tượng thao tác ▲ ranh giới đang xét
1

Tiêu chí đang dùng (chốt trong Sơ đồ §0)

Module = đơn vị đóng gói – cài đặt – bán/license. Tách module khi thỏa một trong bốn điều kiện:

4 điều kiện tách

  • Bán riêng được theo gói (đơn vị license trong store)
  • Vòng đời nâng cấp riêng (release độc lập)
  • Người dùng chính khác nhau (kế toán ≠ giáo vụ ≠ kỹ thuật DAT)
  • Cài/gỡ độc lập — không làm hỏng module khác

Ràng buộc nền OpenGate

  • Mỗi WS = 1 DB chung mọi module
  • Module là gói .ogapp cài/gỡ rời — không ORM registry chung
  • Không FK cứng xuyên module — tham chiếu khóa nghiệp vụ
  • Manifest có depends + scopes

Bản chất

  • Ranh giới theo năng lực nghiệp vụ (business capability), không theo tầng kỹ thuật
  • Cộng thêm trục thương mại (đóng gói/bán) chồng lên trục cohesion thuần
  • Kết quả: 9 module MVP → 16 (v1.5) → 21 (v2), mỗi module = 1 đơn vị bán
2

Bốn trường phái chia module trên thế giới

Trường pháiĐại diệnRanh giới module dựa trênĐặc trưng
Bounded Context
DDD chiến lược (Evans/Fowler)
Lý thuyết nền cho hầu hết hệ hiện đại Năng lực nghiệp vụ + ngôn ngữ chung (ubiquitous language); "hành vi hơn dữ liệu, động từ hơn danh từ" Mỗi context có model + bảng + API riêng; phân biệt core / supporting / generic subdomain (lõi thì tự làm, generic thì mua)
Functional module
ERP cổ điển
SAP — FI, HR, SCM, CRM… Phân hệ chức năng theo phòng ban Bundled — mua gần như trọn gói, cấu hình phức tạp, tùy biến sâu
App theo năng lực,
chung nền tảng
Dynamics 365 (Sales/Finance/Supply Chain/HR trên Dataverse) · Salesforce clouds Business capability = app bán rời, dùng chung 1 data platform "Pick what you need"; Dynamics gộp nhiều tính năng vào base, Salesforce tính phí theo add-on
Modular monolith
+ depends graph
Odoo · ERPNext/Frappe 1 module = 1 mục đích duy nhất, xây tầng qua depends; tích hợp optional×optional bằng bridge module 1 DB + registry chung → join tự do; app = module; cài trước dependency
Điểm hội tụ của cả 4: module = một business capability, gắn với vòng đời / người dùng / gói bán riêng, cài–gỡ độc lập. Đây đúng bằng 4 điều kiện tách ở mục 1 → tiêu chí của hệ khớp đồng thuận quốc tế.
3

Hệ đang "lai" những gì (và làm đúng)

Phương pháp của hệ là hybrid có chủ đích — khớp từng mảnh với từng trường phái:

Trục thương mại → Dynamics/Salesforce

  • Module = app bán rời, chung 1 nền tảng (OpenGate ≈ Dataverse)
  • Bảng "9 MVP → 16 → 21" chính là gói bán theo tầng
  • Mỗi module = 1 đơn vị license trong store

Cơ chế → Odoo

  • depends xếp thứ tự cài
  • Bridge module/feature: hrm.timesheet-dat = dat+teacher+lms (đúng pattern P5)
  • Không FK cứng — tham chiếu khóa nghiệp vụ

Phân loại subdomain → DDD

  • Lõi khác biệt (dat, report tuân thủ Sở) → tự làm (core subdomain)
  • Generic (nhân sự, kế toán, CRM) → dùng built-in hrm/crm/finance thay vì tự viết
  • Đây là best practice nhiều dự án bỏ lỡ — hệ làm đúng (xem Quan hệ module §7)
4

Một điểm căng với DDD thuần — nợ kiến trúc cần ghi nhận

DDD nhấn mạnh ranh giới theo quy trình (hành vi), không theo đối tượng dữ liệu (danh từ). Cách chia hiện tại thiên về danh từ:

Cách hiện tại (chia theo danh từ/bảng — bám legacy QLHS V2, migrate 1:1): student course teacher vehicle dat │ │ │ │ │ └──── ma_dk,ma_kh,ma_gv,ma_xe ── callback dày đặc ────┘ (phải xây cả bộ P1–P6 để nối lại) Góc nhìn DDD (chia theo quy trình/hành vi): ┌─────────── ACADEMIC / TRAINING (1 bounded context) ───────────┐ │ student + course + enrollment + teacher-assignment │ ◄─ vòng đời "ghi danh→đào tạo" khép kín trong 1 context └───────────────────────────────────────────────────────────────┘ vehicle ── tài sản, vòng đời riêng → tách (đồng thuận) dat ── thiết bị thật, vòng đời riêng → tách (đồng thuận)
⚠️ Hệ quả: vòng đời "ghi danh–đào tạo" thực chất là một bounded context nhưng bị trải trên 4 module → sinh nhiều tham chiếu chéo + callback (chính là lý do phải xây cả bộ P1–P6). Đây không phải lỗi — bám legacy để migrate 1:1 là đánh đổi hợp lý cho MVP, đã bù bằng contract view + khóa nghiệp vụ. Nhưng là điểm nợ kiến trúc: nếu về sau callback student↔course↔enrollment quá dày, cân nhắc gộp lại theo quy trình thay vì bảng.
5

Kết luận một câu

Phương pháp chia module của hệ là "module = business capability × đơn vị đóng gói/bán, cài–gỡ độc lập" — một hybrid của DDD bounded context (cohesion) + mô hình app-trên-nền-tảng của Dynamics/Salesforce (ranh giới thương mại) + depends-graph & bridge của Odoo (cơ chế). Tiêu chí vững, khớp đồng thuận quốc tế; khác biệt duy nhất đáng theo dõi là chia theo danh từ/bảng (do bám legacy) thay vì theo quy trình như DDD thuần — đã có contract view che, ghi nhận là nợ kiến trúc.
6

Bổ sung 20/7 — ba nguyên tắc rút ra khi áp dụng

Rút từ hai ca thật: gộp student+course → training và câu hỏi có nên gộp thiết bị vào một module chung.

① Bất đối xứng gộp / tách

Gộp sớm rẻ và an toàn — tách sớm là đánh cược.

  • Gộp = bỏ một ranh giới chưa kiếm được chỗ đứng; sai thì tách lại trong cùng module rất rẻ
  • Tách = dựng ranh giới cho nhu cầu chưa xuất hiện; trả chi phí ngay (manifest, view, scopes, đọc chéo) để đổi lấy lợi ích còn là dự đoán
  • ⇒ Lý lẽ "chưa go-live nên sửa thoải mái" biện minh mạnh cho gộp, yếu cho tách

② Trọng số 4 điều kiện

Điều kiện ③ "người dùng chính khác nhau" là yếu nhất — gần như không bao giờ đủ để tách.

  • Tầng feature đã lo tách quyền theo người dùng rồi
  • Chỉ ① bán riêng · ② vòng đời riêng · ④ cài–gỡ độc lập mới là lý do tách thật

③ Chi phí ranh giới không đều

Trong OpenGate (không có ORM registry chung):

  • Ranh giới chỉ-đọc rẻ (P1 contract view)
  • Ranh giới ghi/callback đắt (P3 service API + outbox + job đối soát)
  • ⇒ Đặt ranh giới ở chỗ quan hệ chỉ-đọc; chỗ có callback hai chiều thì gộp. Guardrail: >2 callback P3 hoặc P3 hai chiều → vào diện review gộp
Nguyên tắc thứ tư — cái đắt khi tách muộn là logic quấn vào nhau, không phải tên bảng. Hệ quả thực dụng: module chưa đáng tách thì giữ bảng của nó "sạch" (không để nghiệp vụ domain lẫn vào bảng có thể tách), để sau này đổi prefix chỉ là thao tác cơ học. Đang áp cho dat_thiet_bi — xem Kiến trúc quản lý thiết bị §5.