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 @RestController
convierte en un servidor HTTP) y un cliente (The Feign @FeignClient
lo 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?
fuente
Respuestas:
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).
fuente