Uso de Rust en una startup: una advertencia
El óxido es increíble, para ciertas cosas. Pero piénselo dos veces antes de elegirlo para una startup que necesita moverse rápido.

Dudé en escribir esta publicación, porque no quiero iniciar o entrar en una guerra santa por los lenguajes de programación. (Solo para quitar el anzuelo de las llamas, ¡Visual Basic es el mejor lenguaje que existe!) Pero varias personas me han preguntado sobre mi experiencia con Rust y si deberían elegir Rust para sus proyectos. Por lo tanto, me gustaría compartir algunos de los pros y los contras que veo de usar Rust en una configuración de inicio, donde moverse rápido y escalar equipos es realmente importante.
Quiero dejar claro que soy fan de Rust por ciertas cosas . Esta publicación no trata sobre cómo Rust es malo como lenguaje ni nada por el estilo. Sin embargo, de lo que sí quiero hablar es de cómo el uso de Rust seguramente implicará un impacto de productividad no trivial que podría ser un factor importante si está tratando de moverse rápido. Considere cuidadosamente si el impacto de la velocidad vale los beneficios del idioma para su empresa y producto.
Desde el principio, debo decir que Rust es muy bueno en lo que está diseñado para hacer , y si su proyecto necesita los beneficios específicos de Rust (un lenguaje de sistemas con alto rendimiento, escritura súper fuerte, sin necesidad de recolección de basura, etc.) entonces Rust es una gran opción. Pero creo que Rust se usa a menudo en situaciones en las que no encaja muy bien, y los equipos pagan el precio de la complejidad y los gastos generales de Rust sin obtener muchos beneficios.
Mi experiencia principal con Rust proviene de trabajar con él durante poco más de 2 años en una startup anterior. Este proyecto era un producto SaaS basado en la nube que es, más o menos, una aplicación CRUD convencional: es un conjunto de microservicios que proporciona un punto final API REST y gRPC frente a una base de datos, así como algunos otros back- microservicios finales (a su vez implementados en una combinación de Rust y Python). Rust se usó principalmente porque algunos de los fundadores de la empresa eran expertos en Rust. Con el tiempo, hicimos crecer el equipo considerablemente (aumentando el número de ingenieros en casi 10 veces), y el tamaño y la complejidad del código base también crecieron considerablemente.
A medida que crecía el equipo y la base de código, sentí que, con el tiempo, estábamos pagando un impuesto cada vez más alto por seguir usando Rust. El desarrollo a veces era lento, el lanzamiento de nuevas funciones tomó más tiempo de lo que esperaba, y el equipo estaba sintiendo un verdadero impacto en la productividad debido a esa decisión temprana de usar Rust. A la larga, reescribir el código en otro idioma habría hecho que el desarrollo fuera mucho más ágil y acelerado el tiempo de entrega, pero encontrar el tiempo para el trabajo de reescritura principal habría sido extremadamente difícil. Así que estábamos atrapados con Rust a menos que decidiéramos morder la bala y reescribir una gran parte del código.
Se supone que el óxido es lo mejor desde el pan rebanado, entonces, ¿por qué no funcionó tan bien para nosotros?

