Почему REST Api не следуют шаблону дизайна Фасада

9

Сравнивая структуру REST [api] с OO-моделью, я вижу следующие сходства:

Обе:

  • Ориентированы на данные

    • REST = Ресурсы
    • ОО = объекты
  • Объемная работа вокруг данных

    • REST = объемные VERBS (Get, Post, ...) вокруг ресурсов
    • OO = продвигать работу вокруг объектов путем инкапсуляции

Тем не менее, хорошие методы OO не всегда основаны на REST apis при попытке применить шаблон фасада, например: в REST у вас нет 1 контроллера для обработки всех запросов И вы не скрываете сложность внутреннего объекта.

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

Аналогия между OO и REST

Напротив, REST способствует публикации ресурсов всех отношений с ресурсом и других по крайней мере в двух формах:

  1. через отношения иерархии ресурсов (контакт с идентификатором 43 состоит из адреса 453): /api/contacts/43/addresses/453

  2. через ссылки в ответе REST JSON:

>> GET /api/contacts/43
<< HTTP Response {
   id: 43, ...
   addresses: [{
      id: 453, ...
   }],
   links: [{
      favoriteAddress: {
          id: 453
      }
   }]
}

Основная сложность скрыта объектом A

Возвращаясь к ОО, шаблон проектирования фасада соблюдает отношение Low Couplingмежду объектом A и его « клиентом objectB » и High Cohesionдля этого объекта A и его внутренней композицией объектов ( objectC , objectD ). С Objecta интерфейс, это позволяет разработчику , чтобы ограничить воздействие на objectB из Objecta внутренних изменений (в objectC и objectD ), до тех пор , как Objecta API (операций) по - прежнему соблюдается.

В REST данные (ресурс), отношения (ссылки) и поведение (глаголы) разбиваются на различные элементы и доступны для Интернета.

Играя с REST, я всегда влияю на изменения кода между моим клиентом и сервером: потому что я имею High Couplingмежду своими Backbone.jsзапросами и Low Cohesionмежду ресурсами.

Я так и не понял, как разрешить мою Backbone.js javascript applicationсделку с обнаружением « ресурсов и возможностей REST », продвигаемой ссылками REST. Я понимаю, что WWW предназначен для обслуживания несколькими серверами, и что элементы OO должны были быть разбиты для обслуживания многими хостами, но для простого сценария, такого как «сохранение» страницы, показывающей контакт с его адресами, Я заканчиваю с:

GET /api/contacts/43?embed=(addresses)
[save button pressed]
PUT /api/contacts/43
PUT /api/contacts/43/addresses/453

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

Имея это в виду, если я не могу упростить свою разработку (шаблоны проектирования фасадов не применимы), и если я добавлю больше сложности своему клиенту (обработка транзакционного атомарного сохранения), какая польза от использования RESTful?

Alain
источник
1
Дай мне понять. Вы говорите, что вам необходимо обновить контакт со «встроенным» (составным) адресом, используя два вызова REST, один для контакта, а другой для его адреса. У вас есть Фасад для обработки обновлений контактов. В чем проблема с PUT /api/contacts/43каскадным обновлением внутренних объектов? У меня было много API, спроектированных так (главный URL читает / создает / обновляет «целые», а суб-URL обновляет фрагменты). Просто убедитесь, что вы не обновляете адрес, когда не требуется никаких изменений (по соображениям производительности).
Энтони Акциоли
@AnthonyAccioly, вы правильно поняли. Я попытался уточнить свой вопрос, добавив несколько изображений. Ваше предложение хорошо, и к этому я пришел к выводу: вручную управляйте моим запросом и используйте встроенный объект, чтобы отправить только один запрос на атомарность моего обновления. И все же: почему все в REST отталкивает меня от ОО-качеств или принудительных мер (инкапсуляция, ...), сглаживая мою модель (имея в виду множество контроллеров). Использование вашего решения дает 1 атомное обновление. Отказ от использования вашего решения влечет за собой новую ответственность разработчика и отсутствие правил API для предотвращения его выполнения.
Алена
Просто примечание: упомянутые вами «отношения иерархии ресурсов» связаны с тем, как можно решить закодировать информацию об отношениях в идентификаторе (в данном случае, в URL). Я не уверен, что это раскрытие информации - это то, что является частью REST или что-то, что он продвигает, просто решение, которое принимается самостоятельно, когда придумываете URL системы. Если вы считаете иначе, есть ли у вас какие-либо упоминания о том, что Рой Филдинг обсуждал этот вопрос в рамках REST?
Тьяго Сильва

Ответы:

7

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

Давайте не будем путать PODS (которые немного больше, чем структуры) и реальные объекты, имеющие поведение (например, Contactsкласс в вашем примере) 1 .

PODS в основном удобны для общения с репозиториями и бизнес-объектами. Они позволяют коду быть безопасным типом. Не больше, не меньше. Бизнес-объекты, с другой стороны, обеспечивают конкретное поведение , например, проверку ваших данных, их сохранение или использование для выполнения вычислений.

Итак, поведения - это то, что мы используем для измерения «сплоченности» 2 , и достаточно легко увидеть, что в вашем примере объекта есть некоторая сплоченность, даже если вы показываете только методы для манипулирования контактами верхнего уровня и нет методов для манипулирования адресами.

