Должны ли службы всегда возвращать DTO или они могут также возвращать модели домена?

Я (ре) разрабатываю крупномасштабное приложение, мы используем многоуровневую архитектуру на основе DDD.

У нас есть MVC с уровнем данных (реализация репозиториев), доменный уровень (определение модели домена и интерфейсов - репозитории, службы, единица работы), уровень обслуживания (реализация услуг). До сих пор мы используем модели домена (в основном сущности) по всем слоям, и мы используем DTO только как модели представления (в контроллере, службе возвращается модель (и) домена, а контроллер создает модель представления, которая передается в представление).

Я читал бесчисленные статьи об использовании, а не использовании, сопоставлении и передаче DTO. Я понимаю, что нет никакого окончательного ответа, но я не уверен, нормально ли он или нет, возвращая модели домена из сервисов в контроллеры. Если я возвращаю модель домена, она все равно никогда не переходит к представлению, так как контроллер всегда создает модель представления с учетом вида - в этом случае она кажется законной. С другой стороны, это не кажется правильным, когда модель домена покидает бизнес-уровень (уровень обслуживания). Иногда службе необходимо вернуть объект данных, который не был определен в домене, и нам нужно либо добавить новый объект в домен, который не отображается, либо создать объект POCO (это уродливо, так как некоторые службы возвращают модели домена, некоторые эффективно возвращать DTO).

Вопрос: если мы строго используем модели просмотра, нормально ли возвращать модели домена до контроллера, или мы всегда должны использовать DTO для связи со слоем услуг? Если да, нормально ли настраивать модели домена на основе того, какие услуги нужны? (Честно говоря, я так не думаю, так как службы должны потреблять то, что у домена.) Если мы должны строго придерживаться DTO, следует ли их определять на уровне обслуживания? (Я так думаю.) Иногда ясно, что мы должны использовать DTO (например, когда служба выполняет много бизнес-логики и создает новые объекты), иногда ясно, что мы должны использовать только модели домена (например, когда служба членства возвращает anemic User ( s) - кажется, не имеет смысла создавать DTO, что совпадает с моделью домена), но я предпочитаю последовательность и хорошие практики.

Статья Домен против DTO и ViewModel - как и когда их использовать? (а также некоторые другие статьи) очень похожа на мою проблему, но она не ответьте на этот вопрос (ы). Статья Должен ли я использовать DTO в шаблоне репозитория с EF? также аналогичен, но он не имеет отношения к DDD.

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

Как всегда, спасибо.

Ответ 1

он не чувствует себя хорошо, когда модель домена покидает бизнес-уровень (уровень обслуживания)

Заставляет вас чувствовать, что вы просто вытаскиваете кишки? По словам Мартина Фаулера: уровень сервиса определяет приложение boundery, он инкапсулирует домен. Другими словами, он защищает домен.

Иногда службе требуется вернуть объект данных, который не был определен в домене

Можете ли вы привести пример этого объекта данных?

Если мы должны строго придерживаться DTO, должны ли они быть определены в уровне обслуживания?

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

нормально ли возвращать модели домена до контроллера, или мы всегда должны использовать DTO для связи с уровнем обслуживания?

A DTO - объект ответа/запроса, имеет смысл, если вы используете его для связи. Если вы используете модели домена в своем слое презентации (MVC-Controllers/View, WebForms, ConsoleApp), тогда уровень презентации тесно связан с вашим доменом, любые изменения в домене требуют изменения ваших контроллеров.

кажется, что не имеет смысла создавать DTO, что совпадает с моделью домена)

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

DTO может добавить дополнительную сложность для вашего приложения, но также ваши слои. DTO - дорогая функция вашей системы, они не бесплатны.

Зачем использовать DTO

В этой статье представлены как преимущества, так и недостатки использования DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Сводка выглядит следующим образом:

Когда использовать

  • Для крупных проектов.
  • Срок службы проекта - 10 лет и старше.
  • Стратегическое, критически важное приложение.
  • Большие команды (более 5)
  • Разработчики распределяются географически.
  • Домен и презентация разные.
  • Сокращение обмена служебными данными (исходная цель DTO)

Если не использовать

  • Проект малого и среднего размера (максимум 5 членов)
  • Срок службы проекта составляет 2 года.
  • Нет отдельной команды для GUI, бэкэнд и т.д.

Аргументы против DTO

Аргументы с DTO

  • Без DTO презентация и домен тесно связаны. (Это нормально для небольших проектов.)
  • Интерфейс/стабильность API
  • Может обеспечить оптимизацию для уровня представления, возвращая DTO, содержащий только те атрибуты, которые абсолютно необходимы. Используя linq-projection, вам не нужно тянуть весь объект.
  • Чтобы снизить затраты на разработку, используйте инструменты генерации кода.

Ответ 2

По моему опыту вы должны делать то, что практично. "Лучший дизайн - это самый простой дизайн, который работает" - Эйнштейн. С этим ум...

если мы строго используем модели просмотра, нормально ли возвращать модели домена до контроллера, или мы всегда должны использовать DTO для связи со слоем услуг?

Абсолютно нормально! Если у вас есть объекты домена, DTO и модели просмотра, а также таблицы базы данных, все поля в приложении повторяются в 4 местах. Я работал над крупными проектами, в которых объекты домена и модели просмотра работали нормально. Единственным искушением в этом случае является распространение приложения и уровень обслуживания на другом сервере, и в этом случае DTO должны отправлять по сети по причинам сериализации.

Если да, нормально ли настраивать модели домена на основе того, какие услуги нужны? (Честно говоря, я так не думаю, так как службы должны потреблять то, что у домена).

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

Если мы должны строго придерживаться DTO, следует ли их определять на уровне обслуживания? (Я думаю так.)

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

Удачи!

