Domain Driven design - Tactical Design

Huy NguyenHuy Nguyen
6 min read

Trong buổi lần trước mình có chia sẻ về Strategic design, bước 1 trong DDD để xác định vấn đề mà hệ thống cần giải quyết. Còn trong bài này, mình sẽ tìm hiểu về bước 2 Tactical design: xác định được vấn đề rồi thì code như thế nào. Tactical design tương đối dài, bài đầu tiên mình muốn nói về những thứ cơ bản nhất trong bước này.

Domain model

  • Domain model được tạo ra nhằm mục đích dễ dàng đáp ứng với logic nghiệp vụ phức tạp và thay đổi theo thời gian.

  • Domain model cố gắng mô phỏng nghiệp vụ sao cho giống nhất có thể, từ sự thay đổi trạng thái của những đối tượng cho đến các business rules.

  • Domain model không mô phỏng các hành động CRUD mà các hành động và sự kiện trong nghiệp vụ thực tế. Ví dụ với hành động đặt vé xem phim trong hệ thống đặt vé phim, thì domain model biểu diễn usecase đó là BookingTicket chứ không phải CreateTicket. Điều này giúp code nhất quán trong nghiệp vụ và dễ bảo trì và mở rộng.

  • Domain model không chứa bất kì (hoặc rất ít) code liên quan đến infra như truy cập database hay message queue. Domain model chỉ thuần chứa nghiệp vụ, bao gồm dữ liệu (data) và hành vi (behavior)

Ubiquitous language

  • Là khái niệm cốt lõi trong DDD. Đây là một ngôn ngữ chung được tất cả các bên liên quan trong dự án (dev, test, BA, chuyên gia nghiệp vụ, và các bên liên quan khác).

  • Ubiquitous language sinh ra nhằm để giúp đội kĩ thuật và nghiệp vụ có thể giao tiếp và mô tả các khái niệm nghiệp vụ dễ dàng. Các khái niệm này sẽ được phản ánh trực tiếp trong code. Ví dụ một số thuật ngữ dùng chung trong một hệ thống đặt phòng khách sạn như là Booking (đặt phòng), Room (phòng), Reservation Status (trạng thái đặt phòng).

Các thành phần trong Domain model

Domain model bao gồm các thành phần được coi là những viên gạch trong domain driven design

Value object

  • Là đối tượng được sử dụng để biểu diễn các khái niệm không có danh tính riêng biệt mà chỉ được định nghĩa thông qua giá trị của chúng.

Tính chất

  • Value object không hề có định danh (id), ta chỉ quan tâm tới giá trị của chúng. Ví dụ hệ thống quản lí bán hàng của ta có 1 sản phẩm là cái áo đỏ, vậy thì đỏ ở đây là 1 value object, vì không thể có 2 màu đỏ giống nhau mà có 2 id khác nhau được.

  • Value object có tính bất biến (immutable): một khi value object được tạo ra thì sẽ không được thay đổi, nếu cần đổi thì phải tạo 1 object value mới.

  • Value object so sánh dựa trên giá trị, 2 value object có tất cả các thuộc tính bằng nhau thì sẽ bằng nhau.

  • Value object giúp tổ chức các kiểu dữ liệu nguyên thủy theo cách rõ ràng và ý nghĩa hơn.

    Article content

Khi nào nên dùng value object

  • Khi cần biểu diễn các khái niệm không có danh tính riêng biệt (như địa chỉ, tiền tệ, ngày tháng, khoảng cách...).

  • Khi một tập hợp các thuộc tính có thể nhóm lại để mang một ý nghĩa rõ ràng hơn, dễ phát triển và bảo trì.

  • Khi muốn đảm bảo tính bất biến và giảm thiểu lỗi thay đổi trạng thái.

Entity

  • Entity được sử dụng để biểu diễn các đối tượng có định danh (id) và tồn tại độc lập với các thuộc tính của chúng.

