[Microservices Series] Bài 2: DDD – Nghệ thuật "vẽ ranh giới" cho các Service
Chào anh em! Ở bài trước, mình đã nói Microservices là chia nhỏ để trị. Nhưng nếu bạn chia theo kiểu: Service User, Service Database, Service UI... thì đó là sai lầm chết người.
Trong Microservices, chúng ta không chia theo tầng kỹ thuật (Technical Layers), mà chia theo Nghiệp vụ (Business Domains). Và DDD (Domain-Driven Design) chính là "la bàn" để bạn không bị lạc lối.
1. Bounded Context: "Giang sơn" riêng của mỗi Service
Đây là khái niệm quan trọng nhất trong DDD. Hãy tưởng tượng trong hệ thống Metro của mình:
- Tại máy bán vé: "User" là một hành khách cần mua thẻ, quan tâm đến số dư và loại thẻ.
- Tại bộ phận nhân sự: "User" là một nhân viên vận hành, quan tâm đến bảng lương và ca trực
Nếu bạn gộp chung tất cả vào một Service User khổng lồ, code sẽ cực kỳ rác và rối. DDD bảo rằng: Hãy chia thành 2 vùng riêng biệt (Bounded Context). Service Bán vé chỉ giữ thông tin nó cần, Service Nhân sự giữ thông tin nó cần. Dù cùng gọi là "User" nhưng ngữ cảnh khác nhau, logic khác nhau.
2. Ubiquitous Language: Nói cùng một ngôn ngữ
Có bao giờ bạn (Dev) nói chuyện với sếp (Business) mà như "vịt nghe sấm" chưa?
- Sếp bảo: "Cần xử lý luồng hoàn tiền cho khách".
- Dev bảo: "Cần update status của transaction và gọi hàm RefundController".
DDD yêu cầu mọi người (từ Dev đến Business) phải dùng chung một bộ từ vựng (Ubiquitous Language). Nếu Business gọi là "Lượt quẹt thẻ", thì trong Code của bạn, class phải tên là TapEvent, database table phải là tap_events. Đừng tự đẻ ra những cái tên kỹ thuật xa lạ.
3. Aggregate: Đơn vị quản lý dữ liệu tối thiểu
Trong mỗi Service, bạn sẽ có rất nhiều Entity (đối tượng). Nhưng không phải cái nào cũng có thể gọi trực tiếp từ bên ngoài.
- Ví dụ: Một "Hóa đơn" (Invoice) sẽ có nhiều "Dòng chi tiết" (InvoiceItem).
- Aggregate bảo rằng: Bạn chỉ được tương tác với Invoice (gọi là Aggregate Root). Bạn không được phép sửa trực tiếp InvoiceItem mà không thông qua Invoice.
Việc xác định đúng Aggregate giúp bạn đảm bảo dữ liệu luôn nhất quán và không bị chồng chéo khi nhiều Service cùng hoạt động.
Kinh nghiệm thực chiến: Đừng quá "cuồng" DDD
DDD rất hay, nhưng nó cực kỳ tốn thời gian để họp hành và thống nhất.
- Với dự án nhỏ: Đừng dùng DDD làm gì cho mệt, cứ làm theo kiểu truyền thống cho nhanh.
- Với Microservices: Bạn bắt buộc phải hiểu ít nhất về Bounded Context để chia service. Nếu không, các service của bạn sẽ gọi nhau chéo ngoe (Circular Dependency) và bạn sẽ sớm "vỡ trận".
Tạm kết
DDD không phải là một bộ quy tắc cứng nhắc, nó là một tư duy thiết kế. Hãy tập trung vào việc hiểu nghiệp vụ của khách hàng trước khi đặt tay xuống gõ code. Khi bạn chia đúng "giang sơn" (Bounded Context), việc scale hệ thống hay thay đổi logic sau này sẽ nhẹ nhàng hơn rất nhiều.
Ở bài tiếp theo (Bài 3), mình sẽ hướng dẫn anh em cách "Chọn vũ khí". Tại sao trong một hệ thống Microservices, mình lại dùng Laravel cho chỗ này và Go cho chỗ kia? Sự kết hợp này mang lại sức mạnh gì?
Bạn đã từng nghe qua DDD chưa? Bạn thấy việc chia service theo Table Database và chia theo Business cái nào khó hơn? Comment nhé!
All Rights Reserved