Навіщо розділяти доступ до даних?
З цієї книги, я думаю, що перші дві сторінки розділу Модель, керований дизайном, дають певне обґрунтування того, чому ви хочете абстрагувати деталі технічної реалізації від впровадження доменної моделі.
- Ви хочете підтримувати тісний зв'язок між моделлю домену та кодом
- Розділення технічних проблем допомагає довести, що модель практична для впровадження
- Ви хочете, щоб всюдисуща мова пронизала дизайн системи
Це, мабуть, все для того, щоб уникнути окремої "моделі аналізу", яка розлучається з реальною реалізацією системи.
З того, що я розумію у книзі, вона говорить про те, що ця "модель аналізу" може бути розроблена без розгляду програмного забезпечення. Як тільки розробники намагаються реалізувати зрозумілу для бізнесу модель, вони формують власні абстракції через необхідність, викликаючи стіну в спілкуванні та розумінні.
В іншому напрямку розробники, які впроваджують занадто багато технічних проблем у доменну модель, також можуть спричинити це розрив.
Таким чином, ви можете вважати, що практичне розмежування проблем, таких як наполегливість, може допомогти захистити від цих дизайнів моделі аналізу, що розходяться. Якщо вам здається необхідним ввести в модель такі речі, як наполегливість, то це червоний прапор. Можливо, модель не практична для реалізації.
Цитування:
"Єдина модель зменшує шанси на помилку, оскільки конструкція зараз є прямим зростанням ретельно розглянутої моделі. Дизайн і навіть сам код мають комунікативність моделі".
Як я трактую це, якщо ви закінчилися з більшою кількістю рядків коду, що стосуються таких речей, як доступ до бази даних, ви втрачаєте цю комунікативність.
Якщо необхідність доступу до бази даних полягає в таких речах, як перевірка унікальності, погляньте на:
Уді Дахан: найбільші помилки, які роблять команди при застосуванні 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;
}
Плюси: "КОЛИ, де і як" доступ до даних прихований від розробника, орієнтуючись на логіку домену. У сукупності немає коду, який би займався завантаженням даних. Обсяг завантажених даних може бути точним, необхідним кодом.
Мінуси: Коли ви стикаєтеся з проблемою продуктивності, важко це виправити, коли у вас є загальне рішення "один розмір, який відповідає всім". Ледаче завантаження може призвести до погіршення загальної продуктивності, а впровадження ледачого завантаження може бути складним.
Рольовий інтерфейс / швидке отримання
Кожен випадок використання робиться явним через інтерфейс ролей, реалізований агрегованим класом, що дозволяє керувати стратегіями завантаження даних для кожного випадку використання.
Стратегія отримання може виглядати приблизно так:
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 використовується для створення агрегату, а потім агрегат виконує свою роботу.
Плюси: Дозволяє використовувати спеціальний код на кожний випадок використання, що забезпечує оптимальну ефективність. Відповідає принципу розбиття інтерфейсу . Немає складних вимог до коду. Тестові одиниці агрегатів не повинні імітувати стратегію завантаження. Загальна стратегія завантаження може використовуватися в більшості випадків (наприклад, стратегія "завантажувати все"), а спеціальні стратегії завантаження можуть бути реалізовані при необхідності.
Мінуси: Розробник все ще повинен коригувати / переглянути стратегію отримання після зміни доменного коду.
При застосуванні стратегії вибору ви все ще можете змінити власний код отримання для зміни правил бізнесу. Це не ідеальне розмежування проблем, але в кінцевому підсумку стане більш ретельним і кращим, ніж перший варіант. Стратегія отримання отримує інкапсуляцію того, як завантажуються дані, КОГО та КОГО. Він краще розділяє проблеми, не втрачаючи гнучкості, як один розмір, який відповідає всім ледачим підходам.