Why I Needed Rust: Finally, Infrastructure Automation I can sleep on
Description

Esta charla comienza con un problema claro. La definición, por ejemplo, de un host, un nodo, donde se va a ejecutar una aplicación y la forma en la que se va a conectar con ella como un puerto, por ejemplo. Entonces ahora lo que hacemos es un recorrido donde mostramos la evolución de los desafíos en infraestructura en diferentes etapas.

La primera etapa es cuando no había redes y los desarrollos eran en local. Estamos hablando de finales de los 80, primeros de los 90. Había terminales tontos, cómo se desplegaba una aplicación, cuáles eran los ciclos de despliegue, los tiempos, las urgencias y los modos de despliegue. La siguiente etapa es la que aparece en la conectividad en las redes. Con Internet y la web el efecto conectividad de redes se multiplica, la seguridad se hace más relavante y muchos del os procesos son críticos, se incrementan los costes por errores o caídas de servicios.

Los sistemas están cada vez más lejos. Hay que conectarse a través de redes remotas o distantes. Los ciclos, el nivel de computación subido. Hay más participación de diferentes agentes en el desarrollo y en la explotación.

Y hay que armonizar la instalación de paquetes, la configuración de recursos, las actualizaciones y demás. La tercera etapa es con la aparición de los contenedores, pasamos de la computación monolítica a arquitecturas claramente distribuidas, con alta disponibilidad, ya trabajando en entornos 24 x 7, 365 días. Servicios cloud, modos híbridos, sistemas automatizados CD/CI en cíclos contínuos. Infraestructura como código.

Y queremos ser competitivos con unos ciclos muy cortos de nuevas funcionalidades, de nuevos despliegues, con la posibilidad de hacer lo que hacemos con las transacciones en las bases de datos en épocas anteriores, que es volver hacia atrás y volver hacia adelante. Ya no solo escalamos horizontalmente o verticalmente como ocurría en otras épocas, sino en ambas direcciones y también desecalamos. 

Y los sistemas se hacen cada vez más complejos. La presión es cada vez mayor. Y las psobilidades de descansar y no tener pesadillas aumenta considerablemente y los estados de alarma terminan siendo lo normal, la capacidad de posibilidades de tener problemas sin que ha aumentado enormemente. 

Hemos llegado hasta aquí con lo que conocíamos y teníamos en cada época. Cómo hemos definido las arquitecturas, cómo las hemos construido, planificado, construido y puesto en marcha y cómo hemos trabajado en su mantenimiento cotidiano, en sus actualizaciones y ciclos de cambio. ¿Qué es lo que ocurrido en cada una de estas etapas al respecto?

En la primera etapa apenas con scripts y con detalles más o menos ocultos en scripts o en definiciones de lo que queríamos de modo procedural. Después una etapa donde hay que instalar varios recursos en paralelo, pues aprendemos e intentamos crear procesos automatizables que se puedan reproducir. Pensamos que podemos escribir lo que queremos en una especie de declaración o una configuración que sido validada.

Y a partir de la tercera etapa empezamos a poner más herramientas para controlar esto. Pensamos que más es mejor, como siempre. Más computación, más mano de obra, más trabajo. El enfoque aquí es utilizar ya Mele, quizá en algunos casos Tomele como en el caso de Arras.

Y lo que hacemos es escribir lo que queremos, como una declaración de buenos deseos, como la carta a los reyes o a Papá Noel. Y queremos, cruzamos los dedos con la esperanza de que las cosas se hagan posibles. Monitorizamos, tenemos recursos para hacer seguimiento. Y muchos de los procesos no se repiten hasta que no pasa mucho tiempo en presencia de personas diferentes.

Entonces empezamos a declarar esto, encontrar fórmulas para declarar esto a través del mundo conocido. Y como JSON no es muy legible para humanos, pues terminamos con Yamele, Tomele y este tipo de cosas. 

Hemos pasado de un estado único que era fácil de mirar y controlar, a una segunda etapa donde había que tener en cuenta varias cosas, podían ocurrir a la vez o podían producirse de forma más o menos paralela, a procesos en la tercera fase ya con contenedores, con infraestructuras cloud, donde todo el proceso es distribuido, donde es muy fácil tener diferentes versiones de lo que creemos que es válido o lo que sería la fuente de verdad.

Y como esto tiene diferentes perspectivas, diferentes necesidades, con diferentes modos de interpretación, en un mundo de contenedores donde esta manera de distribuir lo que queremos no se hace tan fácil y donde un error tiene resonancia, tiene mucha más repercusión que en las dos primeros etapas. 