Ответ 3

Кажется, что ваше приложение достаточно большое и сложное, поскольку вы решили использовать подход DDD. Не возвращайте ваши poco-сущности или так называемые доменные сущности и объекты-значения в слое вашего сервиса. Если вы хотите это сделать, то удалите слой обслуживания, потому что он вам больше не нужен! Объекты View Model или Data Transfer должны находиться в слое Service, потому что они должны отображаться на членов модели домена и наоборот. Так зачем вам нужен DTO? В сложных приложениях с большим количеством сценариев вы должны разделить интересы домена и представления презентации, модель домена может быть разделена на несколько DTO, а несколько моделей домена могут быть объединены в DTO. Так что лучше создать свой DTO в многоуровневой архитектуре, даже если он будет таким же, как ваша модель.

Должны ли мы всегда использовать DTO для связи с уровнем обслуживания? Да, вы должны возвращать DTO по уровню обслуживания, так как вы общаетесь со своим репозиторием на уровне обслуживания с членами модели домена, сопоставляете их с DTO и возвращаете контроллеру MVC и наоборот.

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

Если мы должны строго придерживаться DTO, должны ли они быть определены на уровне обслуживания? Да, попробуйте позже использовать DTO или ViewModel только потому, что они должны быть сопоставлены с членами домена на сервисном уровне, и не рекомендуется помещать DTO в контроллеры вашего приложения (попробуйте использовать шаблон запроса ответа на сервисном уровне), ура !

Ответ 4

До сих пор мы используем модели домена (в основном сущности) на всех уровнях, и мы используем DTO только как модели просмотра (в контроллере, службе возвращается модель (и) модели домена, а контроллер создает модель представления, которая передается в представление).

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

Единственной причиной использования ViewModels/DTO является реализация шаблона MVC в вашем приложении для разделения View (любого уровня представления ) и Model (модель домена). В этом случае ваша презентация и модель домена слабо связаны.

Иногда службе требуется вернуть объект данных, который не был определен в домене, а затем мы либо должны добавить новый объект в домен, который не отображается, либо создать объект POCO (это уродливо, так как некоторые службы возвращают домен модели, некоторые эффективно возвращают DTO).

Я предполагаю, что вы говорите о сервисах Application/Business/Domain Logic.

Я предлагаю вам вернуть объекты домена, когда сможете. Если необходимо вернуть дополнительную информацию, допустимо вернуть DTO, который содержит несколько доменных объектов.

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

Вопрос: если мы строго используем модели просмотра, нормально ли возвращать модели домена до контроллера, или мы всегда должны использовать DTO для связи со слоем услуг?

Я бы сказал, что достаточно вернуть объекты домена в 99,9% случаев.

Чтобы упростить создание DTO и отобразить объекты домена в них, вы можете использовать AutoMapper.

Ответ 5

Я бы предложил проанализировать эти два вопроса:

  1. Являются ли ваши верхние слои (например, view & view models/controller) потребляющими данные по-другому, чем раскрывается слой домена? Если выполняется много картографирования или даже логика, я предлагаю пересмотреть ваш дизайн: вероятно, он должен быть ближе к тому, как данные фактически используются.

  2. Насколько вероятно, что вы глубоко меняете свои верхние слои? (например, замена ASP.NET для WPF). Если это очень непохоже, и ваша архитектура не очень сложна, вам может быть лучше разоблачить столько доменных объектов, сколько сможете.

Я боюсь, что это довольно широкая тема, и это действительно зависит от сложности вашей системы и ее требований.

Ответ 6

Я опаздываю на эту вечеринку, но это такой распространенный и важный вопрос, на который я был вынужден ответить.

Под "услугами" вы подразумеваете "прикладной уровень", описанный Эваном в синей книге? Я предполагаю, что вы делаете, и в этом случае ответ заключается в том, что они не должны возвращать DTO. Я предлагаю прочитать главу 4 в синей книге под названием "Изоляция домена".

В этой главе Эванс говорит следующее о слоях:

Разбейте сложную программу на слои. Разрабатывайте дизайн внутри каждого слоя, который является связным и зависит только от слоев ниже.

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

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

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

Например, что если ваша система взаимодействует с несколькими другими системами или типами клиентов, для каждого из которых требуется собственный DTO? Как вы узнаете, какой DTO метод вашего сервиса приложений должен вернуть? Как бы вы решили эту проблему, если ваш язык не позволяет перегрузить метод (в данном случае, метод службы) на основе возвращаемого типа? И даже если вы придумали способ, зачем нарушать ваш прикладной уровень для поддержки проблемы уровня презентации?

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

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

a) Интерфейсный уровень может получить доступ только к этим объектам домена как возвращаемые значения только для чтения, полученные при обращении к прикладному уровню

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

Интерфейсный уровень использует методы отображения, определенные в самом Интерфейсном уровне, для отображения из объектов Домена в DTO. Опять же, это позволяет DTO сосредоточиться на том, чтобы быть адаптерами, которые контролируются интерфейсным уровнем.

Ответ 7

По моему опыту, если вы не используете шаблон UO UI (например, обнаженные объекты), разоблачение объектов домена в пользовательском интерфейсе - плохая идея. Это потому, что по мере того, как приложение растет, потребности в пользовательском интерфейсе изменяются и заставляют ваши объекты учитывать эти изменения. В итоге вы получаете 2 мастера: UI и DOMAIN, что является очень болезненным опытом. Поверь мне, ты не хочешь быть там. Модель пользовательского интерфейса имеет функцию связи с пользователем, модель DOMAIN для ведения бизнес-правил, а модели персистентности - эффективное хранение данных. Все они затрагивают различные потребности приложения. Я нахожусь в середине написания сообщения в блоге об этом, добавлю его, когда это будет сделано.