Является ли дизайн, управляемый доменом, анти-SQL шаблоном?


44

Я погружаюсь в дизайн, управляемый доменом (DDD), и хотя я углубляюсь в это, есть некоторые вещи, которые я не понимаю. Насколько я понимаю, главное - это отделить доменную логику (бизнес-логику) от инфраструктуры (БД, файловая система и т. Д.).

Что мне интересно, так это то, что происходит, когда у меня возникают очень сложные запросы, такие как запрос на расчет материальных ресурсов? В таких запросах вы работаете с тяжелыми операциями над множествами, для которых и был разработан SQL. Выполнять эти вычисления на уровне домена и работать с большим количеством наборов в нем - все равно что отбросить технологию SQL.

Выполнение этих вычислений в инфраструктуре также не может произойти, потому что шаблон DDD позволяет вносить изменения в инфраструктуру, не изменяя уровень домена и не зная, что MongoDB не обладает такими же возможностями, как, например, SQL Server, что не может произойти.

Это ловушка DDD?


34
Хотя SQL предназначен для обработки алгебры реляционных множеств, это не веселый день, когда вы понимаете, что половина вашей бизнес-логики утопает в горстке функций SQL, которые трудно реорганизовать и еще труднее протестировать. Таким образом, перемещение этого на доменный слой, где он может играть со своими друзьями, звучит привлекательно для меня. Это отбрасывает хороший кусок технологии SQL? Конечно, но SQL намного проще в управлении, когда вы используете только SELECT / JOIN.
Джаред Гогуэн

30
@JaredGoguen, но это может быть потому, что вы не являетесь экспертом по SQL и не из-за технологий
Леонардо Мангано

2
@JimmyJames Я пытался сказать, что если DDD хорошо реализован, он позволяет с минимальными усилиями изменять слои, например, переходить с SQL Server на MongoDB. Но, если в SQL есть сложные запросы, возможно, я не смогу перейти на MongoDB из-за их технических различий. Я думаю, что сказал очевидную вещь.
Леонардо Мангано

7
... is like throwing away the SQL technologyТо, что конкретная технология может что-то сделать, не означает, что это лучший выбор. Это неподтвержденное свидетельство, но я встречал слишком много компаний, которые хранили бизнес-логику в базе данных и уходят от нее из-за долговременных проблем с обслуживаемостью, которые она вызывает. Упрощенно, но базы данных предназначены для хранения данных, а языки программирования предназначены для преобразования данных. Я бы не хотел использовать БД для бизнес-логики больше, чем пытаться использовать свое приложение для непосредственного хранения моих данных.
Конор Манконе

8
Сам SQL является отличным примером DDD. Когда сталкивались с организацией связанных данных, люди сначала указывали язык для этого: SQL. Реализация не имеет большого значения. Администратор БД не должен знать C / C ++ для запроса базы данных. Точно так же, сталкиваясь с задачей планирования событий, кто-то придумал синтаксис CRON (mhdmw) - простую модель предметной области, которая соответствует 99% задач планирования. Суть DDD не в том, чтобы создавать классы или таблицы и т. Д. Это в том, чтобы понять вашу проблему и создать систему для работы в вашей проблемной области
slebetman

Ответы:


39

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

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


13
+1 Хороший ответ, но вы должны дать этому понятию собственное имя, Command-Query Segregation.
Майк поддерживает Монику

6
@Mike Наличие совершенно разных моделей для чтения и записи больше похоже на CQRS, чем на CQS.
Энди

3
«Модель чтения» - это не модель предметной области (или ее часть)? Я не эксперт по CQRS, но я всегда думал, что модель команд сильно отличается от классической модели предметной области, но не от модели чтения. Так, может быть, вы можете привести пример для этого?
Док Браун

Мне потребовалось слишком много времени, чтобы понять, что High Performance Mark привлекает внимание к опечатке.
VoiceOfUnreason

@DocBrown - вот моя попытка прояснить для вас -> cascadefaliure.vocumsineratio.com/2019/04/…
VoiceOfUnreason

21

Насколько я понимаю, главное - это отделить доменную логику (бизнес-логику) от инфраструктуры (БД, файловая система и т. Д.).

