Ingeniería en Catástrofes de Software
Desde hace un tiempo atrás, he venido pensando en esos escenarios en los que todo lo que podría salir mal, sale mal. La tan temida y estudiada “tormenta perfecta” es más común de lo que creemos, y alcanza proporciones insospechadas. Es en ese momento cuando ocurre, donde lo único que queda es hacer control de daños. Estamos hablando de una “Catástrofe de Software”.
Hay dos tipos de catástrofes, las que puedes ver venir y las que sinceramente te agarran de golpe.
Se esperan lluvias para mañana en toda la costa oeste.
Sequías, Huracanes, Nevadas… te dan días sino semanas de anticipación para que puedas prepararte. Tienes tiempo, puedes ver la carta sinóptica y en algunos casos sabes hasta la hora exacta de cuando comenzará a llover.
En la mayoría de los proyectos de Software es el caso ideal.
Una vez efectuada la toma de requerimientos iniciales y el backlog ya tiene vida propia, es un buen momento para comenzar a diseñar los features correspondientes. Lo más importante: hay tranquilidad y entusiasmo por lo que se puede prestar un cierto grado de atención a los detalles para que nada quede al azar. El fenómeno del “Day 1”.
Normalmente dentro de un Acceptance Criteria “normal” entrarían:
- Pull Requests: Que el código sea efectivamente auditado y revisado de forma humana. ¿El código hace lo que dice que hace?
- Check Style: Que el código cumpla con estándares previamente definidos de calidad. ¿Esto es código o un Fettuccine con salsa Alfredo?
- Unit Tests: Que el código sea seguro de ser introducido y pasado a producción. Este código no es una bomba a punto de explotar, ¿cierto? ¿Cierto?
Sin embargo, siempre han habido vicios en este proceso por diversos factores.
Hace poco me tocó ver un caso en el cual un feature importante tuvo un servicio caído por casi una semana y nadie lo notó. No habían alarmas ni métricas relevantes al respecto, y la forma en que este desastre fue descubierto fue casi al azar. Lo peor de todo fue que todos los criterios anteriormente descritos dentro de un “Acceptance Criteria Normal” habían sido cumplidos de forma eficaz por lo que existía una sensación de confianza y derechamente se había bajado la guardia ante otro tipo de riesgos.
Todo puede salir mal, hasta los cambios más seguros.
Si sabes que viene un huracán, proteges las ventanas contra el viento y desalojas el lugar. Te vas, estás lejos. Crees que todo está bien hasta que en las noticias te das cuenta que el mar inundó todo. Ya es muy tarde.
Desastre #1: Ninguna de las métricas hasta ese momento (logs, alarmas, dashboards) era consciente de la posibilidad de un error así. Por lo tanto, todas esas métricas siempre dijeron que todo “estaba bien”. A lo Volkswagen.
Recuerdo que este mismo error ocurrió en 1996 cuando un avión de AeroPerú se cayó al mar. Los sensores indicaban que el avión estaba a altitud crucero cuando en realidad iba en picada, y esa era la misma información que en la torre de control de Lima veían los controladores de tráfico. Era de noche. Estaba todo oscuro. Los pilotos estaban volando a ciegas, y para cuando desde Lima mandaron un avión a buscarlos… ya habían chocado con el Pacífico. Todos murieron.
Las métricas, alarmas y todo lo que involucre saber que “algo anda mal”, deben definirse antes de la primera línea de código. Deben diseñarse con cuidado. Así al menos sabrás que sucede cuando la catástrofe sea inminente.
Tal como con el ejemplo del huracán, de antemano se sabe que el viento es un peligro, el mar, el sistema eléctrico, el gas natural y hasta los saqueadores que aprovechan que la casa está deshabitada. Todos esos riesgos deben ser analizados para que las medidas preventivas sean puestas en práctica. Nada debe ser dejado al azar.
Al diseñar un feature, de inmediato se detectan los posibles riesgos, se determinan las métricas relacionadas con los riesgos, alarmas y planes de mitigación. Así se puede contar con una “navaja suiza” que evitará que cualquier riesgo pase a mayores.
¡Alerta de Tornado!
Normalmente cuando el tornado está a punto de tocar tierra, todos los canales de televisión están alertando a la gente a que busque refugio. Se disparan alertas y suenan las sirenas. Algo va a pasar, es grave, pero aún estás a tiempo de hacer algo.
Cuando el concepto de Tornado pasa por frente a mis ojos, de inmediato pasa por mi mente Oklahoma. Y es que son largamente conocidos porque son el destino preferido de los tornados. Están en la mitad del “Tornado Alley”, y en esa categoría son perfectamente comparables al papel que juega Miami en los huracanes, o Japón en los terremotos.
Un tornado te da poco tiempo de aviso. Quizás un par de segundos después que suena la alarma en la televisión o te llega la alerta al celular. Es algo que puedes ver venir, pero tienes que actuar rápido porque el peligro es inminente. En unas cuantas oportunidades me ha tocado ver estas alertas en la tele. Las veces que me ha pasado, he quedado en el techo, aterrado.
Lo único que queda por hacer, es correr al refugio y no salir de ahí hasta que por la radio indiquen que el peligro ya pasó.
Tal como en los tornados, una vez recibes la alerta (definida en el punto anterior) inmediatamente debes saber qué hacer para poner tu software a resguardo. Mecanismos de mitigación y control de daños, prevenir el sangrado, monitoreo activo. Todos esos pasos deben ya haber sido descritos y ensayados previamente, teniendo en cuenta los escenarios de riesgo que están siendo representados en las métricas. De lo contrario…
Desastre #2: Desde hace 3 horas todos los endpoints de la API están retornando HTTP 500. No estoy seguro de lo que pasa, solo sé que es un IllegalArgumentException en la línea 684. Comenzaré a investigar. Creo que me tomará un par de horas.
La tormenta perfecta está comenzando a tomar forma. Todos los endpoints ya llevan tres horas en el piso, y no se sabe (honestamente) cuando volverán a estar operativos. Es un mal día para la ciencia.
Nuevamente: La mejor forma de afrontar este tipo de casos es saber lo que se está haciendo, y no dejar ningún detalle al azar.
Nuevamente: La etapa de diseño debe ser perfecta. Insisto, perfecta. Y extremadamente documentada.
Cada historia de usuario debe tener una justificación de negocio, y la estrategia técnica de alto y bajo nivel debe estar presente en la documentación. Eso da la oportunidad de identificar potenciales problemas y al saber por qué se producen, existe una estrategia definida para corregir y mitigar. Cuando el tornado venga por ti, sabrás lo que tienes que hacer.
¿Qué estabas haciendo al momento del terremoto?
En Chile esa pregunta es común. Tiembla todos los días, y con una regularidad promedio de casi un lustro un terremoto sobre M8 nos regala la oportunidad demostrar nuestra capacidad de correr por nuestras vidas al cerro más cercano porque un tsunami viene por nosotros.
Una característica principal de los terremotos, es que llegan de golpe y sin aviso. Ya es tarde, las medidas preventivas no funcionaron y este es el momento en el cual deberías comenzar a pensar qué fue lo que faltó, ya que lo estás viviendo.
Estas situaciones son las que convierten a un Desarrollador Junior en un Ingeniero Senior.
Es el momento en que se desarrolla el instinto de supervivencia mientras se quiebran los vidrios, se va la electricidad y se comienza a caer el techo. De todas formas, siempre hay algún tipo de contexto cultural que provee el conocimiento esencial para afrontar este tipo de situaciones.
Un ejemplo: Si el internet anda lento, lo primero que uno piensa es en reiniciar el router.
Algo parecido pasa cuando nuestros sistemas se caen. Muchas veces la solución instintiva es revertir los últimos cambios que fueron introducidos con la esperanza de que esto mitigue el error temporalmente mientras se busca una solución permanente.
El problema es que este tipo de acciones son como un revólver. ¿Qué hacemos cuando se nos acaban las balas?
Ser reactivo es el último recurso. Pero no siempre sale bien.
Hay situaciones que ni James Bond ni Tony Stark pueden manejar, por muy expertos que sean. Y tal como pasa en los terremotos, en las catástrofes de software hay situaciones que son inmanejables, sea por la magnitud de las mismas o porque simplemente se nos acabaron las balas. Personalmente, es en esos momentos donde me gustaría que la vida tuviera una caja negra tal como los aviones, que esté grabando las métricas, nuestras conversaciones y hasta lo que pensamos con tal de poder analizar lo que sucedió y tenerlo en cuenta para el futuro.
Aprender de los errores, una y otra vez.
Hace pocos días una API estuvo abajo por casi una hora por mi culpa. Hice algo que no debía, y por falta de comunicación esto se transformó en una tormenta perfecta, intensa y corta como un downburst.
Lo único que pude decir a la mañana siguiente fue: “Un rey sin cicatrices no es un Rey”. Es en ese momento en el cual aprendes la lección, tomas en cuenta lo que pasó y de inmediato documentas para que no vuelva a pasar.
Para la próxima vez que haya que diseñar una pieza de software, este episodio será considerado y analizado cuidadosamente, tomando en cuenta un principio esencial dentro del desarrollo de software:
La responsabilidad es del diseño. Siempre.