¿Por qué REST Api no sigue el patrón de diseño de Fachada?

9

Al comparar la estructura REST [api] con un modelo OO, veo estas similitudes:

Ambos:

  • Están orientados a datos

    • REST = Recursos
    • OO = Objetos
  • Operación envolvente alrededor de datos

    • REST = surround VERBS (Get, Post, ...) alrededor de los recursos
    • OO = promover la operación alrededor de objetos por encapsulación

Sin embargo, las buenas prácticas de OO no siempre se encuentran en las API REST cuando se trata de aplicar el patrón de fachada, por ejemplo: en REST, no tiene 1 controlador para manejar todas las solicitudes Y no oculta la complejidad interna del objeto.

Relación de objeto simple entre 2 conceptos

Analogía entre OO y REST

Por el contrario, REST promueve la publicación de recursos de todas las relaciones con un recurso y otro en al menos dos formas:

  1. a través de relaciones de jerarquía de recursos (un contacto de id 43 se compone de una dirección 453): /api/contacts/43/addresses/453

  2. a través de enlaces en una respuesta REST json:

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

Complejidad básica oculta por objetoA

Volviendo a OO, el patrón de diseño de fachada respeta a Low Couplingentre un objeto A y su ' cliente objeto B ' y High Cohesionpara este objeto A y su composición interna de objetos (objeto C , objeto D ). Con la Objecta interfaz, esto permite a un desarrollador para limitar el impacto sobre objectB de los Objecta cambios internos (en objectC y objectD ), siempre y cuando el Objecta API (operaciones) todavía son respetados.

En REST, los datos (recursos), las relaciones (enlaces) y el comportamiento (verbos) se explotan en diferentes elementos y están disponibles en la web.

Jugando con REST, siempre tengo un impacto en los cambios de código entre mi cliente y servidor: porque tengo High Couplingentre mis Backbone.jssolicitudes y Low Cohesionentre recursos.

Nunca descubrí cómo dejar que mi Backbone.js javascript applicationtrato con el descubrimiento de " Recursos y características REST " promovido por los enlaces REST. Entiendo que la WWW está destinada a ser servida por múltiples servidores, y que los elementos de OO tuvieron que explotarse para ser atendidos por muchos hosts allí, pero para un escenario simple como "guardar" una página que muestra un contacto con sus direcciones, Termino con:

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

lo que me llevó a mover la acción de ahorro de la responsabilidad transaccional atómica en las aplicaciones de los navegadores (ya que dos recursos se pueden abordar por separado).

Teniendo esto en cuenta, si no puedo simplificar mi desarrollo (los patrones de diseño de fachadas no son aplicables) y si aporto más complejidad a mi cliente (manejo del ahorro atómico transaccional), ¿cuál es el beneficio de estar RESTful?

Alain
fuente
1
Déjame entender. Está diciendo que debe actualizar un contacto con una dirección vinculada "integrada" (composición) utilizando dos llamadas REST, una para el contacto y otra para su dirección. Tiene una Fachada para manejar la actualización de contactos. ¿Cuál es el problema con hacer que PUT /api/contacts/43las actualizaciones de los objetos internos en cascada? Tenía muchas API diseñadas de esta manera (la URL maestra lee / crea / actualiza el "todo" y las sub urls actualizan las piezas). Solo asegúrese de no actualizar la dirección cuando no se requieran cambios (por razones de rendimiento).
Anthony Accioly
@AnthonyAccioly, entendiste correctamente. Intenté aclarar mi pregunta agregando algunas imágenes. Su sugerencia es buena y esa es también la conclusión con la que llegué: controlar manualmente mi solicitud y usar un objeto incrustado para enviar solo una solicitud para mantener mi actualización atómica. Aún así: ¿Por qué todo en REST me aleja de las cualidades OO o la aplicación (encapsulación, ...) al aplanar mi modelo (lo que implica muchos controladores)? Usar su solución le da 1 actualización atómica. No usar su solución le da al desarrollador una nueva responsabilidad y no hay reglas en la API para evitar que lo haga.
Alain
Solo una nota: las "relaciones de jerarquía de recursos" que mencionó son una cuestión de cómo uno podría decidir codificar la información de la relación en un identificador (en este caso, una URL). No estoy seguro de que esta exposición de información sea algo que forme parte de REST o algo que promueva, solo una decisión que uno toma por su cuenta al crear las URL de un sistema. Si cree lo contrario, ¿tiene alguna referencia de Roy Fielding discutiendo este asunto como parte de REST?
Thiago Silva

