Mejores Prácticas para Ambientes de Staging

Publicado en

Nota del editor: Posiblemente has oído mencionar el término “ambiente de staging”, en español también llamado “pre-producción”. Para propósitos de este artículo, y por razones que entenderás conforme lo leas, nos referiremos a este como “ambiente de preparación”.

A pesar de que el ambiente de preparación es una parte importante del ciclo de despliegue de software, en las escuelas y cursos sobre desarrollo se toca muy poco —si acaso.

Cuando tienes una idea de una nueva app o funcionalidad, es natural querer poner tu código en vivo lo antes posible, pero eso rápidamente se puede salir de control. Es fácil refugiarse en la posibilidad de hacer rollbacks en caso de fallas —a fin de cuentas “casi siempre” funcionan—, y así evitar invertir en un ambiente de preparación. Pero si deseas tener un sistema de software maduro y respetable, necesitas un ambiente de
preparación.

Como comenta Alice Goldfuss [1]:

“no se trata simplemente de una buena práctica, se trata de respetar el tiempo y dinero de tus usuarios”.

¿En qué consiste?

Es común definir el ambiente de preparación en relación al ambiente de producción, por ejemplo: “es donde instalas y ejecutas antes de mover a producción”, “es como producción pero sin usuarios”, o “es una versión ligera de producción”. Es cierto que el ambiente de preparación puede ser esto, pero debemos aclarar su propósito:

El ambiente de preparación es donde validamos las “incógnitas conocidos” (known unknowns) sobre nuestros sistemas; es decir las cosas que sabemos que no conocemos. Estos son las dependencias, interacciones y casos extremos previsibles.

Testing no es suficiente

Hay quienes opinan que no necesitas área de preparación si tienes buenas pruebas. Estos equipos típicamente usan el siguiente arreglo de ambientes: desarrollo local, framework para testing, y producción. Su framework de testing es bastante robusto y continuamente
mejorado. Los builds que pasan las pruebas con “todo verde” son liberados a producción. Esta forma de hacer las cosas es básicamente “programación vaquera” con un lindo toque de “hicimos lo que pudimos”.

Pero hay un problema con este modelo: depende por completo de pensamiento previo de personas individuales. Sí, es bueno tener pruebas, pero hay que escribirlas. Y comúnmente las escribe la misma persona que busca que su código esté en vivo lo antes posible. Incluso si las pruebas se programan en pares, eso son tan solo un par de personas tratando de considerar todos los casos posibles con que se encontrará el componente de software una vez que sea puesto en producción.

Esto no significa que las pruebas sean inútiles. Las pruebas sirven para atrapar cosas que ya sabemos que pueden fallar. Implementar pruebas eleva la calidad de los componentes y agiliza las revisiones y despliegues. Pero las pruebas no son un reemplazo de staging. Un ambiente de preparación nos da un espacio donde podemos dejar que el código opere de manera orgánica para poder encontrar las fallas para las que no podemos (o no consideramos) implementar pruebas.

Manos a la obra

¿En qué momento deberías construir un ambiente de preparación? Idealmente, antes de que tu producto tenga usuarios. Pero siendo realistas, lo más probable es que lo termines haciendo como consecuencia de una caída en producción que afectó al negocio.

Comienza por mantener un registro de las caídas y qué las causó. La cantidad de caídas relacionadas con defectos de código o despliegues
inconsistentes probablemente te deprima y motive al mismo tiempo. Esas son las cifras que debes llevar como soporte a las juntas con gerentes que atentan contra tus ideales.

Una vez que la organización reconoce el valor de tener un ambiente de preparación, la pregunta es: ¿Quién debe hacerlo? Típicamente el primer instinto es asignarlo a QA, porque “tiene sentido”. Pero el ambiente de preparación es primo cercano del de producción, por lo que debería ser construido de la misma manera. Haz que el equipo de infraestructura cree la plataforma, y que los desarrolladores instalen sus aplicaciones o servicios.

Prepárate para descubrir todo tipo de cosas: que cierto proyecto usa una base de datos distinta a la recomendada por los lineamientos
de la empresa, que el equipo B piensa que Jenkins es aburrido y mejor hace scripts en Capistrano, etcétera. Haz un inventario de las distintas herramientas para despliegue que los equipos utilizan, identifica cuáles dominan y pónganse la meta de transicionar hacia un conjunto homogéneo y consistente.Usar contenedores puede ser una buena opción, pero no es el único camino.

