Является ли сущность на стороне клиента антипаттерном?
Я раньше пользовался сервисом 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, заключается в том, чтобы делиться этими бизнес-правилами с клиентом, чтобы избежать дублирования. Это также заставит те же объекты быть переданы клиенту.
Я поддерживаю идею о том, чтобы модели клиента и сервера развивались раздельно - модели на клиенте и доменные объекты на сервере. Затраты связаны с переводом моделей, сервисом блоттинга приложений, поиском и проверкой, если бизнес-правила сложны. Вы упомянули о некоторых из них в своем ответе.