¿Hemos aumentado nuestra capacidad de hacer cosas, nuestro potencial, la productividad y demás? Sí. ¿Hemos aumentado la complejidad de los recursos? Sí. ¿Hemos creado mucho más estrés a la hora del mantenimiento de estos recursos porque tenemos más dependencia de ellos? Sí. Esto genera mucha fricción y mucha incertidumbre porque hay cada vez más interacciones desde el principio hasta el final.

Sí. ¿Cuál es el resultado de esto? Pues que nos encontramos frente a sistemas que llega a un punto, no sabemos cómo controlar, no tenemos mucha creencia de lo que puede o no funcionar y simplemente esperamos que funcione. Cuando no funciona, entonces lo arreglamos. 

Primera pregunta: ¿por qué tenemos que esperar a que no funcione o a que se rompa todo para arreglarlo? ¿Por qué no podemos prevenir antes que curar, fallar lo antes posible con el menor coste posible? 
Segunda pregunta, ¿cómo hemos definido lo que queremos? Es decir, independientemente de cómo lo hagamos, ¿tenemos claro lo que queremos? ¿Tenemos claro cómo tiene que ser aquello que tiene que funcionar? ¿En qué términos? ¿Con qué restricciones? ¿Con qué condiciones? ¿Y bajo qué planteamientos? O sea, que hemos encontrado una fórmula para definir cuál es el contexto y los límites o las restricciones a ese contexto en el que queremos que se presten los servicios o bajo qué condiciones.
Tercera pregunta. Hemos encontrado o hemos creado herramientas que utilicen estas definiciones o estos límites o contextos y puedan trabajar de forma automática en los ciclos de vida de las aplicaciones y de los servicios para garantizar que se lleve a cabo lo que queremos, para que se haga en los términos en los que hemos, respetando los términos que hemos acordado previamente, En suma, ¿podemos tener una certeza de que al final tendremos aquello que hemos pedido o que hemos formulado, deseado o declarado? Con la seguridad o la tranquilidad de que eso va a ocurrir de una manera determinista, no de una manera aleatoria, con problemas que pueden ocurrir o no en mi máquina funciona, en aquella ya no lo sé.

La comparación paralela que quiero hacer en cada una de las fases y en cada una de las preguntas y demás es la de cuando se va a un restaurante. Cuando se va al restaurante hay básicamente una cocina, un servicio que atiende al cliente y va y viene de la cocina a la mesa del cliente y un cliente sentado en una mesa, unos clientes sentados en una mesa que son los comensales.

Lo que pasa entre cada una de estas tres partes tiene que ver con la gestión de procesos. Es totalmente declarativa porque el cliente no dice en la mesa cómo en cocina se tiene que elaborar cada uno de los platos que elegido. El cliente simplemente declara lo que quiere, el comensal declara lo que quiere y cuando se va al restaurante le pueden presentar una carta con A, B y C, o una carta en la que A puede tener variantes o sencillamente decirle esto es lo que hay hoy y el cliente elige.

Entonces el servicio que atiende tiene que tener un conocimiento claro de lo que es posible y de lo que no y hacer una validación de esa petición para saber si es posible en tiempo o en forma en función de lo que se pedido. Y por otro lado tiene que entender las mecánicas de la cocina y la elaboración de platos.

Cuando servirlos, cómo servirlos, cómo hacer esa conexión entre los clientes que están en mesa, el mundo del restaurante y el mundo de la cocina. Y con el menor coste, sacrificio y esfuerzo posible porque hay que hacer muchas cosas a la vez.

Analicemos cada una de las cualidades que observamos En cada una de las diferentes etapas que hemos mencionado y en las fases de la petición de platos en un restaurante. En cada una de esas fases y procesos hemos elegido diferentes modos. ¿Qué es lo que tenemos que valorar? Primero, ¿hasta qué punto son eficientes y suficientes para expresar lo que queremos?

No puede ocurrir que yo pida algo para que después el camarero vaya a cocina y el cocinero le diga No, de eso no hay, está fuera temporada, esto hoy no lo tenemos, entonces ¿por qué lo tienes en la carta? etc. No, yo he configurado un host con un puerto pero ese puerto no está permitido, hay que volver y reconfigurar el puerto y volver a empezar de cero.

¿Es esta declaración suficiente y consistente, realista y rigurosa con lo que hay y con lo que es posible de acuerdo con las reglas? ¿Qué reglas? Esas reglas son dinámicas, son permanentes, son para toda la vida, el restaurante sólo ofrece A, B, C y D siempre a todas horas, no hay cambios.

