Domain Driven Design на практике


Download 333.79 Kb.
bet2/2
Sana23.04.2023
Hajmi333.79 Kb.
#1384601
1   2
Bog'liq
Domain Driven Design на практике

var priceInfos = DbContext
.CompanyData
.ByInn("инн")
.ToList();

Альтернативный вариант — использовать SelectMany.

var priceInfos = DbContext
.Company
// имеется в виду другой extension-метод с подходящей сигнатурой
.ByInnAndKpp("инн", "кпп")
.SelectMany(x => x.Company)
.ToList();

Вопрос эквивалентности вариантов с Select и SelectMany с точки зрения IQueryProvider я еще до конца не изучил. Буду благодарен любой информации на эту тему в комментариях.

Связанные коллекции

public virtual ICollection Documents { get; protected set; }



Желательно использовать только в блоке Select для преобразования в SQL-запрос, потому что код вида company.Documents.Where(…).ToList() не построит запрос к БД, а сначала поднимет в оперативную память все связанные сущности, а потому применит Where к выборке в памяти. Таким образом, наличие коллекций в модели может крайней негативно отразиться на производительности приложения. При этом рефакторинг будет произвести сложно, потому что придется передавать необходимые IQueryable из вне. Чтобы контролировать качество запросов нужно поглядывать в miniProfiler.

Сервисы (Service)



В анемичной модели вообще вся логика хранится в сервисах. Я предпочитаю добавлять сервисы только по необходимости, если логика неуместна в коде агрегата или описывает взаимодействие между агрегатами. Лучший вариант, когда домен содержит точные названия для сервиса — «касса», «склад», «кол-центр». В этом случае постфикс «Service» можно опустить. Набор методов в каждом классе соответствует набору use case'ов, сгруппированных по элементам пользовательского интерфейса. Работает хорошо, если интерфейс разработан в стиле Task Based UI.

Write-методы принимают на вход сущности или DTO. Валидация запроса производится в отдельном слое строго до выполнения метода. Если метод может завершиться неудачей, следует явно обозначить это в сигнатуре с помощью типа Result. Исключения остаются для исключительных ситуаций.

Read-методы возвращают DTO для сериализации и отправки на клиент. Благодаря Queryable Extensions в AutoMapper и Mapster можно использовать маппинги для трансляции в выражения для Select, что позволяет не тащить всю сущность из БД целиком.

Менеджеры (Manager)



Использую редко, для операций в рамках одного агрегата. AspNet.Identity, например содержит UserManager. В основном менеджеры нужны, когда необходимо реализовать логику над агрегатом, не относящуюся непосредственно к домену.

TPT для union-type



Иногда одна сщуность может быть связана с одной из нескольких других. Для создания непротиворечивой системы хранения можно использовать TPT, а для control flow — pattern matching. Этот подход подробно описан в отдельной статье.

Queryable Extensions для проекций в DTO

Использование DataMapper позволяет снизить количество boilerplate-кода, а использование Queryable Extensions — строить запросы на получение DTO без необходимости писать Select вручную. Таким образом можно повторно использовать выражения для маппинга в оперативной памяти и построения деревьев выражений для IQueryProvider. AutoMapper довольно прожорлив по памяти и не быстр, поэтому со временем заменил его на Mapster.

CQRS для отдельных подсистем

При работе в условиях высокой неопределенности риск ошибки проектирования также велик. Прежде чем проектировать структуру БД, принимать решения о денормализации или писать хранимые процедуры есть смысл прибегнуть к быстрому макетированию и проверить гипотезы. Когда есть уверенность: что на входе, а что на выходе можно заняться оптимизацией.

В отсутствии команд реализации IQuery возвращают одинаковые результаты на одинаковых входных данных. Поэтому тела таких методов можно агрессивно кешировать. Таким образом, после замены реализаций инфраструктурный код (контроллеры) останется без изменений, а модифицировать придется только тело метода IQuery. Подход позволяет оптимизировать приложение точечно по небольшим кусочкам, а не все целиком.

Подход ограничено-применим для очень-очень нагруженных ресурсов из-за накладных расходов на IOC-контейнер и memory traffic для per request lifestyle. Однако, все IQuery можно сделать singleton'ами, если не инжектировать зависимости от БД в конструктор, а вместо этого использовать конструкцию using.



Работа с унаследованным кодом

При работе с существующей кодовой базой следует определиться с форматом работы: «поддержка» или «развитие». В первом случае не предполагается появление новой функциональности и доработка системы. Максимум — добавить несколько новых отчетов, пару форм тут и там. Во втором — есть необходимость значительной переработки предметной модели и / или архитектуры в целом. Если проект необходимо именно «поддерживать», а не «развивать», лучше следовать существующим правилам, независимо от того на сколько они удачные. Если перед вами откровенный говнокод, от предложения посупортить его лучше отказаться.

Развитие проекта — задача более сложная. Тема рефакторинга выходит за рамки данной статьи. Отмечу лишь два самых полезных паттерна: «антикоррупционный слой» и «душитель». Они очень похожи. Основная идея — выстроить «фасад» между старой и новой кодовыми базами и постепенно есть слона переписывать всю систему по кусочкам. Фасад берет на себя роль барьера, не позволяющего проблемам старой кодовой базы просочиться в новую и обеспечивающего отображение старой бизнес-логики в новую. Будьте готовы, что фасад будет состоять из сплошь из хаков, уловок и костылей и рано или поздно канет в лету вместе со всей старой кодовой базой.
Download 333.79 Kb.

Do'stlaringiz bilan baham:
1   2




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling