paint-brush
Cómo enviar cambios a producción de forma segurapor@israel_hlc
16,506 lecturas
16,506 lecturas

Cómo enviar cambios a producción de forma segura

por 10m2023/10/24
Read on Terminal Reader

Demasiado Largo; Para Leer

Todos conocemos el procedimiento, ¿verdad? Una vez que terminamos de trabajar en un cambio de código y [con suerte] lo probamos en nuestra máquina local, llevamos el cambio a la siguiente etapa del ciclo. Las pruebas locales están muy sesgadas e idealmente nos gustaría validar el cambio en un entorno más estable (y no seguir únicamente el punto de vista del ingeniero que implementó el cambio).
featured image - Cómo enviar cambios a producción de forma segura
 HackerNoon profile picture

Todos conocemos el procedimiento, ¿verdad? Una vez que terminamos de trabajar en un cambio de código y [con suerte] lo probamos en nuestra máquina local, llevamos el cambio a la siguiente etapa del ciclo. Las pruebas locales están muy sesgadas e idealmente nos gustaría validar el cambio en un entorno más estable (y no seguir únicamente el punto de vista del ingeniero que implementó el cambio).


El siguiente paso parece muy natural aquí: impulsar los cambios a un entorno de prueba confiable y hacer que los socios (controles de calidad, gestores de proyectos, otros ingenieros) ayuden con la validación antes de mover los cambios. A esto le seguiría la corrección de errores y la revalidación hasta que creamos que es lo suficientemente bueno como para pasar a producción. ¡Excelente!


Sin embargo, en la mayoría de los contextos esto simplemente no sucede. Puede deberse a varias razones, pero independientemente de la razón, la consecuencia es que a menudo tenemos que promover cambios en los servidores de producción antes de que se prueben o validen lo suficientemente bien.


El problema es… ¿Qué pasa si algo se rompe? En realidad, ¿cómo detectar problemas antes? Buenas noticias: es posible adoptar algunas herramientas y prácticas para hacer que las pruebas y la validación en producción no solo sean una práctica segura para usted y su empresa, sino que tal vez incluso sean una buena idea.

La línea de base: métricas

Antes de pasar a las pruebas en producción, tenemos que hablar de métricas: las necesitamos para validar que el cambio que estamos enviando produce el efecto deseado, no causa efectos secundarios no deseados, el producto aún es estable, etc. -Métricas establecidas, básicamente estamos ciegos al implementar los cambios. Nos referiremos a las métricas en muchos de los temas del artículo, así que echemos un vistazo a dos tipos diferentes de métricas que debemos tener en cuenta.

Métricas comerciales

Las métricas relacionadas con el negocio, como los KPI, los objetivos y el comportamiento del usuario, deben monitorearse después de implementar cambios para evaluar el impacto. Antes de cualquier cambio, identifique las métricas que se espera que se vean afectadas. Igualmente importantes son las métricas de barrera, indicadores de lo que no debería cambiar. Los cambios imprevistos en estas barreras de seguridad pueden significar problemas con el nuevo cambio, lo que requiere una revisión.

Métricas técnicas

Una vez definidas las métricas comerciales, también es importante comprender las métricas técnicas. Estos son fundamentales para garantizar que los sistemas se mantengan saludables a medida que se introducen cambios con el tiempo. Aquí estamos hablando de estabilidad del sistema, tasa de error, volumen, limitaciones de capacidad de la máquina, etc.


Las buenas métricas técnicas también son útiles para explicar los problemas observados en las métricas comerciales o para encontrar rápidamente la causa raíz de las regresiones. Por ejemplo, digamos que observamos que los usuarios interactúan mucho menos con una función en particular después del lanzamiento de la última versión. Un aumento en los tiempos de espera de las solicitudes o en las tasas de error podría mostrar rápidamente qué servicios/puntos finales están causando el problema.

Supervisión

Tenemos métricas comerciales y técnicas bien definidas, ¡bien! Ahora tenemos que monitorearlos. Hay muchas maneras de hacerlo, pero un primer paso común es crear paneles que realicen un seguimiento de las métricas a lo largo del tiempo, haciendo que los picos inusuales sean fáciles de detectar. Aún mejor si el panel permite un filtrado rápido de datos en función de segmentos específicos que pueden ser especialmente relevantes para el negocio. Monitorear activamente los paneles es una buena manera de visualizar rápidamente los efectos que un nuevo cambio ha introducido en el sistema. Algunas empresas consideran que el monitoreo activo es tan importante que incluso tienen turnos de monitoreo las 24 horas del día, los 7 días de la semana para detectar y abordar problemas lo antes posible.


