Ngoại lệ trong DDD


11

Tôi đang học DDD và tôi đang nghĩ về việc ném ngoại lệ trong một số tình huống. Tôi hiểu rằng một đối tượng không thể chuyển sang trạng thái xấu nên ở đây các ngoại lệ đều ổn, nhưng trong nhiều ví dụ, ngoại lệ cũng được đưa ra nếu chúng ta đang cố gắng thêm người dùng mới với email tồn tại trong cơ sở dữ liệu.

public function doIt(UserData $userData)
{
    $user = $this->userRepository->byEmail($userData->email());
    if ($user) {
        throw new UserAlreadyExistsException();
    }

    $this->userRepository->add(
        new User(
            $userData->email(),
            $userData->password()
        )
    );
}

Vì vậy, nếu người dùng có email này tồn tại, thì trong dịch vụ ứng dụng chúng ta có thể bắt ngoại lệ, nhưng chúng ta không nên kiểm soát hoạt động của ứng dụng bằng cách sử dụng khối thử bắt.

Làm thế nào là cách tốt nhất cho việc này?


1
Có dịch vụ tên miền (xử lý) ném ngoại lệ là tốt.
Andy

Câu trả lời:


20

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 Usermô 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á Rulesgó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 EmailMustBeUnqiueRulesẽ đượ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ấtRulesra 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/ CommandHandlerném Exceptionlà 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 CommandHandlercầ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 ChangeEmailphươ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 Repositorycũ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 addphươ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 Userhệ 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.


Tôi có thể hỏi ý của bạn là Moving rules "upwards" is generally a sign of an anemic modelgì? Lên trên có nghĩa là lớp ứng dụng? hoặc cho mô hình miền?
Anyname Donotcare

1
Hướng lên trên có nghĩa là hướng tới lớp ứng dụng của bạn (nghĩ về kiến ​​trúc phân lớp). Tôi đã đề cập đến vấn đề này ở trên, nhưng lý do di chuyển các quy tắc lên trên là dấu hiệu của một mô hình thiếu máu là vì nó thể hiện sự phân tách dữ liệu và hành vi theo cách đánh bại toàn bộ mục đích của việc có một mô hình miền lõi. Nếu xác thực một email nằm trong một mô-đun riêng biệt hơn là gửi email, Emailmô hình của bạn phải là một túi dữ liệu được kiểm tra các bất biến trước khi gửi. Xem: softwareengineering.stackexchange.com/questions/372338/ Kẻ
vua trượt bên

2
Di chuyển tên miền logic sang kho lưu trữ là sai. bạn nên thực thi quy tắc miền bằng cách tổng hợp gốc trong lớp miền.
Arash

1
@Arash Đặt xác thực là khó khăn và thường không chơi tốt với DDD. Bạn có thể chọn xác nhận rằng một số quy trình sẽ hoạt động trước khi thử quy trình đó (thêm a User) hoặc chấp nhận rằng loại bất biến cụ thể này sẽ không được gói gọn trong miền của bạn. Cái trước đại diện cho một sự phân tách dữ liệu và hành vi dẫn đến một mô hình thủ tục. Điều này là ít hơn lý tưởng. Xác nhận nên tồn tại với dữ liệu, không phải xung quanh dữ liệu. Hơn nữa, có lợi ích gì khi tạo ra một dịch vụ tên miền chỉ phục vụ để kiểm tra quy tắc này? Rõ ràng, dịch vụ này ...
king-side-slide

1
@Arash kết hôn với bạn Repository, Uservà điều này bất biến và do đó không đạt được tầm nhìn thuần túy mà bạn đang thúc đẩy. Việc triển khai kho lưu trữ là một phần của miền và do đó có thể được giao một số trách nhiệm nhất định.
vua trượt bên

0

Bạn có thể áp đặt xác nhận trong mỗi lớp của ứng dụng của bạn. Nơi áp đặt các quy tắc phụ thuộc vào ứng dụng của bạn.

Ví dụ: các thực thể triển khai các phương thức thể hiện các quy tắc kinh doanh trong khi các trường hợp sử dụng thực hiện các quy tắc cụ thể cho ứng dụng của bạn.

Nếu bạn xây dựng một dịch vụ email như Gmail, người ta có thể lập luận rằng quy tắc "người dùng nên có một thư điện tử duy nhất" là một quy tắc kinh doanh.

Nếu bạn xây dựng quy trình đăng ký cho hệ thống CRM mới, quy tắc này có thể được triển khai tốt nhất trong trường hợp sử dụng vì quy tắc này cũng có thể là một phần của trường hợp sử dụng của bạn. Ngoài ra, nó cũng có thể dễ dàng hơn để kiểm tra vì bạn có thể dễ dàng thực hiện các cuộc gọi kho lưu trữ trong các bài kiểm tra ca sử dụng của mình.

Để bảo mật quảng cáo, bạn cũng có thể thực thi quy tắc này trong kho lưu trữ của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.