Rust tiene una gran curva de aprendizaje.
He trabajado en docenas de lenguajes en mi carrera y, con pocas excepciones, la mayoría de los lenguajes procedimentales modernos (C++, Go, Python, Java, etc.) todos muy similares en términos de sus conceptos básicos. Cada idioma tiene sus diferencias, pero generalmente se trata de aprender algunos patrones clave que difieren entre los idiomas y luego uno puede ser productivo con bastante rapidez. Sin embargo, con Rust, uno necesita aprender ideas completamente nuevas , como la vida útil, la propiedad y el verificador de préstamos. Estos no son conceptos familiares para la mayoría de las personas que trabajan en otros lenguajes comunes, y existe una curva de aprendizaje bastante empinada, incluso para programadores experimentados.
Algunas de esas ideas "nuevas" están, por supuesto, presentes en otros lenguajes, especialmente en los funcionales, pero Rust las trae a una configuración de lenguaje "convencional" y, por lo tanto, serán nuevas para muchos de los recién llegados a Rust.
A pesar de ser algunos de los desarrolladores más inteligentes y experimentados con los que había trabajado, muchas personas en el equipo (incluido yo mismo) lucharon por comprender las formas canónicas de hacer ciertas cosas en Rust, cómo asimilar los mensajes de error a menudo arcanos del compilador, o cómo entender cómo funcionaban las bibliotecas de claves (más sobre esto a continuación). Comenzamos a tener sesiones semanales de "aprendizaje de Rust" para el equipo para ayudar a compartir conocimientos y experiencia. Todo esto fue una pérdida significativa para la productividad y la moral del equipo, ya que todos sintieron la lentitud del desarrollo.
Como punto de comparación de lo que parece adoptar un nuevo lenguaje en un equipo de software, uno de mis equipos en Google fue uno de los primeros en cambiar completamente de C++ a Go, y no tomó más de dos semanas antes de que todo Un equipo de 15 personas impares codificaba cómodamente en Go por primera vez. Con Rust, incluso después de meses de trabajar diariamente en el idioma, la mayoría de las personas del equipo nunca se sintieron completamente competentes. Varios desarrolladores me dijeron que a menudo se sentían avergonzados de que sus funciones tardaban más de lo esperado en aparecer y que pasaban tanto tiempo tratando de entender Rust.
Hay otras formas de solucionar los problemas que Rust está tratando de resolver.
Como se mencionó anteriormente, el servicio que estábamos creando era una aplicación CRUD bastante sencilla. La carga esperada en este servicio iba a estar en el orden de no más de unas pocas consultas por segundo, como máximo, durante la vida útil de este sistema en particular. El servicio era una interfaz para una canalización de procesamiento de datos bastante elaborada que podía tardar muchas horas en ejecutarse, por lo que no se esperaba que el servicio en sí fuera un cuello de botella en el rendimiento. No hubo ninguna preocupación particular de que un lenguaje convencional como Python tuviera problemas para ofrecer un buen rendimiento. No hubo necesidades especiales de seguridad o simultaneidad más allá de lo que cualquier servicio orientado a la web debe enfrentar. La única razón por la que usábamos Rust era porque los autores originales del sistema eran expertos en Rust, no porque fuera especialmente adecuado para crear este tipo de servicio.
Rust ha tomado la decisión de que la seguridad es más importante que la productividad del desarrollador. Esta es la compensación correcta para hacer en muchas situaciones, como la creación de código en un kernel de sistema operativo o para sistemas integrados con restricciones de memoria, pero no creo que sea la compensación correcta en todos los casos, especialmente en las empresas emergentes donde la velocidad es crucial. Soy pragmático. Prefiero que mi equipo dedique tiempo a depurar la fuga de memoria ocasional o el error de tipeo del código escrito, por ejemplo, Python o Go, que que todos en el equipo sufran un impacto de productividad 4 veces mayor por usar un lenguaje diseñado para evitar estos problemas por completo. .
Como mencioné anteriormente, mi equipo en Google creó un servicio, completamente en Go, que con el tiempo creció hasta admitir a más de 800 millones de usuarios y casi 4 veces el QPS de la Búsqueda de Google en su punto máximo. Puedo contar con los dedos de una mano la cantidad de veces que encontramos un problema causado por el sistema de tipos o el recolector de basura de Go en los años que construimos y ejecutamos este servicio. Básicamente, los problemas que Rust está diseñado para evitar se pueden resolver de otras maneras : mediante buenas pruebas, buen linting, buena revisión del código y buen monitoreo. Por supuesto, no todos los proyectos de software tienen este lujo, por lo que puedo imaginar que Rust puede ser una buena opción en esas otras situaciones.

