Chúng ta hãy bắt đầu điều này bằng một đánh giá ngắn về không gian vấn đề: Một trong những nguyên tắc cơ bản của DDD là đặt các quy tắc kinh doanh càng sát càng tốt đến những nơi cần thực thi. Đây là một khái niệm cực kỳ quan trọng vì nó làm cho hệ thống của bạn trở nên "gắn kết" hơn. Di chuyển quy tắc "lên trên" nói chung là một dấu hiệu của một mô hình thiếu máu; trong đó các đối tượng chỉ là các túi dữ liệu và các quy tắc được đưa vào với dữ liệu đó sẽ được thi hành.
Một mô hình thiếu máu có thể có nhiều ý nghĩa đối với các nhà phát triển chỉ mới bắt đầu với DDD. Bạn tạo một User
mô hình và một mô hình EmailMustBeUnqiueRule
được cung cấp thông tin cần thiết để xác thực email. Đơn giản. Thanh lịch. Vấn đề là "loại" suy nghĩ này về cơ bản là mang tính thủ tục. Không phải DDD. Điều cuối cùng xảy ra là bạn bị bỏ lại một mô-đun với hàng tá Rules
gói gọn gàng và được đóng gói gọn gàng, nhưng chúng hoàn toàn không có bối cảnh đến mức chúng không thể thay đổi được nữa vì không rõ ràng khi nào / nơi chúng được thi hành. Điều đó có ý nghĩa? Có thể là hiển nhiên rằng một EmailMustBeUnqiueRule
sẽ được áp dụng vào việc tạo ra một User
, nhưng những gì về UserIsInGoodStandingRule
? Dần dần nhưng chắc chắn, sự hạt hóa của chiết xuấtRules
ra khỏi bối cảnh của họ để lại cho bạn một hệ thống khó hiểu (và do đó không thể thay đổi). Các quy tắc chỉ nên được gói gọn khi thực hiện crunching / thực tế quá dài đến nỗi mô hình của bạn bắt đầu mất tập trung.
Bây giờ với câu hỏi cụ thể của bạn: Vấn đề với việc có Service
/ CommandHandler
ném Exception
là logic kinh doanh của bạn đang bắt đầu rò rỉ ("trở lên") ra khỏi miền của bạn. Tại sao Service
/ bạn CommandHandler
cần biết một email phải là duy nhất? Lớp dịch vụ ứng dụng thường được sử dụng để phối hợp thay vì thực hiện. Lý do cho điều này có thể được minh họa đơn giản nếu chúng ta thêm một ChangeEmail
phương thức / lệnh vào hệ thống của bạn. Bây giờ, cả hai phương thức / trình xử lý lệnh sẽ cần bao gồm kiểm tra duy nhất của bạn. Đây là nơi mà một nhà phát triển có thể bị cám dỗ để "giải nén" EmailMustBeUniqueRule
. Như đã giải thích ở trên, chúng tôi không muốn đi theo con đường đó.
Một số kiến thức bổ sung giòn có thể dẫn chúng ta đến một câu trả lời DDD hơn. Tính duy nhất của một email là một bất biến phải được thi hành trên một bộ sưu tập các User
đối tượng. Có một khái niệm trong miền của bạn đại diện cho một "bộ sưu tập các User
đối tượng" không? Tôi nghĩ rằng bạn có thể thấy nơi tôi sẽ đến đây.
Đối với trường hợp cụ thể này (và nhiều hơn nữa liên quan đến việc thực thi bất biến trên các bộ sưu tập), nơi tốt nhất để thực hiện logic này sẽ nằm trong của bạn Repository
. Điều này đặc biệt thuận tiện vì bạn Repository
cũng "biết" phần cơ sở hạ tầng bổ sung cần thiết để thực hiện loại xác nhận này (kho lưu trữ dữ liệu). Trong trường hợp của bạn, tôi sẽ đặt kiểm tra này trong add
phương pháp. Điều này có ý nghĩa phải không? Về mặt khái niệm, chính phương pháp này thực sự bổ sung một User
hệ thống của bạn. Các cửa hàng dữ liệu là một chi tiết thực hiện.