Зачем выделять доступ к данным?
Из книги я думаю, что первые две страницы главы «Модель управляемой конструкции» дают некоторое обоснование того, почему вы хотите абстрагироваться от деталей технической реализации от реализации модели предметной области.
- Вы хотите сохранить тесную связь между моделью домена и кодом
- Разделение технических проблем помогает доказать, что модель является практичной для реализации
- Вы хотите, чтобы вездесущий язык проникал через дизайн системы
Похоже, что это все для того, чтобы избежать отдельной «модели анализа», которая отделена от фактической реализации системы.
Из того, что я понимаю в книге, говорится, что эта «модель анализа» может быть разработана без учета программной реализации. Как только разработчики пытаются реализовать модель, понятную бизнес-стороне, они по необходимости создают свои собственные абстракции, создавая стенку в общении и понимании.
С другой стороны, разработчики, вносящие слишком много технических проблем в модель предметной области, также могут вызвать это разделение.
Таким образом, вы могли бы подумать, что практика разделения проблем, таких как постоянство, может помочь защитить от этих моделей расхождение моделей анализа. Если необходимо ввести в модель такие вещи, как постоянство, тогда это красный флаг. Возможно модель не практична для реализации.
Цитирование:
«Единая модель уменьшает вероятность ошибки, потому что дизайн в настоящее время является прямым следствием тщательно продуманной модели. Дизайн и даже сам код имеют коммуникативность модели».
Как я понимаю, если у вас появилось больше строк кода, связанных с такими вещами, как доступ к базе данных, вы потеряете эту коммуникативность.
Если вам необходим доступ к базе данных для проверки уникальности, взгляните на:
Уди Дахан: самые большие ошибки команды делают при применении DDD
http://gojko.net/2010/06/11/udi-dahan-the-biggest-mistakes-teams-make-when-applying-ddd/
под "Все правила не равны"
и
Использование модели доменной модели
http://msdn.microsoft.com/en-us/magazine/ee236415.aspx#id0400119
в разделе «Сценарии неиспользования модели предметной области», который затрагивает ту же тему.
Как выделить доступ к данным
Загрузка данных через интерфейс
«Уровень доступа к данным» был абстрагирован через интерфейс, который вы вызываете для получения необходимых данных:
var orderLines = OrderRepository.GetOrderLines(orderId);
foreach (var line in orderLines)
{
total += line.Price;
}
Плюсы: Интерфейс отделяет код доступа к данным, что позволяет вам писать тесты. Доступ к данным может обрабатываться в каждом конкретном случае, обеспечивая лучшую производительность, чем общая стратегия.
Минусы: код вызова должен предполагать, что было загружено, а что нет.
Скажем, GetOrderLines возвращает объекты OrderLine с нулевым свойством ProductInfo по соображениям производительности. Разработчик должен иметь глубокие знания кода за интерфейсом.
Я попробовал этот метод на реальных системах. В конечном итоге вы постоянно меняете объем загружаемого содержимого, пытаясь исправить проблемы с производительностью. В итоге вы заглядываете за интерфейс, чтобы посмотреть код доступа к данным, чтобы увидеть, что загружается, а что нет.
Теперь разделение задач должно позволить разработчику сосредоточиться на одном аспекте кода одновременно, насколько это возможно. Интерфейсная техника удаляет, КАК эти данные загружены, но НЕ КАК МНОГО загружаются данные, КОГДА они загружаются, и ГДЕ они загружаются.
Вывод: довольно низкая сепарация!
Ленивая Загрузка
Данные загружаются по запросу. Вызовы для загрузки данных скрыты внутри самого графа объектов, где доступ к свойству может привести к выполнению запроса sql перед возвратом результата.
foreach (var line in order.OrderLines)
{
total += line.Price;
}
Плюсы: «КОГДА, ГДЕ и КАК» доступа к данным скрыты от разработчика, сосредоточенного на предметной логике. В агрегате нет кода, который занимается загрузкой данных. Количество загруженных данных может быть точным количеством, требуемым кодом.
Минусы: когда вы сталкиваетесь с проблемой производительности, ее трудно исправить, если у вас есть универсальное решение "один размер подходит всем". Ленивая загрузка может привести к ухудшению производительности в целом, а реализация отложенной загрузки может быть сложной задачей.
Роль Интерфейс / Eager Fetching
Каждый вариант использования делается явным образом через ролевый интерфейс, реализованный агрегатным классом, что позволяет обрабатывать стратегии загрузки данных для каждого варианта использования.
Стратегия выборки может выглядеть так:
public class BillOrderFetchingStrategy : ILoadDataFor<IBillOrder, Order>
{
Order Load(string aggregateId)
{
var order = new Order();
order.Data = GetOrderLinesWithPrice(aggregateId);
return order;
}
}
Тогда ваш агрегат может выглядеть так:
public class Order : IBillOrder
{
void BillOrder(BillOrderCommand command)
{
foreach (var line in this.Data.OrderLines)
{
total += line.Price;
}
etc...
}
}
BillOrderFetchingStrategy используется для построения агрегата, а затем агрегат выполняет свою работу.
Плюсы: позволяет настраивать код для каждого варианта использования, обеспечивая оптимальную производительность. Инлайн с интерфейсом сегрегация Принцип . Нет сложных требований к коду. Агрегатные модульные тесты не должны имитировать стратегию загрузки. Общая стратегия загрузки может использоваться в большинстве случаев (например, стратегия «загрузить все»), и при необходимости могут быть реализованы специальные стратегии загрузки.
Минусы: Разработчик все еще должен скорректировать / пересмотреть стратегию выборки после изменения кода домена.
При подходе стратегии извлечения вы все равно можете изменить пользовательский код извлечения для изменения бизнес-правил. Это не идеальное разделение проблем, но в итоге будет более ремонтопригодным и лучше, чем первый вариант. Стратегия выборки инкапсулирует данные HOW, WHEN и WHERE. Он лучше разделяет проблемы, не теряя гибкости, так как один размер подходит для всех подходов с отложенной загрузкой.