Почнемо це з короткого огляду проблемного простору: Однією з основних принципів DDD є розміщення правил бізнесу якомога ближче до місць, де їх потрібно виконувати. Це надзвичайно важлива концепція, оскільки вона робить вашу систему "більш згуртованою". Переміщення правил «вгору», як правило, є ознакою анемічної моделі; де об'єкти - це лише пакети даних, і правила вводяться в ці дані для виконання.
Анемічна модель може створити багато сенсу розробникам, тільки починаючи з DDD. Ви створюєте User
модель та модель, EmailMustBeUnqiueRule
яка отримує необхідну інформацію для перевірки електронної пошти. Простий. Елегантний. Питання в тому, що такий "вид" мислення має принципово процедурний характер. Не DDD. Що в кінцевому підсумку відбувається, це те, що вам залишається модуль з десятками Rules
акуратно загорнутих і інкапсульованих, але вони повністю позбавлені контексту до того, що їх більше не можна змінити, оскільки не ясно, коли / де вони застосовуються. Чи має це сенс? Це може бути само собою зрозумілим , що EmailMustBeUnqiueRule
буде застосовуватися на створення User
, але як UserIsInGoodStandingRule
?. Повільно, але впевнено відбувається грануляризація вилученняRules
поза їх контексту залишає вас систему, яку важко зрозуміти (і тому її неможливо змінити). Правила слід інкапсулювати лише тоді, коли фактична хрускіт / виконання настільки багатослівна, що ваша модель починає втрачати фокус.
Тепер перейдемо до вашого конкретного питання: Проблема з Service
/ CommandHandler
киданням Exception
полягає в тому, що ваша логіка бізнесу починає просочуватися ("вгору") з вашого домену. Чому ваш Service
/ CommandHandler
потрібно знати електронний лист повинен бути унікальним? Службовий рівень додатків зазвичай використовується для координації, а не для реалізації. Причину цього можна проілюструвати просто, якщо ми додамо ChangeEmail
метод / команду до вашої системи. Тепер методи BOTH / обробники команд повинні включати ваш унікальний чек. Ось де розробник може спокуситись "витягти" EmailMustBeUniqueRule
. Як пояснено вище, ми не хочемо йти цим маршрутом.
Деякі додаткові скорочення знань можуть призвести до більш відповіді DDD. Унікальність електронної пошти - це інваріант, який потрібно застосовувати через колекцію User
об'єктів. Чи є у вашому домені концепція, яка представляє "колекцію User
об'єктів"? Я думаю, ти, певно, можеш побачити, куди я сюди їду.
У цьому конкретному випадку (і багато інших із залученням інваріантів у колекціях) найкраще місце для реалізації цієї логіки буде у вашому Repository
. Це особливо зручно, оскільки ви Repository
також "знаєте" додатковий фрагмент інфраструктури, необхідний для виконання такого виду перевірки (сховище даних). У вашому випадку я би помістив цю перевірку в add
метод. Це має сенс правильно? Концептуально саме цей метод справді додає User
вашій системі. Зберігання даних - це деталь реалізації.