День 2310. #ЗаметкиНаПолях
Уходим от Анемичных Моделей. Пример DDD-Рефакторинга. Продолжение
Начало
Пошаговый рефакторинг
Цель здесь не в погоне за чистотой или академическим DDD. Она в постепенном улучшении связности и создании пространства для самовыражения домена. На каждом шаге мы спрашиваем: должно ли это поведение принадлежать домену? Если да, мы добавляем его внутрь домена.
Внедрение логики создания и проверки
Первый шаг — сделать агрегат ответственным за самосборку. Статический метод Create даёт нам единую точку входа, где все инварианты могут работать по принципу «fail fast».
Хотя добавление проверки остатков в Order улучшает тестируемость, оно связывает поток заказов с доступностью товаров на складе. В некоторых доменах лучше смоделировать это как событие домена и проверять асинхронно.
// Order.cs (Фабричный метод)
public static Order Create(
Customer customer,
IEnumerable<(Guid productId, int quantity)> lines,
IPricingService pricingService,
IInventoryService invService)
{
var order = new Order(customer.Id);
foreach (var (id, quantity) in lines)
{
if (invService.GetStock(id) < quantity)
throw new InvalidOperationException("Товара недостаточно");
var price = pricingService.GetPrice(id);
order.AddItem(id, quantity,
price, customer.IsVip);
}
order.EnsureCreditWithinLimit(customer);
return order;
}
Зачем мы это сделали?
Создание заказа теперь быстро завершается неудачей, если какой-либо инвариант нарушен. Сервис больше не занимается микроуправлением запасами или скидками.
Обратите внимание, как мы теперь следуем принципу «Скажи, не спрашивай». Вместо того, чтобы сервис проверял условия и затем манипулировал заказом, мы говорим заказу создать себя с необходимыми встроенными проверками. Это фундаментальный сдвиг в сторону инкапсуляции.
Замечание: О внедрении сервисов в методы домена
Передача сервисов, таких как IPricingService или IInventoryService, в метод домена, такой как Order.Create, на первый взгляд может показаться нетрадиционной и спорной. Но это осознанный выбор дизайна: он сохраняет оркестрацию внутри модели домена, где естественным образом находится бизнес-логика вместо того, чтобы раздувать сервис приложения процедурными рабочими процессами.
Такой подход сохраняет автономность сущности, при этом по-прежнему согласуясь с принципами внедрения зависимостей: зависимости передаются явно, а не разрешаются изнутри. Это мощный метод, но его следует использовать избирательно — только тогда, когда операция явно вписывается в сферу ответственности домена и выигрывает от прямого доступа к внешним сервисам.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/from-anemic-models-to-behavior-driven-models-a-practical-ddd-refactor-in-csharp
>>Click here to continue<<