Почнемо це з короткого огляду проблемного простору: Однією з основних принципів 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вашій системі. Зберігання даних - це деталь реалізації.