Re[12]: DDD для небольших проектов.
От: Poopy Joe Бельгия  
Дата: 14.02.20 14:05
Оценка: 12 (1)
Здравствуйте, Sinclair, Вы писали:

PJ>>Какая разница? Это BL.

S>Нууу, как же — большая разница.
Очень информативно.

S>Ну, вот у нас уже получилось 8 типов заказа — ровно 2-в-степени-количество-степеней-свободы.

Тут ровно две степени сводобы оплачен или нет. Все остальные типы завсисимые.

S>И эта модель у нас теряет информацию: после отправки у нас уже нет никаких данных о том, был ли заказ оплачен. Ну, то есть наверное можно попробовать это починить, добавив в ShippedOrder и DeliveredOrder свойство Order по образцу ShippableOrder. Но не факт, что этого достаточно: если мы хотим потребовать платёж-при-получении от наших Shippable(UnpaidOrder), то как будет выглядеть сигнатура конструктора DeliveredOrder?

Это все зависит от того как это системой обрабатывается. Можно при создании ShippableOrder создавать еще и PaymentRequest и обрабатывать его отдельно, позваляя, например, переводить деньги на счет. С собственно доставкой эта операция не больно-то связана. Не обязательно все валить в одну кучу.

S>Надо полагать, будет что-то типа

S>
S>        public DeliveredOrder(ShippedPaidOrder order){} // тут paymentInfo и так есть
S>        public DeliveredOrder(ShippedUnpaidOrder order, PaymentInfo paymentInfo){} // а тут надо её предоставить
S>

S>Может, я чего-то не понимаю, но у нас только что класс ShippedOrder развалился надвое. А заодно придётся развалить пополам и класс ShippableOrder.
В каком, прости, месте? И в том, и в другом случае ты создаешь тип одын штука.

S>Итого — уже 10 классов. И это мы ещё не начали думать о возвратах. Либо мы переносим данные из статического типа в динамическое состояние — как вы поступили с ShippableOrder.

Да хоть 110. Ты это говоришь с таким придыханим, как будь-то у тебя количество типов чем-то ограничено. А куда ты поместишь код когда начнешь думать о возвратах? В астрал?

S>Теперь, чтобы узнать, нуждается ли ShippableOrder в оплате, придётся делать рантайм-анализ:

S>
S>var paymentInfo = (shippableOrder.Order is PaidOrder paidOrder) ? paidOrder.PaymentInfo : UI.RequestPaymentInfo();
S>

Детали реализации. Может да, может нет. Никто не мешает имееть структуру Tuple<ShippedOrder, PaymentRequest> Все эти типы можно как угодно массировать до получения полного удовлетворения и уверенност, что вот сейчас все так как ты и хотел.

PJ>>А я показал, что это не так.

S>Пока что вы подтверждаете мои опасения.
Разве что конструкторы считать "разваливанием класса на два"

S>Ну как же. Вот у вас почти у всех ордеров есть конструкторы. Вы их так пишете, как будто достаточно перечислить аргументы, и всё заработает. Ну дак ведь нет — надо же весь этот бойлерплейт писать руками:

S>
S>public ValidOrder(NotEmptyList<Article> articles, Address address, Customer customer, StockReference reference)
S>{
S>  Articles = articles ?? throw new ArgumentNullException(nameof(articles));
S>  Address = address ?? throw new ArgumentNullException(nameof(address));
S>  Customer = customer ?? throw new ArgumentNullException(nameof(customer));
S>  Reserved = reference ?? throw new ArgumentNullException(nameof(reference)); 
S>}
S>

Не надо. C# поддерживает nullable reference types.
Если ты хочешь наехать на бойлерплейт в C#, то есть куда более болезенные места. Например, дефолтный equality comparer, который проверяет ссылку, отсутствие ADT, нормальной композии и убогий паттерн-матчинг.
Но так все это одинаково справедливо хоть с DDD, хоть без. C# это путь боли. Но это ж добровольный выбор.

S>При этом компилятор всё ещё ни за чем из этого не следит — я могу запросто забыть проинициализировать свойство в конструкторе, и оно прекрасно останется null. В итоге код компилируется, хотя и падает при первом же юнит тесте.

Следит. Хотя пока в виде варнинга, но варнинги можно и как ошибки поставить.

PJ>>Так мне тоже, но вот ты, не стесняясь, требуешь примеров кода, хотя на них времени надо больше, чем на просто текст.

S>К сожалению, без кода вести технические дискуссии бессмысленно.
Уж точно бессмысленно требовать от других, не показывая свой. Гораздо больше хочется помочь человеку, который действительно прилагает усилия понять и что-то сделать.

PJ>>Это никакого отношения к DDD не имеет. Никто не запрещает далать любые оптимизации. DDD запрещает делать их из модели, поскольку они относятся к деталям бд, от которой не зависит бизнес-логика.

S>Ну ок. Модель — это, вроде бы, entities. Агрегаты в вашей версии DDD есть? Или нету?
Эээ...?! Модель это модель. В DDD есть value objects, то у чего нет ID. Адрес например. Entities — то, у чего есть ID. Иначе говоря разные инстансы могут ссылаться на одну entity. И агрегаты — коллекции entities. В данном пример customer, article это, очевидно, ссылки на них. Так что order это агрегат и есть.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.