Đặc điểm

  • Một Entity được định danh bởi id, không phải bởi thuộc tính của nó. Ví dụ: Một khách hàng có thể thay đổi tên, địa chỉ, hoặc số điện thoại, nhưng danh tính của họ (ID) vẫn giữ nguyên.

  • Entity không chỉ chứa dữ liệu (trạng thái) mà còn có các hành vi (phương thức) để thao tác hoặc thay đổi trạng thái đó.

  • Entity thường đại diện cho các đối tượng thực tế trong business.

    Article content

Aggregate

  • Aggregate là một khái niệm cốt lõi trong DDD, dùng để mô hình hóa các nhóm đối tượng liên quan trong domain để đảm bảo tính nhất quán và kiểm soát tốt hơn các thao tác trên dữ liệu.

Đặc điểm của aggregate

  • Aggregate bao gồm một hoặc nhiều Entity và Value Object có quan hệ chặt chẽ với nhau. Ví dụ: Một Đơn hàng (Order) là một Aggregate bao gồm các Entity và Value Object như Thông tin khách hàng, Sản phẩm trong đơn hàng, và Tổng tiền.

  • Mỗi Aggregate có một thực thể chính gọi là Aggregate Root, chịu trách nhiệm kiểm soát và quản lý các đối tượng khác trong Aggregate. Chỉ Aggregate Root mới có thể được truy cập và sửa đổi trực tiếp từ bên ngoài Aggregate. Các thành phần khác trong Aggregate chỉ có thể được truy cập hoặc sửa đổi thông qua Aggregate Root.

  • Tất cả các quy tắc và logic nghiệp vụ liên quan đến Aggregate phải được thực thi trong ranh giới của nó gọi là Transaction Boundary. Khi nói đến sự nhất quán trong Aggregate tức nói đến Strong Consistency, 1 transaction trong aggregate phải đảm bảo thành công hoặc thất bại. Ví dụ Order aggregate bao gồm Order và OrderItem, thì khi tạo Order phải đảm bảo cả Order và OrderItem cùng được thực thi.

  • Có 2 tính chất đối lập trong aggregate là: contention >< consistency. Tức nếu aggregate to thì dễ đảm bảo tính nhất quán, nhưng cũng dễ xảy ra tranh chấp tài nguyên. Nếu aggregate nhỏ thì khó đảm bảo sự nhất quán hơn (strong consistency) nhưng lại giảm được sự tranh chấp tài nguyên.

    Article content

Khi nào nên dùng aggregate

  • Khi có nhiều đối tượng liên quan và cần được quản lý đồng thời để đảm bảo tính nhất quán.

  • Khi cần đảm bảo rằng các logic nghiệp vụ được thực thi chính xác trong một phạm vi cụ thể.

  • Khi muốn kiểm soát các thay đổi thông qua một thực thể duy nhất (Aggregate Root).

Nên thiết kế aggregate như thế nào

  • Aggregate không nên quá to hay nhỏ. Nếu logic nghiệp vụ cần đảm bảo sự nhất quán ngay lập tức (strong consistency) thì hãy đặt nó trong 1 aggregate

  • Với những sự nhất quán không cần đảm bảo real time (eventual consistency) như là đặt hàng xong mới gửi mail, thì có thể thiết kế thành nhiều Aggregate.

  • Sẽ có những ngoại lệ là một logic business cần Strong consistency nhưng để thiết kế 1 Aggregate bao trùm toàn bộ như vậy là quá to thì có thể tách Aggregate nhỏ hơn.

0
Subscribe to my newsletter

Read articles from Huy Nguyen directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Huy Nguyen
Huy Nguyen

I am a software engineer with 4 years of experience in developing web applications. My expertise lies in backend development, and I have a deep interest in problem-solving, algorithms, system design, and databases. I am always eager to learn and embrace challenging projects, striving to deliver applications that exceed user expectations. I also love sharing my knowledge and learning from others to foster mutual growth and improvement