La transición a la arquitectura de microservicios requiere una revisión del enfoque de desarrollo, prueba, mantenimiento, diseño, en otras palabras, a todos los aspectos del ciclo de vida de los componentes de software. En esta publicación, hablaremos sobre las prácticas que el equipo de arquitectos de Acronis ha adoptado para avanzar hacia las mejores API de componentes. La historia incluirá tanto la declaración del problema como el análisis de sus soluciones. Quizás esta publicación parezca "capitana" para algunos, no estará claro para alguien por qué se perdieron la súper solución X, pero esperamos que sea interesante y útil para usted. Invitamos a los creadores de microservicios a leer y dejar sus comentarios debajo de cat.

Si está suscrito a nuestro blog, ya ha leído acerca de los contratos de microservicios. Hablamos de ellos en publicaciones sobre la elección de
Swagger o RAML , así como de
comprobaciones estáticas que pueden llevarse a cabo sobre la base de anotaciones creadas previamente. El motivo de la publicación de hoy fue un
informe en la conferencia HighLoad . En general, necesitábamos hablar sobre el camino que tomamos para formalizar la relación entre microservicios. Y hoy quiero compartir nuestras conclusiones con Habr, y también verificar si otros arquitectos están de acuerdo con nosotros.
Los microservicios son los "ladrillos" a partir de los cuales los desarrolladores crean aplicaciones modernas. Cada uno de estos servicios interactúa con el mundo exterior a través de una API. Por lo general, los microservicios son desarrollados por equipos separados, a veces dispersos geográficamente, por lo que para un trabajo efectivo es necesario mantener la consistencia e integridad de sus interfaces públicas. En grandes empresas con cientos de servicios, es necesario tener una anotación de cada componente: formalizar los datos de entrada y describir en detalle los resultados de su trabajo. Si trabaja con HTTP REST, existen dos formatos de anotación comunes para esto: RAML y Open API Specification (también conocido como Swagger). Pero las preguntas en las que nos enfocamos hoy no están vinculadas a ningún protocolo en particular. Por lo tanto, lo siguiente será relevante incluso para gRPC.
Antecedentes
Acronis ha existido por más de 15 años. Durante este tiempo, los productos y la base de código han evolucionado significativamente. Desde una aplicación de escritorio compleja, hemos llegado a un modelo empresarial con consolas de administración centralizadas, delimitación de derechos y registros de auditoría. El siguiente paso fue la transformación de la aplicación empresarial en una plataforma abierta, donde la experiencia acumulada se utilizó para integrarse con servicios externos.
Si antes la API era importante, ahora se ha convertido en un componente crítico del producto. Y los procesos que proporciona esta API han madurado.
Problemas mayores
Los problemas que rodean la construcción de API parecen familiares para todos. Los describiremos en una forma hipertrofiada: como dolores que atormentan a un programador hipotético Vasya y su no menos hipotético gerente Kolya. Todos los nombres son ficticios, y cualquier coincidencia no es accidental :)
1. La descripción está desactualizadaDeje que el programador Vasya desarrolle el componente A, que utiliza la API del componente B. Este último tiene una anotación, pero no es válida. Vasya tiene que meterse en el código de otra persona, buscar personas, hacer preguntas. Los plazos se están moviendo, y su gerente Kolya debe lidiar con las transferencias de los plazos.
2. API no es consistenteEl programador Vasya terminó la tarea y cambió a la siguiente relacionada con el funcionamiento del componente B. Pero tanto los desarrolladores B como los desarrolladores C tienen un sentimiento diferente de belleza, por lo que las mismas cosas se hacen de manera diferente en la API. Vasya volvió a tratar con el código y Kolya nuevamente no cumple con los plazos.
3. API no documentadaEl gerente de Kolya decide publicar la API del componente A para que los integradores puedan realizar integraciones maravillosas. Los integradores enfrentan problemas, el servicio de soporte está sobrecargado, todo está en llamas con el gerente Kolya, y Vasya siente que su turno llegará pronto.
4. La API no es compatible con la versión anterior.Se implementan integraciones, todos los incendios se extinguen. Pero Vasya repentinamente decide que la API de su componente está lejos de ser perfecta y está inmersa en una revisión. Por supuesto, en este caso se viola la compatibilidad con versiones anteriores y todas las integraciones se desmoronan. Esta situación genera costos por parte de los integradores y la pérdida de dinero por parte de la empresa de desarrollo.
Métodos de tratamiento
Todos estos problemas surgen cuando los programadores no tienen idea de una buena API REST o esta vista está fragmentada. En realidad, no todos los desarrolladores tienen experiencia con REST. Y por lo tanto, los principales métodos de "tratamiento" están dirigidos a la educación. Cuando la visión de la API correcta, coordinada con la visión de otros desarrolladores, arquitectos y documentales, comienza a apretarse en la cabeza de cada desarrollador, la API se vuelve ideal. El proceso de formación de esta visión requiere esfuerzos y herramientas especializadas, de las cuales hablaremos ahora.
Dolor 1. La anotación no corresponde a la implementación
La anotación puede diferir del estado actual del servicio no solo porque es una API del "pasado oscuro", que no se puede alcanzar. También puede ser una API futura brillante que aún no ha llegado.
La razón de estas condiciones es la falta de comprensión de por qué se necesitan anotaciones. Sin terror por parte de los arquitectos, los desarrolladores tienden a considerar la anotación como una herramienta auxiliar interna y no implican que alguien de afuera la use.
Puedes curar este dolor de la siguiente manera:
- Revisión arquitectónica. Algo muy útil para empresas de todos los tamaños, en las que hay al menos un programador que "sabe cómo hacerlo bien". Al cambiar el servicio, el arquitecto o la persona a cargo debe monitorear el estado de las anotaciones y recordar a los programadores que es necesario actualizar no solo el servicio, sino también su descripción. Efectos secundarios: un cuello de botella en la cara del arquitecto
- Generación de código a partir de anotaciones. Este es el llamado enfoque API-first. Implica que inicialmente haga la anotación, luego genere el código primario (hay suficientes herramientas para esto, por ejemplo [go-swagger] (https://github.com/go-swagger/go-swagger)), y luego complete el servicio comercial lógica Este arreglo evita inconsistencias. Funciona bien cuando el área de tareas resueltas por el servicio está claramente delineada.
- Prueba de anotaciones versus implementación . Para hacer esto, generamos a partir de la anotación (RAML / swagger) el cliente que bombardea el servicio con solicitudes. Si las respuestas corresponden a la anotación, y el servicio en sí no cae, entonces todo está bien.
Prueba de anotación vs implementaciónDetengámonos en las pruebas. Dicha generación de consultas totalmente automática es una tarea compleja. Teniendo datos de anotaciones de API, puede crear solicitudes separadas. Sin embargo, cualquier API implica dependencias, por ejemplo, antes de llamar a GET / clients / {cliend_id}, primero debe crear este objeto y luego obtener su id. A veces, las dependencias son menos explícitas: crear un objeto X requiere pasar el identificador del objeto asociado Y, y esto no es una subcolección. Ni RAML ni Swagger permiten describir dependencias explícitas. Por lo tanto, varios enfoques son posibles aquí:
- Espere comentarios formales de los desarrolladores en anotaciones que indiquen dependencias.
- Solicite una descripción de la secuencia esperada a los desarrolladores (hay bastantes maneras de describir las solicitudes utilizando YAML , DSL especializado o mediante una GUI hermosa, como lo hizo el apigee ahora abandonado ) .
- Tome datos reales (por ejemplo, usando OpenResty para registrar todas las solicitudes y respuestas del servidor)
- Extraiga dependencias de la anotación utilizando (casi) inteligencia artificial (por ejemplo, RESTler )
En cualquier caso, la tarea de prueba lleva mucho tiempo.

Personalmente, llegamos al punto de preparar secuencias de prueba manualmente. En cualquier caso, los desarrolladores necesitan escribir pruebas, para que podamos proporcionarles una herramienta conveniente que pueda encontrar un par de errores adicionales.
Nuestra utilidad utiliza el siguiente yaml para describir la secuencia de solicitudes:

Los corchetes declaran variables que se sustituyen durante la prueba. La variable de dirección se pasa como un parámetro CLI y aleatoriamente genera una cadena arbitraria. Aquí es de gran interés el campo respuesta a var: contiene una variable en la que se escribirá json con la respuesta del servidor. Por lo tanto, en la última línea, puede obtener la identificación del objeto creado usando task.id.
Pain 2. API no es consistente
¿Qué es la consistencia? No introduciremos ninguna definición formal, pero, simplificando, esto es consistencia interna. Por ejemplo, en el proyecto inicial, Vasya necesitaba agregar datos sobre informes en HighLoad, y la API proporciona filtrado de datos por año. Después de que el proyecto estaba casi terminado, el gerente Kolya llegó a Vasya con una solicitud para agregar estadísticas sobre los oradores al análisis, y para hacer un nuevo método "OBTENER oradores" también con filtrado por año. Como resultado, Vasya completa el código en un par de horas, pero durante el proceso de prueba resulta que el método no funciona. La razón es que en un caso, "año" es un número, en otro, una cadena. Pero esto, por supuesto, no es obvio a primera vista y requiere un cuidado constante al trabajar con la API. La persistencia de la API es cuando no se requiere tal cuidado excesivo.
Hay muchos ejemplos de inconsistencia:
- uso de diferentes formatos de los mismos datos. Por ejemplo, formato de hora, tipo de identificador (número o cadena UUID),
- aplicando una sintaxis diferente para el filtrado o la paginación,
- diferentes esquemas de autorización para servicios. Las diferencias no solo afectan los cerebros de los programadores, sino que también reflejan las pruebas que necesitarán para admitir diferentes esquemas.
Tratamiento :
- Revisión arquitectónica. Si hay un arquitecto tirano, él (en ausencia de esquizofrenia) garantizará la coherencia. Efectos secundarios: factor de bus y tiranía :)
- Creación de la API de pautas. Este es un estándar único que debe desarrollarse (o prepararse), pero lo más importante es implementarlo. Esto requiere propaganda, y un palo, y una zanahoria.
- Implementación de comprobaciones estáticas para el cumplimiento de la directriz API de anotación (lea sobre esto aquí ).
Ejemplo: elementos de prueba estáticaCada compañía hace su propia elección de qué Guía usar. Y, probablemente, no existe un enfoque universal, qué debería ser y qué no. Después de todo, cuantas más disposiciones haya en el estándar, más estricto será el control y más restringirá la libertad de creatividad. Y lo más importante, pocas personas leen hasta el final un documento de "solo 100 páginas".
En nuestra empresa, incluimos los siguientes puntos en la guía:

Otros buenos ejemplos de directrices se pueden encontrar en
Microsoft ,
PayPal ,
Google .
Dolor 3. API no documentada
La existencia de anotaciones es una condición necesaria pero no suficiente para la simplicidad de trabajar con la API. Puede escribir una anotación para que no se dé cuenta de todo su potencial. Esto sucede cuando:
- no hay suficientes descripciones (para parámetros, encabezados, errores, etc.);
- no hay suficientes ejemplos de uso, porque el ejemplo se puede usar no solo para mejorar la documentación (más contexto para el desarrollador y la capacidad de jugar directamente con la API directamente desde el portal), sino también para probar (como punto de partida para difuminar));
- Hay características no documentadas.
Por lo general, esto sucede cuando los desarrolladores no tienen una comprensión clara de por qué se necesitan las anotaciones necesarias, cuando no hay comunicación entre los escritores técnicos y los programadores, y también si nadie ha descubierto cuánto cuesta la empresa con una documentación deficiente. Y si acudían al programador y se retiraban después de cada solicitud de soporte, todas las anotaciones se completarían muy rápidamente.
Tratamiento:- Disponibilidad de herramientas de generación de referencia API para el programador. Si el desarrollador ve cómo se ve la descripción de su API para colegas y usuarios, intentará mejorar la anotación. Efectos secundarios: la configuración de estas herramientas requerirá trabajo manual adicional.
- Establecer interacción entre todos los involucrados : programadores, evangelistas, personal de apoyo. Efectos secundarios: reunirse con todos y complicar los procesos.
- Uso de pruebas basadas en anotaciones de API . Implementación de las comprobaciones estáticas anteriores en repositorios de CI con anotaciones.
En Acronis, se genera una API de anotaciones basada en anotaciones con clientes SDK y secciones Try-It. Junto con ejemplos de código y descripciones de casos de uso, forman una gama completa de complementos necesarios y convenientes para programadores. Vea nuestro portal en developer.acronis.com