Это основа недоразумения: цель DDD не состоит в том, чтобы разделить вещи по жесткой линии, например, «это на сервере SQL, поэтому не должно быть BL», цель DDD - разделить домены и создать барьеры между они позволяют внутренним элементам домена быть полностью отделенными от внутренних элементов другого домена и определять общие внешние элементы между ними.

Не думайте, что «быть в SQL» - это барьер BL / DL - это не то, что есть. Вместо этого думайте, что «это конец внутреннего домена», как барьер.

Каждый домен должен иметь внешние API-интерфейсы, позволяющие ему работать со всеми другими доменами: в случае уровня хранения данных он должен иметь действия чтения / записи (CRUD) для объектов данных, которые он хранит. Это означает , что само по себе SQL не является на самом деле барьер, VIEWи PROCEDUREкомпоненты. Вы никогда не должны читать непосредственно из таблицы: это подробности реализации DDD говорит нам, что, как внешний потребитель, мы не должны беспокоиться.

Рассмотрим ваш пример:

Что мне интересно, так это то, что происходит, когда у меня возникают очень сложные запросы, такие как запрос на расчет материальных ресурсов? В таких запросах вы работаете с тяжелыми операциями над множествами, для которых и был разработан SQL.

Это именно то, что должно быть в SQL, и это не является нарушением DDD. Это то, для чего мы сделали DDD . С этим вычислением в SQL это становится частью BL / DL. Что бы вы сделали, это использовали бы отдельное представление / хранимую процедуру / что-что-у-вас и держали бизнес-логику отдельно от уровня данных, так как это ваш внешний API. Фактически, ваш уровень данных должен быть еще одним DDD Domain Layer, где ваш уровень данных имеет свои собственные абстракции для работы с другими уровнями домена.

Выполнение этих вычислений в инфраструктуре также не может произойти, потому что шаблон DDD позволяет вносить изменения в инфраструктуру, не изменяя уровень домена и не зная, что MongoDB не обладает такими же возможностями, как, например, SQL Server, что не может произойти.

Это еще одно недоразумение: в нем говорится, что детали реализации внутри могут меняться без изменения других уровней домена. В нем не сказано, что вы можете просто заменить целую часть инфраструктуры.

Опять же, имейте в виду, что DDD скрывает внутренние компоненты с четко определенными внешними API. Где находятся эти API - это совершенно другой вопрос, и DDD этого не определяет. Он просто определяет, что эти API существуют и никогда не должны изменяться .

DDD не настроен так, чтобы вы могли произвольно заменить MSSQL на MongoDB - это два совершенно разных компонента инфраструктуры.

Вместо этого давайте воспользуемся аналогией для определения DDD: газ против электромобилей. У обоих автомобилей есть два совершенно разных метода создания тяги, но у них одинаковые API: включение / выключение, дроссель / тормоз и колеса для движения автомобиля. DDD говорит, что мы должны иметь возможность заменить двигатель (бензиновый или электрический) в нашем автомобиле. Это не говорит о том, что мы можем заменить автомобиль на мотоцикл, и это фактически то, что MSSQL → MongoDB.


1
Спасибо за объяснение. Для меня это очень сложная тема, у каждого своя точка зрения. Единственное, с чем я не согласен, это сравнение между MSSQL (автомобиль) и MongoDB (мотоцикл), для меня правильное сравнение заключается в том, что это два разных двигателя для одного автомобиля, но это просто мнение.
Леонардо Мангано

8
@ LeonardoMangano Ах, но это не так. MSSQL - это реляционная база данных, MongoDB - это база данных документов. Да, «база данных» описывает и то и другое, но это примерно так. Техники чтения / записи совершенно разные. Вместо MongoDB вы могли бы использовать Postgre или MySQL в качестве альтернативы, и это было бы правильным сравнением.
410_Пошла

3
«Никогда не читайте прямо со стола ...» Безумие.
jpmc26

«Вы никогда не должны читать прямо из таблицы ...» Это правило, которое я пришел для того, чтобы реализовать самостоятельно после десятилетия написания программного обеспечения, которое взаимодействует с базами данных, и страдало от ранней боли от попыток следовать руководствам, структурированным вокруг популярные шаблоны дизайна.
Люцифер Сэм

@LuciferSam Да. Это значительно облегчает управление разделением между деталями реализации и границами домена. Один «объект» в домене может быть представлен 5 таблицами, поэтому мы используем представление для инкапсуляции этого объекта.
410_Пошла

