ERD vẽ tay là nợ kỹ thuật trá hình
ERD vẽ tay trông đẹp lúc đầu, nhưng lệch khỏi schema thật sau mỗi migration. Để schema tự sinh tài liệu là cách thực tế hơn — docs sống cùng code, không chết dần.
Table of Contents
Hi friend! 👋
Lần đầu mở một codebase lạ, mình được “onboard” bằng một file PNG: ERD của database. Hộp ngay ngắn, mũi tên thẳng tắp, màu sắc đồng bộ. Mình dùng nó làm bản đồ suốt hai tuần.
Rồi một hôm trace quan hệ từ orders sang payments — phát hiện mũi tên ấy trỏ tới một cột đã không tồn tại từ bốn migration trước. Bản đồ đẹp đấy. Chỉ là vẽ sai đường từ lâu rồi.
📖 Nói nhanh cho bạn chưa quen:
ERD giống bản đồ gia phả của database: bảng nào nối bảng nào, quan hệ cha-con ra sao. Còn schema — cấu trúc thật của database (bảng, cột, khoá, ràng buộc) — chính là sự thật. Vẽ ERD bằng tay giống viết gia phả bằng tay: đúng lúc viết, nhưng mỗi lần schema đổi mà sơ đồ không cập nhật, cuốn gia phả dần thành tiểu thuyết.
Tài liệu chết vì đứng ngoài quy trình
Một tài liệu database thường chết theo ba bước rất quen thuộc:
- Ban đầu, ai đó vẽ ERD trong Miro, Draw.io, Excel, Notion hoặc một file PNG rất đẹp.
- Sau đó, team thay đổi schema qua migration, ORM hoặc SQL script.
- Cuối cùng, không ai cập nhật sơ đồ vì việc đó không nằm trong flow review, không có test fail, không có CI nhắc, cũng không ảnh hưởng trực tiếp đến deploy.
Và thế là tài liệu bắt đầu nói dối.
Tài liệu thủ công không hỏng ngay. Nó hỏng từ từ, nên team thường phát hiện quá muộn.
Điều nguy hiểm không phải thiếu tài liệu. Thiếu thì ai cũng cảnh giác. Điều nguy hiểm là có một tài liệu trông đáng tin nhưng đã lệch khỏi hệ thống thật. Nó khiến người mới hiểu sai quan hệ bảng. Nó khiến BA và dev tranh luận trên một hình ảnh cũ. Nó khiến reviewer bỏ sót một foreign key quan trọng vì sơ đồ đẹp quá — chỉ là không còn đúng nữa.
Nếu một tài liệu không được sinh ra từ source of truth, nó sẽ phải cạnh tranh với source of truth. Và nó sẽ thua.
Đừng chăm viết docs hơn — hãy giảm quyền nói dối của docs
Phản xạ phổ biến khi docs lệch schema là kêu gọi kỷ luật: “Từ nay nhớ cập nhật tài liệu sau khi sửa database.”
Nghe thì đúng. Nhưng trong phần mềm, “nhớ làm” là một cơ chế yếu. Mình đã thấy cái vòng này lặp lại ở nhiều nơi: vẽ tay rồi lệch, kêu “nhớ cập nhật” rồi chẳng ai nhớ — và nó cứ kéo dài âm thầm cho tới lúc một người mới hiểu sai quan hệ bảng. Những thứ quan trọng không nên phụ thuộc vào trí nhớ và thiện chí. Chúng nên nằm trong pipeline.
Mình thích cách nghĩ này hơn:
Nếu schema đổi, tài liệu phải đổi. Nếu tài liệu không đổi, CI nên làm team khó chịu.
Nghĩa là đảo lại vai trò: sơ đồ không còn là một artifact thủ công đứng bên cạnh code. Sơ đồ trở thành output của code — schema-driven.
🔧 Bắt đầu setup
Liam ERD là công cụ, nhưng ý tưởng mới là phần quan trọng
Liam ERD không chỉ hấp dẫn vì nó render ERD đẹp. Phần đáng giá hơn là nó đối xử với database schema như đầu vào, rồi sinh ra một giao diện có thể tìm kiếm, zoom, filter và highlight quan hệ.
Với public repo, mình mở schema trực tiếp qua URL dạng liambx.com/erd/p/.... Với private repo hoặc CI/CD, mình dùng CLI build ERD thành static site.
npx @liam-hq/cli erd build --input ./path/to/schema.sql --format postgresCâu lệnh trên không quan trọng bằng việc: từ đây trở đi, sơ đồ có thể được sinh lại bất cứ khi nào schema đổi. Không cần mở tool, không cần kéo thả, không cần export PNG, cũng không cần hy vọng ai đó nhớ cập nhật nữa.
PNG không đủ cho database lớn
Một bức ảnh ERD tĩnh có thể ổn với 12 bảng. Nhưng khi hệ thống lên 80, 100, 150 bảng, ảnh tĩnh bắt đầu phản bội người đọc.
Kích thước chưa phải vấn đề chính. Vấn đề là khả năng đặt câu hỏi.
- Bảng
ordersliên quan trực tiếp đến những bảng nào? - Quan hệ giữa
users,roles,permissionsđi qua bảng trung gian nào? - Có bảng nào trở thành “God table” vì quá nhiều bảng phụ thuộc vào nó không?
- Migration mới vừa thêm quan hệ nào vào vùng billing?
Ảnh tĩnh không trả lời tốt các câu hỏi đó. Một ERD tương tác thì có cơ hội.
Search, filter, zoom, highlight không phải “nice to have”. Với database lớn, chúng là điều kiện để sơ đồ còn hữu ích.
CI mới là nơi tài liệu nên sống
Một command chạy local chỉ là demo. Quy trình thật phải nằm trong CI.
Ví dụ với tbls, mình sinh schema.json từ database, rồi để Liam ERD build giao diện tương tác từ file đó. Phần YAML cụ thể mình để ở sample repo cuối bài, không nhồi vào đây. Điều quan trọng là bức tranh lớn:
Code tạo schema. Schema tạo docs. Docs quay lại phục vụ review, onboarding và vận hành.
Với team khác, output có thể được publish lên GitHub Pages, Cloudflare Pages, S3 hoặc attach link preview vào pull request. Cách triển khai có thể đổi. Nguyên tắc không nên đổi: schema thay đổi thì tài liệu phải được máy sinh lại.
🎯 Bài này hữu ích nếu bạn:
| Bạn là… | Áp dụng để… |
|---|---|
| Dev mới onboarding | Hiểu flow nghiệp vụ mà không phải đọc 40 migration |
| Reviewer / Tech lead | Kiểm tra foreign key trên schema thật, không phải ảnh cũ |
| BA | Thấy dữ liệu nghiệp vụ chia ở đâu, nối ở đâu — không cần biết SQL |
| Ai chạy AI agent | Cung cấp schema thật làm context đáng tin cho LLM |
Vì tài liệu database, nói cho cùng, là giao diện giao tiếp — không phải bản vẽ kỹ thuật.
Một schema thật, nhiều đối tượng cùng đọc được theo nhu cầu của họ.
Giữa dev với dev, nó giảm thời gian đoán. Giữa dev với BA, nó tạo ra một hình ảnh chung. Giữa dev với AI, nó còn quan trọng hơn.
LLM không thiếu khả năng viết code. Nó thiếu context đáng tin. Nếu mình chỉ prompt “viết API tạo order”, AI sẽ đoán. Nếu mình đưa vào schema thật, constraints thật, quan hệ thật, nullable fields thật — nó có cơ hội viết code gần hệ thống của mình hơn.
Đó là lý do output như schema.json, markdown docs từ tbls, hoặc ERD sinh từ Liam không chỉ phục vụ con người. Chúng là nguồn context tốt cho AI agent: audit schema, phát hiện thiếu index, giải thích quan hệ bảng, gợi ý refactor query.
Một tài liệu tốt trong thời AI không chỉ để đọc. Nó phải có thể được máy tiêu thụ.
✅ Checklist áp dụng ngay:
- Lấy schema của một dự án đang có, quăng vào Liam ERD (5 phút)
- Thêm bước sinh
schema.jsonvào CI mỗi khi merge migration - Publish ERD tương tác lên GitHub Pages / Cloudflare Pages
- Attach link preview ERD vào template pull request
- Bỏ hẳn ERD vẽ tay khỏi quy trình review
💡 Đúc kết:
Schema đổi, tài liệu phải đổi. Tài liệu không đổi, CI nên làm team khó chịu.
Nếu bạn muốn xem stack này hoạt động trong một project Laravel thực tế, tham khảo sample repo này:
Hi friend! Câu hỏi đúng không phải “Ai sẽ cập nhật ERD sau sprint này?” — mà là “Vì sao ERD không tự cập nhật khi schema đổi?”. Nếu bạn cũng đang duyệt tài liệu thủ công, hoặc có cách giữ database docs sống gọn hơn — chia sẻ với mình nhé. Mình luôn muốn học thêm từ kinh nghiệm của bạn.
Mở terminal, lấy schema của dự án hiện tại, quăng vào Liam ERD. Nếu sơ đồ khiến bạn thấy hệ thống rối hơn bạn tưởng, đó không phải lỗi của công cụ. Đó là lần đầu tiên hệ thống đang nói thật với bạn.
Hẹn gặp lại ở bài sau! 👋