Я (пере) проектирую крупномасштабное приложение, мы используем многоуровневую архитектуру на основе DDD.
У нас есть MVC с уровнем данных (реализация репозиториев), доменом (определение модели домена и интерфейсов - репозитории, сервисы, единица работы), сервисным уровнем (реализация сервисов). До сих пор мы использовали доменные модели (в основном сущности) для всех уровней и использовали DTO только в качестве моделей представлений (в контроллере служба возвращает модель (ы) домена, а контроллер создает модель представления, которая передается представлению).
Я читал бесчисленные статьи об использовании, не использовании, отображении и передаче DTO. Я понимаю, что нет однозначного ответа, но я не уверен, нормально ли это, или не возвращает модели доменов из сервисов в контроллеры. Если я возвращаю модель предметной области, она все равно никогда не передается в представление, поскольку контроллер всегда создает модель представления, зависящую от вида, - в этом случае это кажется допустимым. С другой стороны, он не чувствует себя хорошо, когда доменная модель покидает бизнес-уровень (сервисный уровень). Иногда службе необходимо вернуть объект данных, который не был определен в домене, и тогда нам нужно либо добавить новый объект в домен, который не отображается, либо создать объект POCO (это ужасно, поскольку некоторые службы возвращают модели домена, некоторые эффективно вернуть DTOs).
Вопрос заключается в том, что если мы строго используем модели представлений, можно ли возвращать модели доменов вплоть до контроллеров, или мы всегда должны использовать DTO для связи с уровнем обслуживания? Если да, то можно ли корректировать доменные модели в зависимости от того, какие услуги нужны? (Честно говоря, я так не думаю, поскольку сервисы должны потреблять то, что имеет домен.) Если мы должны строго придерживаться DTO, должны ли они быть определены на уровне сервисов? (Я так думаю.) Иногда ясно, что мы должны использовать DTO (например, когда служба выполняет много бизнес-логики и создает новые объекты), иногда ясно, что мы должны использовать только модели домена (например, когда служба членства возвращает анемичного пользователя ( s) - кажется, не имеет смысла создавать DTO, аналогичный модели предметной области), - но я предпочитаю последовательность и хорошие практики.
Статья Домен против DTO против ViewModel - Как и когда их использовать? (а также некоторые другие статьи) очень похожа на мою проблему, но не отвечает на этот вопрос (ы). Статья Должен ли я реализовать DTO в репозитории с EF? также похож, но это не касается DDD.
Отказ от ответственности: я не собираюсь использовать какой-либо шаблон проектирования только потому, что он существует и причудливый, с другой стороны, я хотел бы использовать хорошие шаблоны проектирования и практики также потому, что это помогает проектировать приложение в целом, помогает с разделением проблем, даже если использование определенного шаблона не является «необходимым», по крайней мере, на данный момент.
Как всегда, спасибо.
источник
Ответы:
Чувствуете ли вы, что вы выводите из себя кишки, верно? По словам Мартина Фаулера: уровень обслуживания определяет границы приложения, он инкапсулирует домен. Другими словами это защищает домен.
Можете ли вы привести пример этого объекта данных?
Да, потому что ответ является частью вашего уровня обслуживания. Если оно определено «где-то еще», то сервисный уровень должен ссылаться на это «где-то еще», добавляя новый слой в вашу лазанью.
DTO является объектом ответа / запроса, имеет смысл, если вы используете его для связи. Если вы используете доменные модели в своем уровне представления (MVC-Controllers / View, WebForms, ConsoleApp), то уровень представления тесно связан с вашим доменом, любые изменения в домене требуют смены контроллеров.
Это один из недостатков DTO для новых глаз. Прямо сейчас вы думаете дублировании кода , но по мере расширения вашего проекта это будет иметь гораздо больше смысла, особенно в командной среде, где разные команды назначаются на разные уровни.
DTO может добавить дополнительную сложность вашему приложению, как и ваши уровни. DTO - дорогая функция вашей системы, они не бесплатны.
Зачем использовать DTO
Эта статья предоставляет как преимущества, так и недостатки использования DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html.
Резюме следующим образом:
Когда использовать
Когда не использовать
Аргументы против DTO
Аргументы с DTO
источник
Кажется, что ваше приложение достаточно большое и сложное, поскольку вы решили использовать подход DDD. Не возвращайте ваши poco-сущности или так называемые доменные сущности и объекты-значения в слое вашего сервиса. Если вы хотите сделать это, то удалите слой обслуживания, потому что он вам больше не нужен! Объекты View Model или Data Transfer должны находиться в слое Service, поскольку они должны отображаться на членов модели домена и наоборот. Так зачем вам нужен DTO? В сложном приложении с большим количеством сценариев вы должны разделить интересы домена и представления презентации, модель домена может быть разделена на несколько DTO, а несколько моделей домена могут быть объединены в DTO. Поэтому лучше создать DTO в многоуровневой архитектуре, даже если она будет такой же, как ваша модель.
Должны ли мы всегда использовать DTO для связи с уровнем обслуживания? Да, вы должны возвращать DTO по уровню обслуживания, так как вы общаетесь со своим репозиторием на уровне обслуживания с членами модели домена, сопоставляете их с DTO и возвращаетесь к контроллеру MVC и наоборот.
Можно ли корректировать доменные модели в зависимости от того, какие услуги нужны? Служба просто взаимодействует с методами репозитория и домена и доменными службами, вы должны решать бизнес в своем домене исходя из своих потребностей, и задача службы не состоит в том, чтобы сообщить домену, что нужно.
Если мы должны строго придерживаться DTO, должны ли они быть определены на уровне обслуживания?Да, попробуйте позже использовать DTO или ViewModel только потому, что они должны быть сопоставлены с членами домена на сервисном уровне, и не стоит помещать DTO в контроллеры вашего приложения (попробуйте использовать шаблон запроса ответа на сервисном уровне), ура !
источник
По моему опыту вы должны делать то, что практично. «Лучший дизайн - это самый простой дизайн, который работает», - Эйнштейн. С этим разум ...
Абсолютно все нормально! Если у вас есть доменные сущности, DTO и модели просмотра, то, включая таблицы базы данных, все поля в приложении повторяются в 4 местах. Я работал над большими проектами, в которых доменные сущности и модели просмотра работали просто отлично. Единственное исключение - если приложение распределено, а уровень обслуживания находится на другом сервере, и в этом случае DTO необходимо отправлять по проводам по причинам сериализации.
Обычно я бы согласился и сказал бы «нет», потому что модель предметной области, как правило, отражает бизнес-логику и обычно не формируется потребителем этой логики.
Если вы решите использовать их, я соглашусь и скажу «да», уровень обслуживания - идеальное место, так как он возвращает DTO в конце дня.
Удачи!
источник
Я опаздываю на эту вечеринку, но это такой распространенный и важный вопрос, на который я был вынужден ответить.
Под «услугами» вы подразумеваете «уровень приложений», описанный Эваном в синей книге ? Я предполагаю, что вы делаете, и в этом случае ответ заключается в том, что они не должны возвращать DTO. Я предлагаю прочитать главу 4 в синей книге под названием «Изоляция домена».
В этой главе Эванс говорит о слоях следующее:
Для этого есть веская причина. Если вы используете понятие частичного порядка в качестве меры сложности программного обеспечения то наличие уровня в зависимости от уровня выше повышает сложность, что снижает удобство обслуживания.
Применяя это к вашему вопросу, DTO действительно являются адаптером, который относится к уровню пользовательского интерфейса / презентации. Помните, что удаленное / межпроцессное взаимодействие - это как раз цель DTO (стоит отметить, что в этом посте Фаулер также спорит против того, чтобы DTO были частью уровня обслуживания, хотя он не обязательно говорит на языке DDD).
Если ваш прикладной уровень зависит от этих DTO, он зависит от уровня над собой, и ваша сложность возрастает. Я могу гарантировать, что это увеличит сложность обслуживания вашего программного обеспечения.
Например, что если ваша система взаимодействует с несколькими другими системами или типами клиентов, для каждого из которых требуется собственный DTO? Откуда вы знаете, какой DTO метод вашего приложения должен вернуть? Как бы вы решили эту проблему, если ваш язык не позволяет перегрузить метод (в данном случае, метод службы) на основе типа возвращаемого значения? И даже если вы придумали способ, зачем нарушать ваш прикладной уровень для поддержки проблемы уровня презентации?
В практическом плане это шаг по пути, который закончится архитектурой спагетти. Я видел такого рода деволюцию и ее результаты на собственном опыте.
Там, где я сейчас работаю, сервисы нашего уровня приложений возвращают доменные объекты. Мы не считаем это проблемой, поскольку уровень интерфейса (т.е. пользовательского интерфейса / представления) зависит от уровня домена, который находится ниже. ним. Кроме того, эта зависимость сводится к типу зависимости «только для ссылки», потому что:
a) Интерфейсный уровень может получить доступ только к этим объектам домена как возвращаемые значения только для чтения, полученные при обращении к прикладному уровню
b) методы служб на прикладном уровне принимают в качестве входных данных только «необработанные» входные данные (значения данных) или параметры объекта (для уменьшения количества параметров при необходимости), определенные на этом уровне. В частности, сервисы приложений никогда принимают объекты домена в качестве входных данных.
Интерфейсный уровень использует методы отображения, определенные в самом Интерфейсном уровне, для отображения из объектов Домена в DTO. Опять же, это позволяет DTO сосредоточиться на том, чтобы быть адаптерами, которые контролируются интерфейсным уровнем.
источник
Поздно к вечеринке, но я сталкиваюсь с точно такой же архитектурой и склоняюсь к «только DTO от обслуживания». Это главным образом потому, что я решил использовать только доменные объекты / агрегаты для поддержания валидности внутри объекта, то есть только при обновлении, создании или удалении. Когда мы запрашиваем данные, мы используем только EF в качестве хранилища и отображаем результат в DTO. Это позволяет нам оптимизировать запросы на чтение и не адаптировать их к бизнес-объектам, часто используя функции базы данных, поскольку они быстры.
Каждый метод обслуживания определяет свой собственный контракт и поэтому его легче поддерживать с течением времени. Я надеюсь.
источник
Поскольку Доменная Модель предоставляет терминологию ( Ubiquitous Language ) для всего вашего приложения, лучше широко использовать Доменную Модель.
Единственная причина использования ViewModels / DTO - это реализация шаблона MVC в вашем приложении для разделения
View
(любого уровня представления) иModel
(модели предметной области). В этом случае ваша презентация и модель предметной области слабо связаны.Я предполагаю, что вы говорите об услугах приложений / бизнеса / доменной логики.
Я предлагаю вам вернуть доменные объекты, когда вы можете. Если необходимо вернуть дополнительную информацию, допустимо вернуть DTO, который содержит несколько сущностей домена.
Иногда люди, которые используют платформы 3-й части, которые генерируют прокси для сущностей домена, сталкиваются с трудностями, открывая доменные сущности из своих сервисов, но это только вопрос неправильного использования.
Я бы сказал, что достаточно вернуть доменные объекты в 99,9% случаев.
Чтобы упростить создание DTO и сопоставление сущностей вашего домена в них, вы можете использовать AutoMapper .
источник
Если вы вернете часть своей доменной модели, она станет частью контракта. Контракт трудно изменить, так как от него зависят вещи вне вашего контекста. Таким образом, вам будет сложно изменить часть вашей доменной модели.
Очень важным аспектом доменной модели является то, что ее легко изменить. Это делает нас гибкими к изменяющимся требованиям домена.
источник
Я бы предложил проанализировать эти два вопроса:
Ваши верхние уровни (т.е. модели просмотра / просмотра / контроллеры) потребляют данные другим способом, чем тот, который предоставляет уровень домена? Если выполняется много картирования или даже логики, я предлагаю пересмотреть ваш дизайн: вероятно, он должен быть ближе к тому, как на самом деле используются данные.
Насколько вероятно, что вы глубоко измените свои верхние слои? (например, замена ASP.NET для WPF). Если это очень непохоже, а ваша архитектура не очень сложна, возможно, вам лучше разоблачить как можно больше доменных сущностей.
Боюсь, что это довольно широкая тема, и она действительно сводится к тому, насколько сложна ваша система и каковы ее требования.
источник
По моему опыту, если вы не используете шаблон OO UI (например, голые объекты), подвергать доменные объекты пользовательскому интерфейсу - плохая идея. Это связано с тем, что по мере роста приложения потребности пользовательского интерфейса меняются и вынуждают ваши объекты учитывать эти изменения. Вы заканчиваете тем, что служили 2 мастерам: UI и DOMAIN, что очень болезненно. Поверь мне, ты не хочешь быть там. Модель пользовательского интерфейса имеет функцию связи с пользователем, модель DOMAIN для хранения бизнес-правил, а модели постоянства - для эффективного хранения данных. Все они направлены на разные потребности приложения. Я нахожусь в середине записи в блоге об этом, добавлю это, когда это будет сделано.
источник