18

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

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

Отклонение от архитектурного образца

Когда вы сталкиваетесь с трудностями при чисто шаблонном применении или отклонении в какой-либо области, тогда вам нужно принять решение. Шаблон - это просто шаблонный способ сделать что-то, чтобы помочь организовать ваш проект. На этом этапе нужно время, чтобы оценить:

  • Это правильный шаблон? (много раз, но иногда это просто плохо)
  • Должен ли я отклониться в этом направлении?
  • Насколько далеко я отклонился?

Вы обнаружите, что некоторые архитектурные шаблоны хорошо подходят для 80-90% вашего приложения, но не так сильно для оставшихся битов. Случайное отклонение от предписанного шаблона полезно по причинам производительности или логистики.

Однако, если вы обнаружите, что ваши кумулятивные отклонения составляют более 20% от архитектуры вашего приложения, это, вероятно, просто плохое соответствие.

Если вы решите продолжать следовать архитектуре, сделайте себе одолжение и укажите, где и почему вы отклонились от предписанного способа действий. Когда в вашей команде появляется новый увлеченный участник, вы можете указать им на эту документацию, которая включает измерения производительности и обоснования. Это уменьшит вероятность повторных запросов для устранения «проблемы». Эта документация также поможет устранить необузданные отклонения.


Я бы избегал использования фраз типа «это правильный шаблон» в ответах. Достаточно сложно заставить людей быть конкретными, когда они пишут свои вопросы, и по вашему собственному признанию «иногда это плохо подходит», что говорит о том, что нет, это не правильный шаблон.
Роберт Харви

@RobertHarvey, я был в проектах, где использованный шаблон был просто не подходящим для приложения, что приводило к сбою определенных показателей качества. Это, конечно, не норма, но когда это происходит, вам сложно принять решение изменить архитектуру или оставить код приложения в приложении. Чем раньше вы сможете определить плохую посадку, тем легче ее исправить. Вот почему я всегда учитываю эту мысль при оценке крайних случаев. Наряду с последней пулей, иногда вы не понимаете, насколько это плохо, пока не увидите скопление отклонений.
Берин Лорич

7

Логика манипулирования множеством, в которой хорошо работает SQL, без проблем может быть интегрирована с DDD.

Скажем, например, мне нужно знать некоторую совокупную стоимость, общее количество продуктов по типу. Легко запустить в SQL, но медленно, если я загружаю каждый продукт в память и добавляю их все.

Я просто представляю новый объект Domain,

ProductInventory
{
    ProductType
    TotalCount
    DateTimeTaken
}

и метод в моем хранилище

ProductRepository
{
    List<ProductInventory> TakeInventory(DateTime asOfDate) {...}
}

Конечно, может быть, теперь я полагаюсь на то, что у моей БД есть определенные способности. Но у меня все еще есть техническое разделение, и пока логика проста, я могу утверждать, что это не «бизнес-логика»


