¿Por qué es una mala idea compartir una interfaz entre el servidor y el cliente?

12

Estaba leyendo la documentación de Spring Cloud Netflix cuando descubrí una forma de compartir una interfaz entre un servidor HTTP y su cliente. Usan este ejemplo para microservicios, aunque no hay ninguna razón por la cual no se puede extender a la comunicación HTTP genérica:

// The shared interface, in a common library
public interface UserService {
    @RequestMapping(method = GET, value = "/users/{id}")
    User getUser(@PathVariable long id);
}

// The controller, on the server
@RestController
public class UserResource implements UserService {
}

// The same interface used for the client
@FeignClient("users")
public interface UserClient extends UserService {
}

Esto define una interfaz que se usa como un servidor (The Spring lo @RestControllerconvierte en un servidor HTTP) y un cliente (The Feign @FeignClientlo configura para el uso del cliente HTTP). Las implementaciones de clase de servidor y cliente se pueden usar en proyectos separados, pero aún usan la misma interfaz para garantizar que los tipos coincidan.

Sin embargo, debajo del ejemplo ponen la siguiente advertencia:

Nota: Por lo general, no es recomendable compartir una interfaz entre un servidor y un cliente. Introduce un acoplamiento estrecho y, en realidad, tampoco funciona con Spring MVC en su forma actual (el mapeo de parámetros del método no se hereda).

Bien, no está bien integrado en este momento ... pero esa parte viene después de la advertencia de no compartir código e introducir el acoplamiento entre el servidor y el cliente, lo que creen que es más importante. ¿Por qué piensan que es una mala idea compartir una interfaz de esta manera?

Sin él, pierde la capacidad de garantizar que el servidor y el cliente se envíen datos que ambos puedan entender. Puede agregar un campo a uno pero no al otro y solo descubrir la falta de coincidencia hasta el tiempo de ejecución. En mi opinión, no está introduciendo el acoplamiento, sino simplemente revelando el acoplamiento que ya existe. ¿Es la necesidad de hacer que los servidores sean completamente independientes más que la necesidad de hacerles saber qué tipos de datos recibirán?

Ben S
fuente
1
El acoplamiento que existe, en términos de datos / formato manejado por clientes / servidores, está determinado por el protocolo , una pieza de documentación que puede usarse como una convención . El acoplamiento introducido al compartir una interfaz es un acoplamiento en tiempo de compilación: considere lo que sucede cuando se cambia la interfaz (de una manera incompatible con versiones anteriores, por ejemplo), pero el código cliente / servidor que usa esa interfaz se implementa en diferentes momentos. Ese acoplamiento de tiempo de implementación puede ser más difícil de administrar, especialmente a escala de Netflix.
Castaglia
1
Estoy bastante seguro de que no estoy operando a la escala de Netflix :) pero si las interfaces se cambian de una manera incompatible con versiones anteriores , ¿no cambia esto el error de ser encontrado en tiempo de compilación a ser encontrado en tiempo de ejecución? ¿Consideran correcto dejar que algunas llamadas de función fallen mientras actualizan lentamente todos los servidores?
Ben S
1
Posiblemente; Depende del código del cliente. Tenga en cuenta también el otro caso: los servidores se actualizan primero, y los clientes ahora tienen que tratar con (inesperadamente) llamadas que fallan ...
Castaglia
1
Por curiosidad, al compartir esta interfaz, ¿limita qué idiomas / pila puede construir el cliente?
JeffO
Sí, es un archivo Java, por lo que tendrá que usar Java. Es posible que pueda usar otro lenguaje JVM pero no lo he probado.
Ben S

Respuestas:

6

La razón como se indica en los comentarios es que da como resultado un acoplamiento estrecho de su plataforma de cliente con la plataforma de su servidor. Aquí, eso significa que su cliente debe usar el idioma / plataforma que está utilizando en el servidor para comprender el contrato esperado de su servidor. Tenga en cuenta que existe una diferencia entre compartir el mismo código (un artefacto de un idioma / plataforma específico) y acordar un contrato específico.

En cambio, muchos proyectos utilizan documentación para sus contratos. Ejemplos de solicitudes y respuestas en un formato neutral (por ejemplo, JSON) sobre protocolos estándar (por ejemplo, REST). (Ver documentos de API de Stripe , por ejemplo). Debido a que no es práctico escribir un contrato basado en código para cada posible plataforma de cliente que desee utilizar o permitir. Otros usan herramientas de administración de API para definir contratos neutrales .

Su ejemplo de agregar un campo es una preocupación separada, un ejemplo de por qué es importante versionar los contratos de API. Deje que los clientes usen la versión para la cual están diseñados. Existe una nueva versión de API incompatible con versiones anteriores junto con la anterior. El cliente para la versión anterior continúa trabajando hasta que su equipo lo actualiza o hasta que retira la versión anterior (después de un período de desaprobación / migración). Ver cambio paralelo .

Seguir la advertencia (consejo implícito en) ayuda al cliente y al servidor a evolucionar de formas y ritmos que tengan sentido para cada uno. Si puede garantizar razonablemente que su servidor y cliente siempre compartirán el mismo idioma / plataforma Y evolucionarán al mismo ritmo, entonces usar un artefacto de código específico de idioma y plataforma como su contrato probablemente estará bien. Sin embargo, esto probablemente no sea una expectativa razonable, especialmente para proyectos que apuntan a Netflix OSS (algo específicamente diseñado para la escalabilidad y el rendimiento de la nube, con toda la complejidad necesaria).

Kasey Speakman
fuente
2
¿Se espera realmente que el cliente use la interfaz? Siempre he visto tales construcciones como una forma de facilitar la escritura de un cliente. Después de todo, aún puede escribir un cliente REST en un idioma diferente.
Jimmy T.
1
Exactamente, la API seguirá existiendo, con sus definiciones de ruta, nada impide la creación de un cliente en otro idioma, pero siempre que use Java podría usar la interfaz
Leonardo Villela