¿Por qué me gusta tanto Rust?

Hace ya tres años de que escribí mi primer intento ambicioso de aplicación en Rust, era un componente de un sistema más grande que recibía posiciones de gps de centenares de vehículos y las redirigía a RabbitMQ para su posterior procesamiento. Este componente no salió a producción realmente pues encontramos una solución en Java que tenía implementada la decodificación de varias decenas de protocolos diferentes de comunicación con dispositivos GPS, pero marcó un parteaguas en mi historia como desarrollador y arquitecto.

He de haber conocido Rust en twitter, motivado por los emocionantes comentarios de alguien de habla inglesa. Hay que decir que esto realmente pasa cada día, levantas una piedra y salen tres lenguajes de programación y gente emocionada hablando de ellos, pero de alguna manera Rust saltó como un bicho más raro y más brillante, aunque ciertamente más difícil de atrapar.

Mi proceso con cualquier cosa nueva consiste en probarlo, fallar, no entender, volverlo a probar, ... Lo interesante de ese proceso es que el conocimiento va madurando entre fracaso y fracaso hasta construir un entendimiento sólido de la herramienta en cuestión. Conseguí una versión en epub de El Libro y me la leí de principio a fin y debo decir que eso fue lo que me permitió avanzar con más confianza en el aprendizaje de este increíble lenguaje. La otra cosa que me ayudó fue la interacción con diferentes comunidades (RustMx) y la participación en algunos talleres. Posteriormente incluso impartiría cursos de capacitación en este lenguaje.

Pero ya en serio, por qué te gusta tanto

Hay que recordar que venía de python, un lenguaje sencillo y práctico y del que sin embargo ya podía entrever sus deficiencias. Entoncer ir aprendiendo este nuevo lenguaje me resultaba una tarea fascinante y retadora por su inclinada curva de aprendizaje. Estas son las cosas que más me llamaron la atención.

Su facilidad, como en python. Ok, sí tiene una curva de aprendizaje bastante más empinada que python y sin embargo sigue siendo cierto que llegado a cierto punto de entendimiento las cosas son simplemente naturales y puedes comprender por qué algo tiene que funcionar de tal o cual manera. También en este lenguaje pude predecir comportamientos que estaban ahí esperándome.

Increíble api y documentación. Cada nueva tecnología se puede beneficiar del conocimiento previo para mejorarse, y creo que esto hicieron muy bien con Rust. La homogeneidad que existe en la biblioteca estándar y lo increíblemente bien documentada que está la hace fácil de descubrir y de utilizar.

Sintaxis familiar. Para mi esto es muy importante, ninguna sintaxis esotérica, el código que leía y que escribía se parecía mucho a lo que ya sabía de PHP, Java, C, Python y Javascript. La única cosa interesante fueron quizá los tiempos de vida.

Manejo de memoria. Hasta el momento de aprender Rust siempre había usado lenguajes con recolectores de basura. Si bien es cierto que tengo conocimiento de C, malloc y free, nunca me quedó claro su uso y mi entendimiento de lo que era el heap y el stack siempre fue difuso. Conocer Rust no solo me llevó a un buen entendimiento de estas dos áreas de la memoria sino que puso a mi disposición una forma del manejo de la memoria que no sabía ni que existía: el colector estático de basura. Aquí las variables solo viven exactamente lo que tienen que vivir y son liberadas después de su último uso. No se te puede olvidar hacer free.

Acercamiento al bajo nivel. Por una u otra razón siempre me sentí atraído por esta área, interactuar con las llamadas al sistema, conocer cómo funciona la memoria, compilar a ejecutables que entiende el procesador. Sin embargo los lenguajes que de facto se utilizan para esto (C y C++) son terriblemente oscuros, con documentación dispersa y muros de segmentation fault muy difíciles que franquear. Build sistems igual de complicados, y una terrible situación respecto a las dependencias. Rust hace muchas cosas bien, pero en particular su promesa de empoderar a sus usuarios es una promesa bien cumplida. La documentación es increíble, los errores de compilación son los mejores que he visto en mis 15 años echando código, el manejo de dependencias es moderno, en general el tooling es de primera clase.

Garantías inigualables. Hay que decirlo, ningún otro lenguaje me da la confianza que me da Rust de que si el producto compila realmente va a hacer lo que yo quiero que haga. El sistema de tipos usado en Rust (Hindley Milner) y el uso de tipos unión para suprimir la necesidad de null como constructo del lenguaje hacen que cuando manejes información tengas la certeza de que estás manejando el tipo que declaraste y además ¡permite omitir la mayoría de las delcaraciones de tipos! Además el mismo sistema de tipos es utilizado para controlar cómo se mueve la información entre hilos, poniendo a tu disposición una técnica históricamente difícil o propensa a errores.

Enums y pattern matching. Aunque en el punto anterior mencioné los tipos unión este punto me parece tan importante que necesita su propio inciso. Es muy común cuando escribes código que estás ante la necesidad de representar información que viene en una de varias formas posibles. Hay formas muy tristes y oscuras de representar esto como booleanos o enteros, pero tener un tipo de dato específico para cada escenario y un sistema de tipos fuerte te permite que el compilador además verifique que cuando pasas una variante a una función esa variante tenga sentido en ese contexto. Y no solo es un asunto de tener un tipo unión, que ya de por si es bueno, sino tener la posibilidad de guardar información de la variante dentro y después poder usar pattern matching para extraerla. Esta característica me ha gustado tanto que ha moldeado también (y para bien) cómo diseño el software en otros lenguajes.

Manejo de errores. Hay que decirlo, las excepciones junto con construcciones try catch nunca me parecieron particulamente limpias, no solo visualmente sino conceptualmente tener la ilusión de que puedes recuperar el estado del programa después de cierto tipo de sucesos. En rust la posibilidad de un error es parte de la firma de la función y como tal no puedes utilizar el valor de retorno sin manejar la posibilidad de haber fallado, y pasa lo mismo con los nulos y el tipo Option<T>. Y cuando el error es irrecuperable tienes el panic que mata completamente el hilo.

Paradigma. ¿Es una silla siempre un objeto con cuatro patas y siempre hereda de la clase mueble? Yo creo que si una piedra es suficientemente cómoda y te sientas en ella entonces es una silla. Esta idea ridícula de hacer de todas las cosas un objeto está fundamentalmente rota. Encapsular la información relacionada para mantener los invariantes tiene sentido, añadir comportmientos a grupos de información tiene sentido, y tener funciones que simplemente transforman información aunque no pertenezcan a ninguna clase tiene sentido.

Y dónde lo usas?

Como cualquier herramienta hay lugares en los que brilla más. Actualmente trabajo en una aplicación de escritorio para dibujar llamada Pizarra porque me encanta hacer diagramitas cuando explico cosas, lo cual hago muy seguido.

Porté un procesador de archivos CSV que aunque parecía que estaba reinventando la rueda resultó más útil de lo que pensaba y he usado en un manojo de ocasiones.

Planeo concluir el componente que recibe posiciones de gps que mencionaba al principio.

Tengo a medio portar de python un algoritmo de map matching: le das una traza gps y te dice por qué calles pasó.

Escribí una herramienta de línea de comandos que me ayuda a subir la versión de un proyecto, porque resulta que mantengo algunos paquetes y me gusta que los tags y las versiones del proyecto correspondan.

Tengo un bot de telegram escrito con rocket al que le puedes mandar código LaTex y te lo devuelve renderizado como una imagen que puedes compartir en los chats.