Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là một Business Analyst (BA) đang làm việc trong một dự án Agile. Sáng thứ Hai, product owner nhắn tin: "Anh vừa thêm một trường loyalty_points vào bảng khách hàng, em cập nhật ERD giúp nhé." Nếu ERD của bạn nằm trong một file .drawio hay một hình PNG xuất từ Lucidchart, bạn sẽ phải mở công cụ, kéo thả, căn chỉnh lại đường nối, rồi xuất ảnh mới, rồi upload lại vào tài liệu. Mười phút cho một thay đổi một dòng.
Bây giờ tưởng tượng ERD của bạn chỉ là một đoạn văn bản thuần. Bạn thêm đúng một dòng chữ, commit vào Git, và sơ đồ tự động render lại trong trang wiki của dự án. Đó chính là triết lý diagram as code — sơ đồ như mã nguồn — và Mermaid là công cụ phổ biến nhất hiện nay để làm điều đó.
Ở các bài trước trong khóa học, bạn đã học về entity, attribute, quan hệ, cardinality và ba mô hình dữ liệu (conceptual, logical, physical). Bài 16 giới thiệu các công cụ ERD dạng kéo-thả như Lucidchart và dbdiagram. Bài 43 này bổ sung một kỹ năng khác hẳn về bản chất: viết ERD bằng văn bản và để máy tự vẽ. Đây là kỹ năng ngày càng bắt buộc với BA hiện đại, vì phần lớn tài liệu kỹ thuật ngày nay sống trong Git, Markdown, Confluence và Notion — những nơi mà Mermaid được hỗ trợ sẵn.
Khái niệm cốt lõi
Mermaid là gì?
Mermaid là một thư viện JavaScript mã nguồn mở, cho phép bạn mô tả sơ đồ bằng cú pháp văn bản đơn giản (giống Markdown), rồi trình duyệt hoặc công cụ sẽ render (dựng hình) thành sơ đồ trực quan. Bạn không kéo thả bất cứ thứ gì; bạn chỉ gõ chữ.
Mermaid hỗ trợ nhiều loại sơ đồ: flowchart (lưu đồ), sequence diagram (sơ đồ tuần tự), class diagram (sơ đồ lớp), state diagram, Gantt chart, và quan trọng với chúng ta — entity relationship diagram (ERD). Trong bài này ta chỉ tập trung vào loại ERD.
Điểm mấu chốt khiến Mermaid khác biệt so với Lucidchart hay draw.io: sơ đồ của bạn là text, không phải là một tệp nhị phân. Text thì:
- Version control được: bạn thấy rõ dòng nào thay đổi trong
git diff. - Diff được trong code review: đồng nghiệp review đúng phần thay đổi thay vì phải so hai tấm ảnh.
- Sống chung với tài liệu: nhúng trực tiếp vào file Markdown, README, Confluence, Notion, GitLab/GitHub wiki.
- Sinh tự động được: có thể để một script hoặc AI sinh ra đoạn Mermaid từ mô tả nghiệp vụ.
Cú pháp ERD trong Mermaid
Một sơ đồ ERD trong Mermaid luôn bắt đầu bằng từ khóa erDiagram. Cấu trúc cơ bản có hai phần: khai báo quan hệ giữa các entity, và khai báo thuộc tính bên trong mỗi entity.
Khai báo quan hệ có dạng:
erDiagram
CUSTOMER ||--o{ ORDER : places
Đọc dòng này như một câu tiếng Anh: "CUSTOMER places ORDER". Phần ký hiệu ở giữa (||--o{) chính là cardinality theo ký pháp Crow's Foot mà bạn đã học ở Bài 8. Cụ thể:
||nghĩa là "một và chỉ một" (exactly one).o{nghĩa là "không hoặc nhiều" (zero or many).- Ghép lại: một CUSTOMER có thể có 0 hoặc nhiều ORDER, và mỗi ORDER thuộc về đúng một CUSTOMER.
| Ký hiệu | Ý nghĩa | ||
|---|---|---|---|
\ | o / o\ | Zero hoặc one | |
\ | \ | Exactly one (một và chỉ một) | |
}o / o{ | Zero hoặc many | ||
}\ | / \ | { | One hoặc many |
--) và non-identifying (không định danh, vẽ nét đứt ..). Quan hệ identifying nghĩa là entity con không thể tồn tại nếu thiếu entity cha (thường là weak entity).Khai báo thuộc tính đặt trong dấu ngoặc nhọn ngay sau tên entity:
erDiagram
CUSTOMER {
int customer_id PK
string full_name
string email UK
date created_at
}
Mỗi dòng gồm kiểu dữ liệu (int, string, date...), tên thuộc tính, tùy chọn key (PK cho primary key, FK cho foreign key, UK cho unique key), và tùy chọn một comment trong dấu ngoặc kép ở cuối.
Một sơ đồ hoàn chỉnh trông như thế nào
Đây là một ERD nhỏ mô tả quan hệ khách hàng — đơn hàng — sản phẩm, viết hoàn toàn bằng Mermaid:
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ ORDER_ITEM : contains
PRODUCT ||--o{ ORDER_ITEM : "appears in" CUSTOMER {
int customer_id PK
string full_name
string phone UK
}
ORDER {
int order_id PK
int customer_id FK
datetime ordered_at
decimal total_amount
}
ORDER_ITEM {
int order_id FK
int product_id FK
int quantity
}
PRODUCT {
int product_id PK
string name
decimal price
}
Chỉ với đoạn text trên, bất kỳ công cụ hỗ trợ Mermaid nào cũng dựng ra một ERD đầy đủ với bốn entity, khóa chính, khóa ngoại và ba quan hệ có cardinality rõ ràng.
Tình huống thực tế
Tình huống 1 — Fintech Việt Nam đưa ERD vào Git
Một công ty fintech ở TP.HCM (giả định tên VíMoMo, khoảng 40 kỹ sư) gặp vấn đề kinh điển: tài liệu thiết kế cơ sở dữ liệu luôn lỗi thời. Team backend dùng Lucidchart để vẽ ERD, nhưng mỗi lần schema đổi, không ai nhớ cập nhật ảnh. Sau ba tháng, ERD trong Confluence còn thiếu tới 12 bảng so với thực tế.
BA của dự án đề xuất chuyển toàn bộ ERD sang Mermaid, lưu trong chính repository backend, ngay cạnh code migration. Mỗi khi có pull request thay đổi database, quy ước mới bắt buộc là file docs/erd.md cũng phải được cập nhật trong cùng PR đó. Reviewer sẽ thấy ngay trong git diff: nếu code thêm bảng wallet_transaction mà file Mermaid không có, PR bị chặn.
Sau một quý, độ lệch giữa ERD và schema thực tế gần như bằng không. Bài học rút ra: sức mạnh lớn nhất của Mermaid không nằm ở việc vẽ đẹp, mà ở chỗ nó biến sơ đồ thành một phần của quy trình code review — thứ mà công cụ kéo-thả không bao giờ làm được. Với BA, đây là cách buộc tài liệu và thực tế đi cùng nhịp.
Tình huống 2 — Startup e-commerce ĐNA giải thích schema cho stakeholder
Một startup thương mại điện tử tại Singapore mở rộng sang thị trường Việt Nam. BA cần trình bày mô hình dữ liệu phần "chương trình khách hàng thân thiết" (loyalty) cho ba nhóm: kỹ sư, phòng marketing và giám đốc vận hành. Nếu vẽ physical model đầy đủ với 20 bảng, nhóm marketing sẽ hoảng.
BA quyết định viết hai bản Mermaid từ cùng một nguồn. Bản conceptual chỉ có ba entity MEMBER, POINTS_LEDGER, REWARD với quan hệ đơn giản, không thuộc tính — dùng khi họp với marketing và giám đốc. Bản logical/physical đầy đủ khóa và kiểu dữ liệu — dùng khi làm việc với kỹ sư. Vì cả hai đều là text, BA chỉ cần copy đoạn nào cần vào slide hoặc email, không phải mở công cụ đồ họa nào.
Khi giám đốc hỏi "một thành viên có thể có nhiều thẻ reward không?", BA sửa một ký hiệu ||--o{ ngay trong buổi họp trên màn hình chia sẻ, render lại tức thì, cả phòng thấy ngay tác động. Bài học rút ra: vì Mermaid render nhanh và sửa dễ, nó cực kỳ hợp cho việc thảo luận trực tiếp — biến ERD từ tài liệu tĩnh thành công cụ đối thoại. Bạn có thể chuyển đổi nhanh giữa các mức trừu tượng cho từng đối tượng người nghe.
Tình huống 3 — Ngân hàng cập nhật ERD trong tài liệu bàn giao
Một BA freelance làm cho một ngân hàng ở Hà Nội, phụ trách module quản lý hồ sơ tín dụng. Tài liệu bàn giao (handover) được viết bằng Markdown trong Azure DevOps Wiki, vốn hỗ trợ Mermaid sẵn. Trong quá trình phân tích, yêu cầu thay đổi tới bốn lần: ban đầu một khách hàng chỉ có một hồ sơ tín dụng, sau đó nghiệp vụ cho phép nhiều hồ sơ, rồi thêm entity guarantor (người bảo lãnh), rồi tách collateral (tài sản đảm bảo) thành bảng riêng.
Vì ERD là text nhúng thẳng trong tài liệu, mỗi lần đổi BA chỉ sửa vài dòng và lịch sử wiki tự lưu lại toàn bộ quá trình tiến hóa. Khi có tranh cãi "tại sao lại tách bảng collateral", BA mở lịch sử phiên bản, chỉ ra đúng commit và ghi chú yêu cầu tương ứng. Bài học rút ra: khi ERD là code, nó thừa hưởng toàn bộ hạ tầng version control — lịch sử, blame, review — biến việc truy vết quyết định thiết kế thành chuyện đơn giản. Đây là lợi thế lớn cho các dự án có yêu cầu audit như ngân hàng.
Hướng dẫn từng bước
Dưới đây là quy trình thực tế để tạo một ERD bằng Mermaid từ đầu.
Bước 1 — Chọn nơi render. Trước khi viết, xác định công cụ sẽ hiển thị sơ đồ. Ba lựa chọn phổ biến:
- Mermaid Live Editor (mermaid.live) — trình soạn thảo online, gõ bên trái thấy sơ đồ bên phải, dùng để thử nghiệm và xuất PNG/SVG.
- Nền tảng tài liệu hỗ trợ sẵn: GitHub, GitLab, Notion, Azure DevOps Wiki, Obsidian. Chỉ cần đặt code trong khối
`mermaid. - Confluence/Jira: cần cài plugin Mermaid (nhiều bản không có sẵn), nên kiểm tra trước.
Bước 3 — Vẽ quan hệ và xác định cardinality. Nối các entity bằng cú pháp A ||--o{ B : verb. Với mỗi quan hệ, tự hỏi hai câu: "Một A có tối thiểu và tối đa bao nhiêu B?" và ngược lại. Câu trả lời quyết định ký hiệu Crow's Foot. Đặt tên quan hệ bằng động từ (places, contains, owns) để sơ đồ đọc được thành câu.
Bước 4 — Bổ sung thuộc tính và key. Khi khung quan hệ đã ổn, thêm khối { } cho từng entity. Nhớ đánh dấu PK, FK, UK. Thêm comment cho các trường không rõ nghĩa, ví dụ string status "PENDING|APPROVED|REJECTED".
Bước 5 — Render, kiểm tra, tinh chỉnh. Dán vào công cụ và xem kết quả. Nếu sơ đồ rối, cân nhắc tách thành nhiều sơ đồ nhỏ theo domain thay vì một sơ đồ khổng lồ.
Bước 6 — Đưa vào version control. Lưu file .md chứa Mermaid vào Git cạnh code hoặc trong repo tài liệu. Từ đây, mọi thay đổi đều được diff và review như code.
Lỗi thường gặp & mẹo
Lỗi 1 — Đọc ngược cardinality. Đây là lỗi phổ biến nhất. Ký hiệu ở đầu gần entity nào thì mô tả entity đó. Trong CUSTOMER ||--o{ ORDER, ký hiệu || sát CUSTOMER nói "mỗi ORDER thuộc đúng một CUSTOMER", còn o{ sát ORDER nói "mỗi CUSTOMER có 0 hoặc nhiều ORDER". Nhiều người mới đọc lộn phía. Mẹo: luôn đọc thành câu hai chiều để tự kiểm tra.
Lỗi 2 — Không xử lý quan hệ many-to-many. Mermaid không có ký hiệu vẽ trực tiếp M:N một cách "tự động phân rã". Giống như trong mô hình quan hệ thật (Bài 7), bạn phải tự tạo bảng nối (junction/associative table). Đừng cố nối STUDENT }o--o{ COURSE rồi để đó — hãy tạo ENROLLMENT ở giữa với hai khóa ngoại.
Lỗi 3 — Tên có dấu cách hoặc tiếng Việt gây lỗi cú pháp. Tên entity và quan hệ có dấu cách phải để trong dấu ngoặc kép, ví dụ PRODUCT ||--o{ ORDER_ITEM : "appears in". Với tên entity, nên dùng gạch dưới (ORDER_ITEM) thay vì dấu cách. Tránh dấu tiếng Việt trong tên kỹ thuật để đảm bảo render ổn định trên mọi nền tảng.
Lỗi 4 — Sơ đồ quá lớn, không đọc nổi. Mermaid tự động sắp xếp bố cục (auto-layout), và với hơn 15–20 entity, bố cục có thể rối như tơ vò, đường nối chồng chéo. Đây cũng là giới hạn so với Lucidchart nơi bạn kiểm soát vị trí từng box. Mẹo: chia theo bounded context — vẽ ERD riêng cho từng miền nghiệp vụ (thanh toán, kho, người dùng), rồi có một sơ đồ tổng quan mức cao.
Mẹo 1 — Dùng AI để sinh bản nháp. Bạn có thể mô tả nghiệp vụ bằng lời và nhờ AI sinh ra đoạn Mermaid, sau đó tự rà lại cardinality. Vì đầu ra là text, việc kiểm tra và sửa rất nhanh — đây chính là lý do Mermaid hợp với quy trình có AI hỗ trợ.
Mẹo 2 — Giữ một "nguồn sự thật" duy nhất. Đừng vừa có ERD Mermaid vừa có ảnh Lucidchart cho cùng một thứ; chúng sẽ lệch nhau. Chọn Mermaid làm nguồn chính khi bạn cần tài liệu sống trong Git.
Mẹo 3 — Thêm chú thích bằng comment. Dòng bắt đầu bằng %% là comment, không render. Dùng để ghi chú ngữ cảnh cho người đọc code Mermaid.
Bài tập thực hành
Đề bài: Một trung tâm tiếng Anh tại Đà Nẵng cần mô hình dữ liệu cho hệ thống quản lý lớp học. Nghiệp vụ như sau:
- Mỗi học viên (
STUDENT) có thể ghi danh vào nhiều lớp (CLASS); mỗi lớp có nhiều học viên. - Mỗi lớp do đúng một giảng viên (
TEACHER) phụ trách; một giảng viên dạy nhiều lớp. - Mỗi lớp có nhiều buổi học (
SESSION); mỗi buổi thuộc đúng một lớp. - Cần lưu điểm danh: mỗi buổi học ghi nhận việc mỗi học viên có mặt hay không.
- Xác định các entity, trong đó có ít nhất hai bảng nối để xử lý quan hệ many-to-many (ghi danh và điểm danh).
- Viết ERD hoàn chỉnh bằng Mermaid với đúng cú pháp
erDiagram, có khóa chính (PK), khóa ngoại (FK), và cardinality Crow's Foot. - Dán vào mermaid.live để kiểm tra render.
erDiagram
STUDENT ||--o{ ENROLLMENT : registers
CLASS ||--o{ ENROLLMENT : has
TEACHER ||--o{ CLASS : teaches
CLASS ||--|{ SESSION : contains
SESSION ||--o{ ATTENDANCE : records
STUDENT ||--o{ ATTENDANCE : "is marked in"
Hãy tự bổ sung phần thuộc tính cho từng entity (ví dụ ENROLLMENT có enrolled_at, ATTENDANCE có is_present boolean), rồi so sánh với cách bạn từng vẽ cùng bài toán này bằng công cụ kéo-thả. Bạn mất bao lâu để thay đổi khi trung tâm bổ sung yêu cầu "một buổi học có thể do giảng viên khác dạy thay"?
Tóm tắt
- Mermaid là thư viện JavaScript cho phép viết sơ đồ bằng văn bản (diagram as code); với ERD, bạn bắt đầu bằng
erDiagram. - Cú pháp gồm hai phần: quan hệ (
A ||--o{ B : verb) với ký hiệu Crow's Foot, và thuộc tính trong khối{ }vớiPK/FK/UK. - Sức mạnh cốt lõi: ERD trở thành text, nên version control được, diff được, review được trong Git, và sống chung với tài liệu Markdown/Confluence/Notion.
- Ba tình huống thực tế cho thấy Mermaid giúp giữ tài liệu đồng bộ với schema, hỗ trợ đối thoại trực tiếp với stakeholder, và truy vết lịch sử quyết định thiết kế.
- Lưu ý các bẫy: đọc ngược cardinality, quan hệ M:N phải tự tạo bảng nối, tên có dấu cách phải để trong ngoặc kép, và sơ đồ quá lớn thì nên chia nhỏ theo miền nghiệp vụ.
- Với BA hiện đại, Mermaid không thay thế hoàn toàn Lucidchart hay draw.io (Bài 16), mà là lựa chọn tối ưu khi bạn cần tài liệu sống, nhẹ, và tích hợp vào quy trình phát triển phần mềm.