Respuestas:

7

Creo que los objetos solo se construyen correctamente alrededor de comportamientos coherentes y no alrededor de datos. Provocaré y diré que los datos son casi irrelevantes en el mundo orientado a objetos. De hecho, es posible y en ocasiones común tener objetos que nunca devuelven datos, por ejemplo, "sumideros de registros" u objetos que nunca devuelven los datos que se pasan, por ejemplo, si calculan propiedades estadísticas.

No confundamos los PODS (que son poco más que estructuras) y los objetos reales que tienen comportamientos (como la Contactsclase en su ejemplo) 1 .

Los PODS son básicamente una conveniencia utilizada para hablar con repositorios y objetos comerciales. Permiten que el código sea de tipo seguro. Ni mas ni menos. Los objetos de negocio, por otro lado, proporcionan comportamientos concretos , como validar sus datos, almacenarlos o usarlos para realizar un cálculo.

Entonces, los comportamientos son lo que usamos para medir la "cohesión" 2 , y es bastante fácil ver que en su ejemplo de objeto hay cierta cohesión, aunque solo muestre métodos para manipular contactos de nivel superior y ningún método para manipular direcciones.

Con respecto a REST, puede ver los servicios REST como repositorios de datos. La gran diferencia con el diseño orientado a objetos es que hay (casi) una sola opción de diseño: tiene cuatro métodos básicos (más HEAD, por ejemplo, si cuenta ) y, por supuesto, tiene un gran margen de maniobra con los URI para que pueda hacer ingenioso cosas como pasar muchos identificadores y recuperar una estructura más grande. No confunda los datos que pasan con las operaciones que realizan. La cohesión y el acoplamiento tienen que ver con el código y no con los datos .

Claramente, los servicios REST tienen una alta cohesión (todas las formas de interactuar con un recurso están en el mismo lugar) y un bajo acoplamiento (cada repositorio de recursos no requiere conocimiento de los demás).

Sin embargo, el hecho básico sigue siendo que REST es esencialmente un patrón de repositorio único para sus datos. Esto tiene consecuencias, porque es un paradigma construido alrededor de la accesibilidad fácil a través de un medio lento, donde existe un alto costo para la "charla": los clientes generalmente quieren realizar la menor cantidad de operaciones posible, pero al mismo tiempo solo reciben los datos que necesitan . Esto determina qué tan profundo será el árbol de datos que va a enviar de vuelta.

En el diseño orientado a objetos (correcto), cualquier aplicación no trivial realizará operaciones mucho más complejas, por ejemplo, a través de la composición. Podría tener métodos para realizar operaciones más especializadas con los datos, lo cual debe ser así, porque si bien REST es un protocolo API, ¡OOD se usa para crear aplicaciones completas orientadas al usuario! Es por eso que medir la cohesión y el acoplamiento es fundamental en OOD, pero casi insignificante en REST.

Ahora debería ser obvio que analizar el diseño de datos con conceptos OO no es una forma confiable de medirlo: ¡es como comparar manzanas y naranjas!

De hecho, resulta que los beneficios de ser RESTful son (principalmente) los descritos anteriormente: es un buen patrón para API simples en un medio lento. Es muy almacenable en caché y shardable. Tiene control de grano fino sobre chattiness, etc.

Espero que esto responda a su pregunta (bastante polifacética) :-)


1 Este problema es parte de un conjunto más amplio de problemas conocido como desajuste de impedancia relacional de objetos . Los defensores de los ORM generalmente están en el campo que explora las similitudes entre el análisis de datos y el análisis de comportamiento, pero los ORM han sido criticados últimamente porque parecen no resolver realmente el desajuste de impedancia y se consideran abstracciones con fugas .

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

Sklivvz
fuente
Tiene razón, tuve dificultades para explotar mi pregunta en muchos aspectos, para concretar un punto específico, ya que la pregunta aborda una conclusión "incorrecta" basada en la acumulación de estos aspectos. Intentaré ahora responder a sus puntos en muchos comentarios.
Alain el
[texto 1] Usé la palabra "datos" para hacer un resumen del mundo OO y REST. ¿Qué palabra usarías para abstraer propiedades en OO y estructura de datos en REST?
Alain
@Alain "datos" está bien, pero mi punto es no confundir PODS y objetos comerciales. Cuando hablamos de OOD, generalmente hablamos del segundo. Los primeros son convenientes, y podría pensarse casi tan fácilmente en un diccionario, estructura o tupla.
Sklivvz
Sí, estoy de acuerdo, uso Backbone.js donde guardar un modelo es usar una estructura json simple. Aquí es donde el texto refleja mi experiencia real de codificación.
Alain el
[texto 3] Esto es nuevo para mí. Pensé que la cohesión se medía por la cantidad de tiempo que los métodos usan una relación específica ... Prefiero su forma de verlo.
Alain
1

