Почему я должен изолировать объекты моего домена от уровня представления?

StackOverflow https://stackoverflow.com/questions/821276

Вопрос

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

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

Поэтому я ищу какие-то конкретные причины, которые я мог бы использовать для подтверждения этого.В частности:

  1. Почему мы не должны использовать объекты домена в нашем уровне представления?
    (если ответ очевиден, "развязка", то, пожалуйста, объясните, почему это важно в данном контексте)
  2. Должны ли мы использовать дополнительные объекты или конструкции, чтобы изолировать объекты нашего домена от интерфейса?
Это было полезно?

Решение

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

Лично я считаю, что лучший способ приблизиться к вещам - это строгое соблюдение парадигмы интерфейса; то есть уровень вашего бизнес-объекта предоставляет интерфейс, который является единственным способом связи с ним; никакие подробности реализации (т.е. доменные объекты) об интерфейсе не предоставляются. Да, это означает, что вы должны реализовать свои доменные объекты в двух местах; ваш уровень интерфейса и в вашем уровне BO. Но это переопределение, хотя на первый взгляд это может показаться дополнительной работой, помогает навязать разделение, которое сохранит ТОННЫ работы в какой-то момент в будущем.

Другие советы

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

Ну, вместо того, чтобы загружать CompanyObject, который мог бы содержать ссылки на подписки или, кто знает, что еще, я мог бы отправить обратно DTO с именем и идентификатором.Это хорошее применение, ИМХО.

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

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

Идея о том, что кто-то поместит проверку в свой бизнес-объект?Что ж, я говорю, что это хорошо.Ваш пользовательский интерфейс не должен нести единоличную ответственность за проверку ваших бизнес-объектов.Ваш бизнес-уровень ДОЛЖЕН выполните его собственную проверку.

Зачем вам помещать код генерации пользовательского интерфейса в объект busienss?В моем случае у меня есть отдельные объекты, которые генерируют код пользовательского интерфейса отдельно от пользовательского интерфейса.У меня есть объекты sperate, которые преобразуют мои бизнес-объекты в Xml, идея о том, что вы должны разделять свои слои, чтобы предотвратить этот тип загрязнения, настолько чужда мне, потому что зачем вам вообще помещать код генерации HTML в бизнес-объект...

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

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

Вы делаете это по той же причине, по которой вы не допускаете SQL на страницы ASP / JSP.

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

Вы хотите повторно использовать этот изящный виджет пользовательского интерфейса в другом приложении? Ну, вам нужно создать базу данных с этим именем, этими двумя схемами и этими 18 таблицами. Вы также должны настроить Hibernate и Spring (или выбранные вами фреймворки) для проведения бизнес-валидации. О, вы также должны включить эти 85 других не связанных классов, потому что на них есть ссылки на бизнес-уровне, который просто находится в том же файле.

Я не согласен.

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

Вопреки распространенному мнению, «доменные объекты» и " Объекты ценности " может счастливо сосуществовать на уровне представления. И это лучший способ сделать это - вы получаете выгоду от обоих миров, уменьшая дублирование (и стандартный код) с объектами домена; и адаптация и концептуальное упрощение использования объектов значений в запросах.

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

Проблемы главным образом связаны с тем, что модель предметной области необходимо разрезать на более мелкие части, чтобы можно было сериализовать ее без ссылки на всю базу данных. Это усложняет использование на сервере. Важные ссылки отсутствуют. Некоторые типы также не сериализуемы и не могут быть отправлены клиенту. Например, «Тип» или любой универсальный класс. Они должны быть не универсальными, а Type должен быть передан в виде строки. Это создает дополнительные свойства для сериализации, они избыточны и сбивают с толку.

Другая проблема заключается в том, что сущности в пользовательском интерфейсе не подходят. Мы используем привязку данных, и многие объекты имеют множество избыточных свойств только для целей пользовательского интерфейса. Кроме того, в модели сущностей есть много «BrowsableAttribute» и других. Это действительно плохо.

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

Ответ зависит от масштаба вашего приложения.


Простое CRUD-приложение (Создание, чтение, обновление, Удаление)

Для базовых crud-приложений у вас нет никакой функциональности.Добавление DTO поверх сущностей было бы пустой тратой времени.Это увеличило бы сложность без увеличения масштабируемости.

enter image description here


Умеренно сложное приложение без использования CRUD

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

Добавление DTO в этом случае является хорошей идеей по нескольким причинам:

  • Уровень представления может видеть только подмножество полей, которые есть у объекта.Вы инкапсулируете Сущности
  • Нет связи между бэкэндом и фронтэндом
  • Если у вас есть бизнес-методы внутри сущностей, но не в DTO, то добавление DTO означает, что внешний код не может разрушить состояние вашей сущности.

enter image description here


Сложное Корпоративное приложение

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

enter image description here

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

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

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

Интерфейсы - это входные данные и представления, предоставляемые для правильно смоделированного и инвариантного функционального ядра.

Черт возьми, я клянусь в этой настойчивости.

В любом случае, это еще один пример того же: закон Парнаса гласит, что модуль должен хранить секрет, а секрет - это требование, которое может измениться. (У Боба Мартина есть правило, которое является еще одной версией этого.) В такой системе, как эта, презентация может изменяться независимо от домена . Например, компания, которая поддерживает цены в евро и использует французский язык в офисах компании, но хочет представить цены в долларах с текстом на китайском языке. домен такой же; презентация может измениться. Итак, чтобы минимизировать хрупкость системы & # 8212; то есть количество вещей, которые необходимо изменить, чтобы реализовать изменение в требованиях & # 8212; Вы разделяете проблемы.

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

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

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

Конечно, легко попасть в ловушку "Ну, в моей компании мы заботимся только об английском языке, запускаем наш веб-сайт на LAMP (Linux, Apache, MySQL и PHP), и все используют одну и ту же версию Firefox". Но что будет через 5 или 10 лет?

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

http: // galaxy .andromda.org / документы / AndroMDA-документация / AndroMDA пробивной стартером-Java / Java / index.html

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

Единственная причина, по которой я не вижу преимуществ в использовании view model, заключается в том, что ваш проект небольшой и достаточно простой, чтобы представления были привязаны непосредственно к каждому свойству вашей модели.Но если в будущем требования изменятся и некоторые элементы управления в представлениях не будут привязаны к модели, и у вас не будет концепции модели представления, вы начнете добавлять исправления во многих местах, и у вас появится устаревший код, который вам не понравится.Конечно, вы можете провести некоторый рефакторинг, чтобы преобразовать вашу view-model в view-viewmodel и следовать принципу YAGNI, не добавляя код, если вам это не нужно, но для меня гораздо более рекомендуемой практикой является добавление уровня представления, отображающего только объекты view-model.

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

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

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

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

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

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

Проекты, управляемые доменом, лучше всего работают при использовании в сочетании с ортогональным набором структур функциональных доменов (таких как ORM, GUI, Workflow и т. д.). Всегда помните, что только в смежности внешнего уровня семантика домена должна быть представлена. Обычно это внешний интерфейс (GUI) и постоянный внутренний интерфейс (RDBM, ORM). Любые эффективно разработанные промежуточные слои могут и должны быть инвариантными в отношении домена.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top