Что касается REST, вы можете увидеть службы REST в качестве хранилищ данных. Большая разница с объектно-ориентированным дизайном заключается в том, что существует (почти) только один выбор дизайна: у вас есть четыре основных метода (например, больше, если вы считаете HEAD), и, конечно, у вас есть много возможностей с URI, поэтому вы можете сделать изящный такие вещи, как передать много идентификаторов и получить большую структуру обратно. Не путайте данные, которые они передают, с операциями, которые они выполняют. Сплоченность и связь связаны с кодом, а не с данными .

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

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

В (правильном) объектно-ориентированном проектировании любое нетривиальное приложение будет выполнять гораздо более сложные операции, например, посредством композиции. У вас могут быть методы для выполнения более специализированных операций с данными, что должно быть так, потому что, хотя REST является протоколом API, OOD используется для создания целых пользовательских приложений! Вот почему измерение когезии и сцепления является основополагающим в OOD, но почти незначительным в REST.

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

Фактически, оказывается, что преимущества RESTful (в основном) описаны выше: это хороший шаблон для простых API по медленной среде. Это очень кешируется и может быть разорвано. Имеет мелкозернистый контроль над болтливостью и т. Д.

Я надеюсь, что это отвечает на ваш (довольно многогранный) вопрос :-)


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

2 http://en.wikipedia.org/wiki/Cohesion_(computer_science)

Sklivvz
источник
Вы правы, мне было трудно разобрать свой вопрос во многих аспектах, зафиксировать конкретную точку зрения, поскольку этот вопрос направлен на «неправильный» вывод, основанный на накоплении этих аспектов. Я постараюсь сейчас ответить на ваши вопросы во многих комментариях.
Алена
[текст 1] Я использовал слово «данные», чтобы абстрагироваться от мира OO и REST. Какое слово вы бы использовали для абстрагирования свойств в ОО и структуры данных в REST?
Алена
@ Ален "данные" в порядке, но я не хочу путать PODS и бизнес-объекты. Когда мы говорим об ООД, мы обычно говорим о втором. Первый - это удобство, и его можно почти так же легко найти в словаре, структуре или кортеже.
Скливвз
Да, я согласен, я использую Backbone.js, где при сохранении модели используется простая структура json. Здесь текст отражает мой реальный опыт написания кода.
Алена
[текст 3] Это ново для меня. Я думал, что сплоченность измеряется количеством временных методов, использующих определенное отношение ... Я предпочитаю ваш способ его просмотра.
Алена
1

Имея это в виду, если я не могу упростить свою разработку (шаблоны проектирования фасадов не применимы), и если я добавлю больше сложности своему клиенту (обработка транзакционного атомарного сохранения), какая польза от использования RESTful?

Ответ на вопрос «в чем польза от RESTful?» подробно проанализирован и объяснен здесь: http://www.ics.uci.edu/~fielding/pubs/dis Диссертация/ top.htm

Путаница в этом вопросе заключается в том, что речь идет не о характеристиках REST, а о том, как с ними справляться, а о том, что дизайн URL-адресов, которые вы создали для своей системы примеров, как-то связан с RESTful. В конце концов, REST заявляет, что существуют вещи, называемые ресурсами, и для тех, на кого нужно сослаться, должен быть указан идентификатор, но это не означает, что, скажем, сущности в вашей модели ER должны иметь соответствие 1-1 с созданными вами URL-адресами. (ни то, что URL не должны кодировать количество связей ER в модели).

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

Тиаго Сильва
источник
1

Это потому, что фасады являются «клугом»; Вы должны взглянуть на «API абстракция» и «Api Chaining». API представляет собой сочетание двух наборов функций: ввод-вывод и управление ресурсами. Локально, ввод / вывод в порядке, но в распределенной архитектуре (т.е. прокси, API-шлюз, очередь сообщений и т. Д.) Ввод / вывод используется совместно, и, таким образом, данные и функциональность дублируются и запутываются. Это приводит к сквозным архитектурным проблемам. Это изводит ВСЕ существующие apis.

Единственный способ решить эту проблему - абстрагировать функциональность ввода-вывода для API до обработчика до / после (например, handlerIntercepter в Spring / Grails или фильтр в Rails), чтобы функциональность можно было использовать в качестве монады и совместно использовать между экземплярами и внешними инструментов. Данные для запроса / ответа также необходимо экстернализовать в объекте, чтобы их можно было совместно использовать и перезагружать.

http://www.slideshare.net/bobdobbes/api-abstraction-api-chaining

Orubel
источник
0

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

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

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

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

JensG
источник
Я согласен с понятием слоя, но что вы подразумеваете под «программировать свой контроллер через него»?
Алена
1
Хочу подчеркнуть тот факт, что сам контроллер является настоящим сервисом. Интерфейс, обернутый вокруг всего этого, является просто средством для достижения чего-то. Любой интерфейс существует, чтобы облегчить доступ к упакованным функциям, так или иначе. GUI делает это для пользователей, сервисный API используется клиентами. Обе целевые аудитории хотят чего-то добиться с помощью вещей, скрытых за интерфейсом. Я согласен, что «программа» может быть не самой лучшей формулировкой для этого, но «контролировать контроллеры» тоже звучит неловко ;-)
JensG