Teniendo esto en cuenta, si no puedo simplificar mi desarrollo (los patrones de diseño de fachadas no son aplicables) y si aporto más complejidad a mi cliente (manejo del ahorro atómico transaccional), ¿cuál es el beneficio de estar RESTful?

La respuesta a "¿dónde está el beneficio de estar RESTANTE?" se analiza a fondo y se explica aquí: http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Sin embargo, la confusión en esta pregunta es que no se trata de las características de REST y de cómo lidiar con ellas, sino de asumir que el diseño de las URL que creó para su sistema de ejemplo tiene algo que ver con ser RESTful. Después de todo, REST afirma que hay cosas llamadas recursos y se debe proporcionar un identificador para aquellos a los que se debe hacer referencia, pero no dicta que, por ejemplo, las entidades en su modelo de ER deben tener una correspondencia de 1-1 con las URL que creó (ni que las URL deben codificar la cardinalidad de las relaciones ER en el modelo).

En el caso de contactos y direcciones, podría haber definido un recurso que represente conjuntamente estas informaciones como una sola unidad, aunque desee extraer y guardar estas informaciones en, por ejemplo, diferentes tablas de bases de datos relacionales, cada vez que se PONEN o PUBLICEN .

Thiago Silva
fuente
1

Eso es porque las fachadas son un 'kludge'; deberías echar un vistazo a 'abstracción api' y 'encadenamiento api'. La API es una combinación de dos conjuntos de funcionalidades: E / S y gestión de recursos. Localmente, la E / S está bien pero dentro de una arquitectura distribuida (es decir, proxy, puerta de API, cola de mensajes, etc.) la E / S se comparte y, por lo tanto, los datos y la funcionalidad se duplican y se enredan. Esto conduce a una preocupación transversal arquitectónica. Esto afecta a TODAS las API existentes.

La única forma de resolver esto es abstrayendo la funcionalidad de E / S para la API a un controlador previo / posterior (como un controlador Intercepter en Spring / Grails o un filtro en Rails) para que la funcionalidad se pueda utilizar como mónada y compartir entre instancias y externos estampación. Los datos para solicitud / respuesta también deben externalizarse en un objeto para que también puedan compartirse y recargarse.

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

Orubel
fuente
0

Si comprende su servicio REST, o en general cualquier tipo de API, solo como una interfaz adicional expuesta a los clientes para que puedan programar sus controladores a través de él, de repente se vuelve fácil. El servicio no es más que una capa adicional sobre su lógica de negocios.

En otras palabras, no tiene que dividir la lógica de negocios entre múltiples controladores, como lo hizo en la imagen de arriba, y lo más importante, no debería hacerlo. Las estructuras de datos que se usan para intercambiar datos no necesitan coincidir con las estructuras de datos que usa internamente, pueden ser bastante diferentes.

Es avanzado y ampliamente aceptado que es una mala idea poner cualquier lógica de negocios en el código de la interfaz de usuario. Pero cada interfaz de usuario es solo una especie de interfaz (la I en la interfaz de usuario) para controlar la lógica de negocio detrás. En consecuencia, parece obvio que también es una mala idea poner cualquier lógica de negocio en la capa de servicio REST, o en cualquier otra capa API.

Conceptualmente hablando, no hay mucha diferencia entre UI y API de servicio.

JensG
fuente
Estoy de acuerdo con la noción de capa, pero ¿qué quiere decir con "programar su controlador a través de ella"?
Alain
1
Quiero enfatizar el hecho de que el controlador en sí mismo es el servicio real. La interfaz envuelta alrededor de todo es simplemente un medio para lograr algo. Cualquier interfaz existe para facilitar el acceso a la funcionalidad envuelta, de una forma u otra. Una GUI hace esto para usuarios humanos, los clientes utilizan una API de servicio. Ambos públicos objetivo quieren lograr algo con las cosas envueltas detrás de la interfaz. Estoy de acuerdo en que "programa" puede no ser la mejor redacción para eso, pero "controlar a los controladores" también suena incómodo ;-)
JensG