Ну, пока я помню. Хранилища должны также получать Queryпараметры. repository.find(query);, Я читал то же самое, но с Specs. That opens a door to leave Query` в качестве абстракции и / QueryImplили реализации конкретного запроса на уровне инфраструктуры.
Laiv

5
о боже, я знаю, что некоторые люди делают это, но я думаю, что это ужасно. Вы можете рассматривать такие вещи как шаг вниз по этому пути. Но я думаю, что это может быть принято с осторожностью.
Эван

I know some people do thatнекоторые люди являются Pivotal и его основой. SpringFramework имеет много этого :-). В любом случае, как предположил @VoiceOfUnreason, ключом к DDD является поддержание согласованности записей. Я не уверен в том, чтобы заставить дизайн использовать доменные модели, для которых единственной целью является запрос или параметризация запросов. Это может быть реализовано вне домена с помощью структур данных (pocos, pojos, dtos, преобразователи строк и т. Д.).
Laiv

очевидно, нам нужна какая-то инквизиция, чтобы помочь этим людям вернуться к здравомыслию. Но я придерживаюсь своего оружия. Частичное раскрытие слоя данных приемлемо, когда оно объективно способствует лучшему применению, где то, что является или не является «доменным объектом», субъективно
Ewan

1
@LeonardoMangano зависит от вашего приложения и реализации. Главное, что нужно понять, это то, что вы можете переосмыслить свой домен, чтобы сделать его практически осуществимым.
Эван

3

Один из возможных способов решения этой дилеммы - думать о SQL как о языке ассемблера: вы редко, если вообще используете код непосредственно на нем, но там, где важна производительность, вы должны уметь понимать код, созданный вашим C / C ++ / Golang / Rust компилятор и, возможно, даже написать крошечный фрагмент в сборке, если вы не можете изменить код на языке высокого уровня для получения желаемого машинного кода.

Точно так же в области баз данных и SQL различные библиотеки SQL (некоторые из которых являются ORM ), например SQLAlchemy и Django ORM для Python, LINQ для .NET, предоставляют абстракции более высокого уровня, но по возможности используют сгенерированный код SQL для достижения производительности. Они также обеспечивают некоторую переносимость в отношении используемой БД, возможно, с разной производительностью, например, на Postgres и MySQL, из-за некоторых операций, использующих более оптимальный SQL для конкретной БД.

Как и в случае с языками высокого уровня, очень важно понимать, как работает SQL, даже если нужно просто переупорядочить запросы, выполняемые с вышеупомянутыми библиотеками SQL, для достижения желаемой эффективности.

PS Я бы предпочел сделать комментарий, но у меня нет достаточной репутации для этого.


2

Как обычно, это одна из тех вещей, которая зависит от ряда факторов. Это правда, что с SQL можно многое сделать. Есть также проблемы с его использованием и некоторые практические ограничения реляционных баз данных.

Как отмечает в комментариях Джаред Гогуэн, SQL может быть очень сложно протестировать и проверить. Основные факторы, которые приводят к этому, - то, что это не может (вообще) быть разложено на компоненты. На практике сложный запрос должен рассматриваться в целом. Еще одним осложняющим фактором является то, что поведение и правильность SQL сильно зависят от структуры и содержания ваших данных. Это означает, что тестирование всех возможных сценариев (или даже определение того, что они есть) часто невозможно или невозможно. Рефакторинг SQL и модификация структуры базы данных также проблематичны.

Другим важным фактором, который привел к отходу от SQL, являются реляционные базы данных, которые имеют тенденцию масштабироваться только по вертикали. Например, когда вы строите сложные вычисления в SQL для запуска в SQL Server, они будут выполняться в базе данных. Это означает, что вся эта работа использует ресурсы в базе данных. Чем больше вы делаете в SQL, тем больше ресурсов понадобится вашей базе данных с точки зрения памяти и процессора. Часто это менее эффективно делать в других системах, но практического ограничения количества дополнительных машин, которые вы можете добавить к такому решению, нет. Этот подход менее дорогой и более отказоустойчивый, чем создание огромного сервера баз данных.

Эти проблемы могут относиться или не относиться к данной проблеме. Если вы можете решить вашу проблему с помощью доступных ресурсов базы данных, возможно, SQL подойдет для вашего проблемного пространства. Вы должны учитывать рост, однако. Это может быть хорошо сегодня, но через несколько лет стоимость добавления дополнительных ресурсов может стать проблемой.


Разве не альтернатива базе данных монстров, просто чудовищное количество и разнообразие вспомогательных систем? Какую устойчивость имеют вспомогательные системы, если все они зависают от базовой системы? И если оправданием является просто технологическое ограничение базовой системы, то это часто будет преждевременной оптимизацией для большинства бизнес-систем. SQL, как правило, может быть написан в несвязном виде, если это необходимо.
Стив

@ Стив, я думаю, что если вы ошиблись, то предполагаете, что должна быть одноядерная система, от которой «зависают» другие.
JimmyJames

@Steve Чтобы привести пример, вы можете заменить всю системную базу данных единой базой данных без SQL (я не говорю, что это всегда правильный выбор, просто это можно сделать.) Затем эту базу данных можно хранить во многих системы, даже географические регионы. Такая БД не является вспомогательной, это массовая замена БД SQL.
JimmyJames

@JimmyJames, согласен, но когда нет базовой системы, это может создать свои собственные проблемы, анализируя зависимости и поддерживая согласованность данных. В этом и заключается причина монолитов - они создают определенную простоту и, следовательно, определенные виды эффективности анализа и обслуживания. Немонолитные решения просто обменивают одни проблемы или затраты на другие.
Стив

@jmoreno Бросать ресурсы во что-то, чтобы хромать, это не то, что я бы назвал хорошей инженерией: «для обработки огромного объема данных сайта и запускает 9 000 экземпляров memcached для того, чтобы не отставать от количества транзакций база данных должна служить. " Рассматриваете ли вы стоимость ваших проектов или вы предполагаете, что кто-то выложит деньги, чтобы сделать ваши личные предпочтения работоспособными?
JimmyJames

2

Это ловушка DDD?

Позвольте мне сначала прояснить несколько заблуждений.

DDD это не образец. И это действительно не предписывает образцы.

В предисловии к книге DDD Эрика Эвана говорится:

Ведущие разработчики программного обеспечения признали моделирование и дизайн предметной области критическими темами в течение как минимум 20 лет, но на удивление мало что было написано о том, что необходимо сделать или как это сделать. Хотя это никогда не было сформулировано четко, философия возникла как скрытое течение в объектном сообществе, философию, которую я называю доменным дизайном.

[...]

Общей чертой успехов была богатая модель предметной области, которая развивалась в ходе итераций дизайна и стала частью структуры проекта.

Эта книга предоставляет основу для принятия проектных решений и технический словарь для обсуждения дизайна предметной области. Это синтез широко принятых лучших практик наряду с моими собственными знаниями и опытом.

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

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

Ничто в этом не является про- или анти-SQL, хотя разработчики ОО, возможно, в целом лучше выражают модель на языках ОО, и выражение многих концепций предметной области лучше поддерживается ООП. Но иногда части модели должны быть выражены в другой парадигме.

Что мне интересно, так это то, что происходит, когда у меня очень сложные запросы [...]?

Ну, вообще говоря, здесь есть два сценария.

В первом случае некоторый аспект домена действительно требует сложного запроса, и, возможно, этот аспект лучше всего выражен в парадигме SQL / реляционная, поэтому используйте соответствующий инструмент для работы. Отразите эти аспекты в своем доменном мышлении и языке, используемом для передачи концепций. Если домен сложный, возможно, это часть субдомена с собственным ограниченным контекстом.

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


0

Сиквел стал популярным, когда память была дорогой, потому что реляционная модель данных предоставляла возможность нормализовать ваши данные и эффективно хранить их в файловой системе.

Теперь память относительно дешева, поэтому мы можем пропустить нормализацию и сохранить в том формате, в котором мы ее используем, или даже скопировать много одинаковых данных ради скорости.

Рассматривайте базу данных как простое устройство ввода-вывода , которое несет ответственность за хранение данных в файловой системе - да, я знаю, это сложно представить, потому что мы написали множество приложений с важной бизнес-логикой, записанной в запросах SQL, - но просто попытайтесь представить, что SQL Server это просто еще один принтер.

Вы бы встроили генератор PDF в драйвер принтера или добавили триггер, который будет печатать страницу журнала для каждого заказа на продажу, распечатанного с нашего принтера?

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

В 70-90-х годах базы данных SQL были эффективными, а теперь? - Не уверен, что в некоторых случаях асинхронный запрос данных будет возвращать требуемые данные быстрее, чем множественные объединения в запросе SQL.

SQL не был разработан для сложных запросов, он был разработан для эффективного хранения данных, а затем предоставлял интерфейс / язык для запроса хранимых данных.

Я бы сказал, что построение вашего приложения на основе реляционной модели данных со сложными запросами - это злоупотребление движком базы данных. Конечно, поставщики ядра СУБД счастливы, когда вы тесно связываете свой бизнес с их продуктом - они будут более чем рады предоставить больше возможностей, которые укрепят эту связь.


1
Но я продолжаю думать, что SQL лучше для множественных вычислений, чем любой другой язык. С моей точки зрения. Ваш пример перевернут, использование C # для очень сложных операций над множествами с миллионами строк и объединений использует неправильный инструмент, но я могу ошибаться.
Леонардо Мангано

@LeonardoMangano, несколько примеров: с помощью c # я могу разделить миллионы строк и рассчитать их параллельно, я могу асинхронно извлекать данные и выполнять вычисления «вовремя», когда данные возвращаются, с помощью c # я могу выполнять вычисления с низким использованием памяти, перечисляя строки по ряду. Сложная логика в коде предоставит вам множество вариантов выполнения вычислений.
Фабио,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.