Otra buena forma de monitorear las métricas es mediante alertas y detección automática. Para métricas clave, las alertas pueden proporcionar notificaciones en tiempo real cuando algo parece mal. Digamos que comenzamos a implementar una función y, unos minutos después de que comienza el proceso, recibimos una alerta que dice que la tasa de error está aumentando por encima de un umbral específico. ¡Esta notificación temprana puede evitar que propaguemos el cambio más en producción y salvarnos de muchos problemas!


Por último, es importante tener en cuenta cuánta información necesitamos y en qué circunstancias. Si bien los paneles son muy útiles para brindar una visión visual del rendimiento del producto y del sistema, agregar 1000 gráficos diferentes generará más confusión que claridad. Del mismo modo, si recibimos 1.000 alertas al día, es imposible investigarlas y actuar en consecuencia, y acabarán siendo ignoradas.

Aterrizaje más seguro

Métricas definidas, seguimiento implementado, ¡genial! Ahora echemos un vistazo a algunas herramientas y estrategias que nos ayudarán a evitar problemas, detectarlos antes y minimizar los impactos en la producción. Dependiendo de cómo esté configurado el entorno de producción, algunos de ellos serán más difíciles de implementar que otros y tal vez ni siquiera tengan mucho sentido cuando se combinen. Sin embargo, cada elemento aquí podría ayudarnos a acercarnos a un entorno de producción seguro y estable.

Pruebas automatizadas

Las pruebas automatizadas, que a menudo se dejan de lado cuando los proyectos se desvían, pueden acelerar el desarrollo y hacer que los cambios en la producción sean más seguros y rápidos. Cuanto antes se detecten los problemas, más rápido se podrán solucionar, lo que reducirá el tiempo total invertido en el proceso. El proceso de revertir cambios, arreglarlos y volver a impulsarlos suele ser muy estresante y puede quitarnos un tiempo precioso.


Apuntar a una cobertura de prueba del 100% con pruebas unitarias, de integración y de extremo a extremo puede ser idealista para la mayoría de los proyectos. En su lugar, priorice las pruebas basadas en el esfuerzo versus el beneficio. Las métricas pueden guiar esto: cubrir las características principales del negocio probablemente sea más crucial que las características de nicho de menor impacto, ¿verdad? Comience con las funciones principales y amplíelas a medida que evoluciona el sistema.


El proceso de publicación en producción debe incluir la ejecución del conjunto de pruebas antes de implementarlo en producción. Las fallas en las pruebas deberían detener la publicación, evitando problemas de producción. Es preferible retrasar el lanzamiento de una función que descubrir que no funciona correctamente al día siguiente.

comida para perros

Dogfooding es el proceso de lanzar una función para pruebas internas antes de que llegue a los usuarios finales. Durante la prueba interna, la función está disponible en producción, pero solo para usuarios internos (empleados, miembros del equipo, etc.). De esta manera, podemos probar y validar si la nueva característica funciona como se esperaba, utilizando datos de producción reales, sin afectar a los usuarios externos.


Existen diferentes estrategias para el dogfooding. Para obtener una descripción general simplificada, podríamos agruparlos en dos grupos más grandes:

  1. Dogfooding completo de artefactos : Esto es común, por ejemplo, en aplicaciones de iOS/Android, donde tenemos herramientas integradas para lanzar una nueva versión de la aplicación para usuarios específicos y luego hacer que esta misma versión esté disponible para el público general en las tiendas.
  2. Comida selectiva para perros : A veces, no es posible (o incluso deseado) aplicar pruebas internas a todo el artefacto, pero aun así podemos permitir la prueba interna basada en información específica del usuario. Digamos, por ejemplo, que somos capaces de identificar empleados cruzando algunos datos. Luego, la aplicación podría configurarse para habilitar/deshabilitar una característica particular verificando estos datos y derivando al usuario al comportamiento deseado. La aplicación entonces contiene ambas funciones, pero solo algunos usuarios se verían afectados por el nuevo cambio. Volveremos a algunos de estos conceptos en los próximos temas.