¿Cada cuánto tiempo se producen esos cambios? ¿Cuáles son los ciclos de vida? ¿De cambio que hay? ¿O todo es cambio continuo y adaptación?

¿No hay un marco o unos límites estrictos? Entonces tenemos que valorar cómo de válida es esa declaración, hasta qué punto respeta los criterios y los límites y cuestionarnos, dar un paso atrás y cuestionarnos entonces cuál es la verdad. La verdad es la nota que toma el camarero o camarera sobre lo que uno quiere, lo que el cliente, el comenzar quiere, o las marcas que hace en esa nota en cocina sobre lo que ya está o lo que no está.

O cómo a partir de eso se gestiona el ticket de pago. Hay una verdad que va mutando en cada proceso, no es estática. La verdad depende de quién lo mire y quién la use en cada momento. Hay cosas que son relevantes y cosas que no lo son.

Como en un sistema neuronal hay neuronas que le prestan atención a unas cosas y a otras no. Son eventos que no, aunque ven, no consideran que son relevantes o que tienen que participar en ellos. 

Estamos hablando de validar un pedido o de validar una infraestructura, como se hacía antes, si hemos encontrado algún tipo de estándar, si ese estándar tiene una capacidad suficientemente adaptativa en los diferentes fases de todo el proceso, están definidas claramente las fases o las fases pueden cambiar dependiendo de lo que ocurra en los diferentes trayectos o procesos.

Y más aún, finalmente hemos logrado aprender algo de toda esta dinámica para poder evitar errores en un momento dado y automatizar y facilitar todos los procesos, trayectos o viajes desde la entrada hasta la salida. ¿Cómo medimos esto? ¿Y qué valor tiene? ¿Qué peso tiene? ¿Qué repercusión tiene un fallo en un momento diferente, en un paso, en una situación diferente? No es lo mismo un fallo en la mesa que en la cocina, que la caída en un plato cuando se va a entregar la comida, que un desacuerdo entre lo que se pedido y lo que recibe en mesa cuando se entrega el plato, que una equivocación porque se cedido un tiempo de cocina en una elaboración o porque esa elaboración no contemplado diferentes elementos que se han asumido como parte de la historia. 

Hasta qué punto hemos logrado customizar los procesos. Es decir, si yo hago siempre el mismo tipo de tareas o si el cliente es el que ya conozco, asumo cosas que tengo que registrar. Porque puede haber elementos o procesos en la cadena que no conozcan al cliente. El camarero sí lo conoce, pero en cocina no.

Entonces, para que haya este rigor, tengo que encontrar métodos que me aseguren que la fórmula es comprensible o que lo que se quiere es válido para cualquiera de los elementos que participan en la cadena. Y si alguno de estos elementos, llamémosles actores, o elementos que interactúen o estaciones del recorrido, pueda cambiar parte de lo definido y que eso tenga que volver a hacerse una validación al cliente.

Es que no tengo champiñón. Puedo reemplazártelo por una verdura. 

Cuando empezamos con el HTML era perfecto porque era una manera de encapsular o una manera de guardar, reflejar el contenido para poderlo propagar de manera que se pudiera renderizar en la misma manera en diferentes puntos. Y pensamos que teníamos que usar más lenguajes y que para combinar esto pues ya no íbamos a escribir más HTML porque era un rollo.

Y entonces usamos herramientas que escribían HTML, escribían CSS, Javascript y aparte interactuaban con los servicios de backend. ¿Qué ocurrió después? Después pensamos que esto en infraestructura no era muy válido porque en mucha de la infraestructura pues lo que hacía era que dentro del paquete pues tenía todos los dependencias, todas las acciones, los PAD y tal, todo hardcoded.

Entonces pensamos en hacer de esto una configuración externa que pudiéramos declarar y que los programas o los instaladores pudieran usarla como modo de referencia donde poníamos los recursos de manera externa. Entonces como esto funcionaba muy bien entre máquinas utilizando JSON, pues el JSON se nos quedó como muy mal porque a muchos temas de sintaxis entonces pensamos que la mejor manera era utilizar un Tomele o un Yamele y que luego esto al cargarlo con herramientas, en por ejemplo Serde, el crate Serde, y así pues sería validado.