Una ventaja de tener consistencia es que facilita la recuperación de desastres. Si todas tus aplicaciones se despliegan con el mismo pipeline, es posible ejecutar los planes de recuperación de desastres mucho más rápido y con menos personas.

Busca que el ambiente de preparación sea lo más parecido al de producción. Debes ser capaz de enviar la misma base de código a preparación y producción, usando variables de ambiente para configurar cosas como endpoints y bases de datos. Usa los mismos balanceadores de carga en ambos ambientes, la misma configuración de seguridad de grupos, etcétera. Recuerda que el objetivo es encontrar las cosas que no conocemos, por lo que todas las variables que conocemos deben ser las mismas. Usa también la misma herramienta de monitoreo y nivel de visibilidad en preparación que en producción.

Emular operación

Para emular operación similar a producción existen dos grandes caminos: a) inventar datos de prueba y ejecutarlos con el mismo nivel de carga de trabajo que en producción, y b) replicar un subconjunto de datos y tráfico de producción.

Usar datos de prueba nos permite probar escenarios específicos, pero también puede dejarnos con puntos ciegos (escenarios no
considerados). Por otro lado, replicar tráfico de producción nos da resultados más orgánicos y tiene la ventaja de que no necesitamos
inventar los datos y patrones de uso. Sin embargo, esto puede tener implicaciones de seguridad. Necesitamos asegurarnos de que la información que guardemos no tenga información privada sobre los usuarios, especialmente contraseñas.

Realizar pruebas de carga usando datos de producción puede ayudar a validar la confianza antes de una liberación. Sin embargo,
pudiera ser mejor implementar en producción pruebas A/B y hacer liberaciones parciales para probar el comportamiento.

Otras consideraciones

A pesar de sus buenas intenciones, un ambiente de preparación deficiente puede generar más problemas que beneficios.

Un argumento común en contra es que agregan fricción innecesaria y alentan el despliegue. Esto típicamente se da porque no se invirtió lo suficiente y se usa infraestructura con menor capacidad que en producción. La infraestructura del ambiente de preparación debe ser igual a la de producción y escalarse de la misma manera.

Si producción corre en instancias en la nube, o directamente en “bare metal”, preparación debe ser igual; no solo para que nuestras estimaciones de desempeño sean acertadas, sino también para poder descubrir fallas que se puedan colar de capas bajas.

Por otro lado, el área de preparación no necesita ser algo “sagrado” que solo puedan tocar unos pocos. En lugar de buscar proteger este ambiente para que no se rompa, debemos enfocarnos en que sea fácil de reparar. Por ejemplo, permite que cualquier persona tenga posibilidad de hacer revertir (rollback) código de otros equipos. Imaginemos que un ingeniero encuentra un defecto en el código de otro equipo que está bloqueando su trabajo, así que revierte el código defectuoso a la versión previa y notifica al dueño.

Una estrategia balanceada

Ya hemos hablado bastante sobre ambientes de preparación, pero esto es tan solo un elemento dentro de una línea de despliegue. A
continuación explico mi línea ideal:

  • Desarrollo local. Los desarrolladores programan en su computadora personal, interactúan con bases de datos locales y ven como se ve la aplicación en su navegador web.
  • Pruebas integradas. Cada que se acepta un pull request, la base de código se despliega automáticamente a dicho ambiente y se ejecuta la batería de pruebas. Estas pruebas están diseñadas para ser maliciosas, aplicar casos extremos y en general hacer sufrir al código.
  • Preparación. Lo explicado en este artículo.
  • Liberación parcial. El código es liberado a producción de manera parcial por medio de versiones canario, pruebas A/B, banderas de funcionalidad, u otro mecanismo. El objetivo es someter el código a condiciones de uso real ante un grupo de usuarios reducido.
  • Producción. Libera tu código con la certeza de que hiciste todo lo que pudiste. Asegúrate de que es posible revertir de forma segura.

Puede ser que esto parezca demasiado. Sin embargo, es preferible que estar a las 2 de la mañana tratando de revertir código defectuoso mientras tratas de calmar a clientes furiosos.

Darle importancia al negocio implica darle importancia a los usuarios lo cual implica darle estabilidad a nuestro sistema. Invertir en un ambiente de preparación sólido y bien administrado es un gran paso para lograr dicha estabilidad.


Referencias

[1] A. Goldfuss. “Best Practices for Staging Environments”. Increment Magazine, Num 3. http://swgu.ru/v2

Bio

Pedro Galván es Director Editorial de Software Guru.