Debo decir que hay toda una clase de herramientas para generar la referencia API. Algunas empresas desarrollan estas herramientas para sus propias necesidades. Otros usan herramientas bastante simples y gratuitas como el
Editor Swagger . Después de una larga (muy larga) investigación, en Acronis nos decidimos por Apimatic.io, prefiriendo REST United, Mulesoft AnyPoint y otros.
Dolor 4. Problemas de compatibilidad con versiones anteriores
La compatibilidad con versiones anteriores puede verse afectada debido a cualquier problema. Por ejemplo, el programador Vasya escribe la palabra compatibilidad cada vez con un error tipográfico: compatibilidad. Este error tipográfico se encuentra en el código, en los comentarios y en un parámetro de consulta. Al notar un error, Vasya reemplaza esta palabra a lo largo del proyecto y, sin mirar, envía los cambios a la producción. Por supuesto, la compatibilidad con versiones anteriores se verá comprometida y el servicio disminuirá durante varias horas.
¿Por qué pueden ocurrir tales eventos? La razón principal es un malentendido del ciclo de vida de la API, que puede manifestarse en integraciones deficientes, en políticas impredecibles de EOL (End of Life) y en versiones oscuras de API.
Tratamiento:- Revisión arquitectónica. Como siempre, la mano firme de un arquitecto puede evitar la compatibilidad con versiones anteriores. Sin embargo, su tarea principal es explicar el costo de soportar varias versiones y buscar opciones para realizar cambios sin romper la API existente.
- Verificación de compatibilidad con versiones anteriores. Si la anotación API contiene una descripción actualizada, las infracciones de compatibilidad con versiones anteriores se pueden verificar en la etapa de CI;
- Actualización oportuna de la documentación. La referencia de API y la descripción de API deben actualizarse al mismo tiempo que cambia el código de servicio. Para hacer esto, al menos puede iniciar listas de verificación estandarizadas, al menos configurar notificaciones de cambios, al menos entrenar super-habilidades para generar todo de todo ... ¡Importante! El departamento de documentación debe conocer todos los cambios planificados para que tengan la oportunidad de planificar recursos para actualizar la documentación y escribir guías de actualización. La guía de actualización, probada y verificada, es un atributo triste de cualquier cambio de nombre que inició en la API.
Gestión del cambio
Las reglas que describen las actividades asociadas con el ciclo de vida de la API se denominan políticas de gestión de cambios.

Si tiene dos versiones de las anotaciones "actual" y "nueva", la verificación de compatibilidad con versiones anteriores es técnicamente simple: simplemente analice ambas anotaciones y verifique si existen los campos necesarios

Escribimos una herramienta especial que le permite comparar todos los parámetros críticos para la compatibilidad con versiones anteriores en CI. Por ejemplo, al cambiar el cuerpo de respuesta en la solicitud GET / healthcheck, se mostrará un mensaje similar al siguiente:

Conclusión
Todo arquitecto sueña con deshacerse de los problemas de API. Todo gerente sueña con no saber acerca de los problemas de la API. :). Existen muchos medicamentos, pero cada uno tiene su propio precio y sus efectos secundarios. Compartimos nuestras opciones de tratamiento para las enfermedades infantiles más simples con el API, y luego surgen problemas más serios. Conclusiones de nuestro artículo "capitanes": los problemas de API comienzan con la cabeza y enseñar a las personas buenas prácticas es la principal garantía de éxito. Todo lo demás es solo cuestión de tecnología. ¿Y qué problemas enfrentó y qué medios de solución eligió en su organización?
Medicamentos para la mala API.Estaremos encantados de cualquier pensamiento, calificación, comentarios, opiniones y preguntas!