Является ли сущность на стороне клиента антипаттерном?

Я раньше пользовался сервисом RIA, сейчас тестирую Breeze Sharp.

RIA и Breeze создают впечатление, что то, что вы видите на сервере / среднем уровне, это то, что вы видите на клиенте. Чтобы поддержать это, термин Entity используется как на клиенте, так и на сервере. Это действительно сущность, или это действительно модель представления или модель на клиенте?

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

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

2 ответа

Решение

Вы можете вызывать класс сущности на стороне клиента как угодно:-)

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

Клиент не является уровнем представления

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

Термины "сущность" и "DTO" означают разные вещи для разных людей. Мне нравится DDD-определение Эвана для "сущности" и определение Фаулера для "DTO" в PoEAA.

Сущности Breeze client квалифицируются как сущности Эванса: " Объекты, которые имеют различную идентичность, которая проходит во времени и в разных представлениях. Вы также слышите эти так называемые" ссылочные объекты " " [ Фаулер ]. Бриз-сущности - это не просто сумки с недвижимостью; у них также есть бизнес-логика, и вы можете расширить их своими собственными.

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

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

Отправить сущности или DTO?

Я собираюсь утверждать, что это ложная дихотомия.

Люди часто говорят, что "отправлять сущности по проводам - ​​это не шаблон. Всегда отправляйте DTO ". За этим плохо сформулированным указом стоит веская аргументация. Когда класс сущности клиента и сервера идентичен, вы связали реализацию сервера с реализацией клиента. Если модель изменяется на сервере, она должна меняться на клиенте и наоборот, даже если изменение относится только к одному из уровней. Это может помешать вашей способности независимо развивать код сервера и клиента. Мы можем принять эту связь как вопрос целесообразности (а целесообразность имеет значение!), Но никто не хочет этого.

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

Они концептуально связаны, конечно. У вас будет дьявольское время, преобразующее данные между двумя представлениями, если значение Customer сущность широко расходится с двух сторон. Это правда с или без явных DTO.

Давайте также признаем, что легче преобразовывать данные в обоих направлениях, когда классы фактически одинаковы. Вы платите налог на сопоставление, когда они различаются, и вы можете потерять возможность составлять запросы Breeze LINQ на клиенте. Вы можете оплатить налог, если хотите. Бриз не волнует.

Я склоняюсь к тому, чтобы начать с одних и тех же классов с обеих сторон и менять их по мере необходимости. Это хорошо сработало для большого процента классов в RIA Services и DevForce. Что наиболее важно, мне никогда не было трудно повторно разделять классы, когда возникла такая необходимость.

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

Когда использовать презентационные модели

Вы написали:

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

По моему опыту, это верно только в том случае, если вы предполагаете, что ваш клиент просто вставляет объекты на экран. Но я уже оговорил, что клиент - это приложение, а не уровень представления.

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

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

FWIW, у меня всегда есть "Модель представления" (AKA "ViewModel") в моих приложениях для управления действиями View. Так что я не спрашиваю себя "ПМ или Модель?". Вместо этого я выбираю либо привязывать данные визуальные элементы управления непосредственно к объектам модели, которые я предоставляю через API виртуальной машины, либо вместо этого привязываю их к промежуточной "Модели представления элементов" (AKA "Item ViewModel"), которая охватывает некоторые объекты. Какой путь я выберу, это решение по заявке. На практике я начинаю с привязки к сущностям и рефакторинга к "Item ViewModel", когда и когда это необходимо.

В любом случае я создам PM (VM), которые мне нужны на клиенте. Если мне нужен "Item ViewModel", я создаю его и на клиенте. Я не прошу мой сервер подготовить DTO для моего клиента для отображения. Для меня это анти-паттерн, потому что он связывает сервер с клиентом.

Как? Если разработчику необходимо изменить экран на клиенте, ему, возможно, придется подождать, пока кто-нибудь предоставит конечную точку сервера поддержки и DTO. Теперь мы должны скоординировать графики выпуска сервера и клиента, хотя стимулом для изменения было требование клиента, а не требования сервера.

Сервисное загрязнение

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

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

Делать исключения

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

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

Надеюсь это поможет.

Я не знаю, нравится ли мне идея иметь другую модель домена на клиенте. Это приведет к легендарной проблеме, с которой мы все боролись годами, - распространению бизнес-логики на клиента. Я имею в виду интерфейс, такой как приложение Windows Forms или XAML или HTML5, при условии, что приложение подключено к серверу. Разве это не поддерживается, если сущности существуют только на уровне домена на сервере и защищены службой приложений?

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

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

Другие вопросы по тегам