Lanzamiento canario

El lanzamiento de Canary es un proceso de lanzamiento en el que, en lugar de implementar los cambios en producción en todos los servidores a la vez, el cambio se pone a disposición de un pequeño subconjunto de ellos y se monitorea durante algún tiempo. Solo después de certificar que el cambio es estable, se envía al entorno de producción.


Lanzamiento canario


Esta es una de las herramientas más poderosas para probar nuevas funciones y cambios riesgosos, reduciendo así las posibilidades de romper algo en producción. Al probar el cambio en un grupo de usuarios, podemos detener/revertir el proceso de implementación si se detecta algún problema, evitando el impacto en la mayoría de los usuarios.

Despliegue azul verde

Blue Green Deployment, una práctica de DevOps, tiene como objetivo evitar tiempos de inactividad mediante el uso de dos clústeres de servidores (azul y verde) y alternando el tráfico de producción entre ellos. Durante la implementación de funciones, los cambios se publican en un conjunto (verde) mientras que el otro (azul) se mantiene sin cambios. Si surgen problemas, el tráfico se puede revertir rápidamente a los servidores azules, tal como se mantenían en funcionamiento con la versión anterior.


#Despliegue Azul Verde

La implementación azul y verde a menudo se contrasta con la versión Canary que comentamos anteriormente. No profundizaremos en los detalles de esta discusión, pero es importante mencionar esto para ayudarnos a decidir qué herramientas son más adecuadas para nuestro trabajo.

Interruptores de apagado y alternancia de funciones

Los interruptores de apagado no se originan en el contexto de la ingeniería de software, y la mejor manera de comprender su uso es mirando hacia atrás a la intención y el diseño originales. En la maquinaria utilizada en las industrias, los interruptores de apagado son mecanismos de seguridad que los apagan lo más rápido posible mediante una interacción muy simple (generalmente un simple botón o interruptor de encendido/apagado). Existen para situaciones de emergencia, para evitar que un incidente (mal funcionamiento de la máquina, por ejemplo) provoque uno aún peor (heridas o muerte).


En ingeniería de software, los interruptores de apagado tienen un propósito similar: aceptamos perder (o eliminar) una característica particular en un intento de mantener el sistema en funcionamiento. La implementación es, en un nivel alto, una verificación de condición (consulte el fragmento de código a continuación), que generalmente se agrega en el punto de entrada de un cambio o característica en particular.


 if (feature_is_enabled('feature_x')) {xNewBehaviour();} else {xOldBehaviour();}


Digamos, por ejemplo, que estamos enviando una migración a una nueva API de terceros. Todo está bien en las pruebas, es estable en la versión canary y luego el cambio se implementa al 100% en producción. Después de un tiempo, la nueva API comienza a tener problemas con el volumen y las solicitudes comienzan a fallar (¿recuerdas las métricas técnicas?). Debido a que tenemos un interruptor de apagado, las solicitudes de API se pueden revertir instantáneamente a la API anterior y no necesitamos volver a una versión anterior ni enviar rápidamente una revisión.


Técnicamente hablando, los interruptores de apagado son en realidad un caso de uso particular de alternancia de funciones (también conocidos como indicadores de funciones). Ya que estamos en el tema, vale la pena mencionar otro gran beneficio de la alternancia de funciones: permitir el desarrollo basado en troncales. Gracias a los cambios de funciones, el nuevo código se puede enviar de forma segura a producción, incluso si está incompleto o aún no se ha probado.

Mantener accesible el antiguo comportamiento

El código ejemplificado anteriormente probablemente dejó a algunos de nosotros preguntándonos si ese es realmente un buen patrón, con comportamientos nuevos y antiguos viviendo en la aplicación al mismo tiempo. Estoy de acuerdo en que probablemente este no sea el estado final que queremos para nuestro código base; de lo contrario, cada fragmento de código terminaría rodeado por cláusulas if/else, lo que haría que el código fuera ilegible en poco tiempo.


Sin embargo, no siempre debemos apresurarnos a eliminar el comportamiento anterior. Sí, es muy tentador limpiar el código tan pronto como deja de usarse y evitar deudas técnicas. Pero también está bien dejarlo ahí por algún tiempo bajo el interruptor de función. A veces, puede pasar un tiempo hasta que la nueva característica se estabilice, y tener una opción de respaldo es un mecanismo seguro en caso de que necesitemos volver a ella, aunque sea por un corto tiempo.