Tendrá dificultades para contratar desarrolladores de Rust.
Contratamos a un montón de personas durante mi tiempo en esta empresa, pero solo dos o tres de las más de 60 personas que se unieron al equipo de ingeniería tenían experiencia previa con Rust. Esto no fue por falta de tratar de encontrar desarrolladores de Rust, simplemente no están disponibles. (Del mismo modo, dudábamos en contratar a personas que solo querían codificar en Rust, ya que creo que es una mala expectativa establecer en un entorno de inicio donde las elecciones de idioma y otras tecnologías deben realizarse de manera ágil). Esta escasez El talento de los desarrolladores de Rust cambiará con el tiempo, a medida que Rust se vuelva más convencional, pero construir alrededor de Rust suponiendo que podrá contratar a personas que ya saben que parece arriesgado.
Otro factor secundario es que el uso de Rust seguramente conducirá a un cisma entre las personas del equipo que conocen Rust y las que no. Debido a que habíamos elegido un lenguaje de programación "esotérico" para este servicio, los otros ingenieros de la empresa que de otro modo podrían haber sido útiles en la creación de funciones, la depuración de problemas de producción, etc., no pudieron ayudar en gran medida porque no podían hacer cabeza o colas de la base de código de Rust. Esta falta de fungibilidad en el equipo de ingeniería puede ser una verdadera desventaja cuando intenta moverse rápido y aprovechar las fortalezas combinadas de todos los miembros del equipo. En mi experiencia, las personas generalmente tienen poca dificultad para moverse entre lenguajes como C++ y Python, pero Rust es lo suficientemente nuevo y complejo como para presentar una barrera para que las personas trabajen juntas.
Las bibliotecas y la documentación son inmaduras.
Este es un problema que (¡espero!) Se solucionará con el tiempo, pero en comparación con, digamos, Go, la biblioteca y el ecosistema de documentación de Rust son increíblemente inmaduros. Ahora, Go tuvo la ventaja de que fue desarrollado y respaldado por todo un equipo dedicado en Google antes de su lanzamiento al mundo, por lo que los documentos y las bibliotecas estaban bastante pulidos. El óxido, en comparación, se ha sentido durante mucho tiempo como un trabajo en progreso. Los documentos de muchas bibliotecas populares son bastante escasos y, a menudo, es necesario leer el código fuente de una biblioteca determinada para comprender cómo usarla. Esto es malo.
Los apologistas de Rust en el equipo a menudo decían cosas como "async/await todavía son realmente nuevos" y "sí, faltan los documentos para esa biblioteca", pero estas deficiencias afectaron al equipo de manera bastante significativa. Cometimos un gran error desde el principio al adoptar Actix como el marco web para nuestro servicio, una decisión que condujo a una enorme cantidad de dolor y sufrimiento a medida que nos encontrábamos con errores y problemas enterrados en lo profundo de la biblioteca que nadie sabía cómo solucionar. (Para ser justos, esto fue hace unos años y tal vez las cosas hayan mejorado ahora).
Por supuesto, este tipo de inmadurez no es realmente específico de Rust, pero equivale a un impuesto que tu equipo debe pagar. No importa qué tan buenos sean los tutoriales y la documentación del idioma principal, si no puede descubrir cómo usar las bibliotecas, no importa mucho (a menos que esté planeando escribir todo desde cero, por supuesto).
Rust hace que desbastar nuevas características sea muy difícil.
No conozco a nadie más, pero al menos para mí, cuando estoy creando una nueva función, generalmente no tengo todos los tipos de datos, API y otros detalles finos resueltos desde el principio. A menudo, solo estoy tirando pedos al código tratando de obtener una idea básica que funcione y comprobando si mis suposiciones sobre cómo deberían funcionar las cosas son más o menos correctas. Hacer esto en, digamos, Python es extremadamente fácil, porque puede jugar rápido y suelto con cosas como escribir y no preocuparse si ciertas rutas de código se rompen mientras elabora su idea. Puede volver más tarde y ponerlo todo en orden y corregir todos los errores de tipo y escribir todas las pruebas.
En Rust, este tipo de "borrador de codificación" es muy difícil, porque el compilador puede quejarse y se quejará de cada maldita cosa que no pasa la verificación de tipo y vida útil , como está diseñado explícitamente para hacer. Esto tiene mucho sentido cuando necesita construir su implementación final lista para producción, pero apesta absolutamente cuando está tratando de crear algo para probar una idea o establecer una base básica. La unimplemented!
macro es útil hasta cierto punto, pero aún requiere que todo se verifique arriba y abajo en la pila antes de que puedas compilar.
Lo que realmente molesta es cuando necesita cambiar la firma de tipo de una interfaz de soporte de carga y se encuentra pasando horas cambiando cada lugar donde se usa el tipo solo para ver si su puñalada inicial en algo es factible. Y luego rehacer todo ese trabajo cuando te das cuenta de que necesitas cambiarlo de nuevo.

¿En qué es bueno Rust?
Definitivamente hay cosas que me gustan de Rust y características de Rust que me encantaría tener en otros idiomas. La match
sintaxis es genial. Los rasgos , y son realmente poderosos, y el Option
operador Result
es una forma elegante de manejar errores. Muchas de estas ideas tienen contrapartes en otros lenguajes, pero el enfoque de Rust con ellas es particularmente elegante.Error
?
Absolutamente usaría Rust para proyectos que necesitan un alto nivel de rendimiento y seguridad y para los cuales no estaba terriblemente preocupado por la necesidad de evolucionar rápidamente partes importantes del código con un equipo completo que está creciendo rápidamente. Para proyectos individuales o equipos muy pequeños (digamos, 2 o 3 personas), Rust probablemente estaría bien. Rust es una excelente opción para cosas como módulos de kernel, firmware, motores de juegos, etc., donde el rendimiento y la seguridad son primordiales, y en situaciones en las que puede ser difícil realizar pruebas realmente exhaustivas antes del envío.
De acuerdo, ahora que he cabreado lo suficiente a la mitad de los lectores de Hacker News, supongo que ahora es un buen momento para anunciar el tema de mi próximo artículo: ¿Por qué nano
el editor de texto es superior? ¡Hasta la próxima!