Y que entonces pues aceptaríamos elefante como animal de compañía o no. Y esto lo pondríamos a fuego dentro de la aplicación para que se ejecutara o no.  
¿Y qué pasó? Que nos cansamos de escribir yameles y que era muy estresante mantener los espacios, mantener una cuestión de lo que es la sintaxis, etc. Y entonces utilizamos gestores de plantillas para que fueran capaces de escribir el yamele. Entonces lo que hacíamos es que le pasábamos una serie de variables, otra vez en yamele, domele o json, y era capaz de generar el yamele final, que era el que consumía la aplicación.

¿Todo esto valida el contenido del yaml? No, en absoluto. Es como ahora con la IA un markdown. En vez de escribir un prompt le paso un markdown o utilizo un markdown de referencia. Está validado su contenido. Puede ser sí o no o puede ofrecer una validación determinada como haríamos en un testing. No. 
Entonces, nos movemos en ciclos de cambios, ciclos cambiantes, C y CD, de forma continua, pero ¿qué es lo que queremos? ¿Cuáles son las reglas de juego? ¿Y cuáles las acciones y los cambios que puedo introducir en esas reglas sin salirme fuera de contexto? sin salirme fuera, sin irme demasiado lejos de lo que quiero. Es decir, cuando tengo que volver a la mesa para preguntarle al comensal si le puedo cambiar determinada cosa en el plato porque no, esos ingredientes no son frescos de temporada. En realidad no estamos inventando nada, todo ya existe, el problema es si lo estamos gestionando adecuadamente. 

¿Qué pasa cuando aparece RustS? Pues cuando aparece RustS introduce elementos que ya están o estaban en otros lenguajes, los reúne y aparece algo bastante diferente. En RustS hay mutabilidad, en RAS hay tipado estático, en RAS hay posibilidades de definir componentes o interfaces, como son los traits. Y entonces puedo validar implementaciones en función de los traits.

Tengo un compilador que analiza todo el código y el uso que se hace de los valores y variables antes de construir el binario. 

¿Qué me ofrece RAS o cuál es la propuesta? En primer lugar, tengo que introducir un tipado, o sea, crear tipos para definir exactamente lo que quiero, para que mi declaración pueda interpretarse sin equívocos. Un número no es lo mismo que un texto o un string. RAS es enormemente exhaustivo en los diferentes tipos y tipos naturales del lenguaje o tipos primarios que ofrece.

En segundo lugar, es cohesivo y coherente con estos tipos, es decir, los valida de manera consistente, el tipado es estricto, no se relaja. Hay formas de pasar de un tipo a otro, de hacer las conversiones o los CAST. Hay métodos para gestionar la inmutabilidad, es decir, tengo que definir aquello que puede cambiarse o no de mi declaración.

Yo he dicho que quiero tomate y puedas inventar lo que quieras, pero si no tiene tomate no es el plato que he pedido, ¿vale? Entonces, estos condicionantes de por sí aparecen como invariantes, no pueden cambiar. Pero además tengo la opción de que haya opcionales, no nulos, no inventate lo que quieras si no tienes esto, no.

Hay algo que puedes ponerlo o no, ¿vale? Pero cuando no lo pones, puedo controlar que no está y cobrártelo o no cobrártelo. 

En el análisis de los valores, para cargarlos en una implementación validando un esquema de tipos, yo puedo establecer restricciones, es decir, que un número sea un rango entre n y n, o que un valor sea dentro de una serie de valores determinados, como es el caso del enum.

Otro de los elementos importantes de Rust es la capacidad de definir funciones de llamada, sino analizar que esas funciones asociado determinado tipo de tipos y determinado tipo de implementaciones.Todos asociados a esa función. 
Y luego tengo la posibilidad de definir traits, que ofrecen un sistema de composición, es decir, yo puedo componer implementaciones de un trait, variantes de un objeto en programación orientada a objetos, ¿vale? Que cumplen determinados tipos de criterios, normas o valores. 

Es decir, hay una serie de formas de declarar lo que quiero, de instrumentos para declarar lo que uno quiere, ¿vale? Que son vigilados y mantenidos para que haya una coherencia entre lo que se quiere formular. ¿Quién es el vigilante o el que supervisa todo esto? El compilador. Pregunta, ¿cuándo lo hace?

Antes de construir el ejecutable. No cuando se está ejecutando. No cuando han pasado no sé cuánto tiempo de ejecución. No cuando toca llamar a una función a la que hace tiempo que no se llama. Es decir, el compilador intenta crear binarios o ejecutables predecibles en cómo se van a comportar con la memoria, con los recursos, con los valores y en los flujos de trabajo dentro de la propia aplicación.