El ciclo de vida de cada versión es diferente y es una buena práctica realizar un seguimiento de cuándo es un buen momento para deshacerse del código antiguo. Mantener el código limpio y reducir la sobrecarga de mantenimiento evitará la situación opuesta en la que, aunque tengamos la función deshabilitada en el código, probablemente esté rota dado el tiempo que ha pasado desde que se deshabilitó.

Pruebas de sombra

Una de mis técnicas favoritas para implementar cambios más seguros se conoce como prueba de sombra o modo sombra. Consiste en ejecutar comportamientos nuevos y antiguos para comparar los resultados, pero deshabilitar algunos de los efectos secundarios del nuevo comportamiento según corresponda. Echemos un vistazo a este sencillo ejemplo:


 int sum(int a, int b) {int currentResult = currentMathLib.sum(a, b);int newResult = newMathLib.sum(a, b);logDivergences(a, b, currentResult, newResult);return currentResult;}void logSumDivergences(int a, int b, int currentResult, int newResult) {if (currentResult != newResult) {logger.warn(      'Divergence detected when executing {0} + {1}: {2} != {3}',a, b, currentResult, newResult);}}


Aunque se ejecutan ambas operaciones de suma, la nueva solo se usa para comparar y registrar divergencias. Esta técnica es particularmente útil para monitorear cambios complejos en sistemas y esperamos cierta paridad entre los comportamientos antiguos y nuevos. Otro gran caso de uso es cuando tenemos que realizar cambios en productos con los que no estamos muy familiarizados o cuando no sabemos bien qué casos extremos pueden verse afectados por el cambio previsto.


En escenarios más complejos, es posible que necesitemos desactivar algunos efectos secundarios antes de habilitar las pruebas paralelas. Por ejemplo, digamos que estamos implementando una nueva API de backend para registrar usuarios y guardarlos en la base de datos, devolviendo el ID de usuario. Incluso podríamos tener una base de datos oculta para ejecutar el proceso completo, pero definitivamente no es una buena idea enviar el correo electrónico "Registro exitoso" dos veces, una para cada API de backend. También en el mismo ejemplo, necesitaríamos una lógica de comparación más profunda, ya que simplemente comparar los ID de usuario devueltos no sería muy útil.


Por último, es importante comprender qué es necesario monitorear y probar, y qué criterios se aplicarán si no se logra la paridad. En algunos escenarios críticos, tendremos que repetir las pruebas paralelas hasta que los resultados sean exactamente los mismos. En otros, puede estar bien tener un porcentaje de divergencia cuando la nueva implementación ofrece beneficios adicionales que superan la pérdida.

Registros

Incluso con salvaguardias sólidas, los sistemas pueden fallar. Cuando esto sucede, debemos ser capaces de entender lo que está sucediendo, con el nivel adecuado de detalle; de lo contrario, puede ser extremadamente difícil encontrar una solución eficiente. Aquí es donde los registros vienen a salvar el día.


Si bien el registro no es un concepto nuevo y existen muchas soluciones fáciles de implementar, garantizar registros efectivos es un desafío. A menudo, los registros no son claros, son demasiado complejos, faltan o están inundados de entradas irrelevantes, lo que dificulta la resolución de problemas. Sin embargo, los registros no sirven únicamente para solucionar problemas. El registro adecuado ayuda a verificar la efectividad de nuevas funciones y cambios. Al tomar muestras de las entradas del registro, se pueden rastrear los viajes de los usuarios y confirmar que los sistemas funcionan según lo previsto.

Pensamientos finales

Enviar código a producción a veces es peligroso, pero tenemos muchas estrategias para hacer que el proceso sea mucho más seguro. Incluso si identificamos un problema, también es importante saber qué es aceptable o no. No todas las fallas tienen por qué resultar en una reversión. ¿Qué pasa si intentamos corregir una falla de seguridad grave o cumplir con una nueva regulación? Tener criterios claros y comprender cuán crítico es el cambio es muy importante para determinar cuándo cancelar o continuar en caso de problemas. Volviendo al principio, las principales métricas están ahí para ayudarnos en el proceso de decisión.


¡Aterrizaje seguro a todos!