Por qué no Python
Años atrás, pero también años después de fundar Lokad, me di cuenta de que ninguna aplicación única jamás lograría algo cercano a la grandeza en lo que se refiere a la optimización de supply chain. Hicimos lo mejor que pudimos, pero no fue suficiente. Sin importar cuántas funciones incorporáramos en las primeras versiones de Lokad, cada nuevo cliente parecía desesperadamente distinto a todos los anteriores que habíamos logrado cubrir hasta ahora. Supply chain challenges son simplemente demasiado diversas y caóticas para ser encuadradas en un número razonable de menús, botones y opciones.

De hecho, la mayoría de nuestros competidores reconocen esta situación y optaron por construir productos de software que presentan un número desmedido de menús, botones y opciones, todo esto, como un intento desesperado de hacer frente a todos los supply chain challenges. Desafortunadamente, este camino conduce a monstruosidades de software que se transforman en espectaculares fracasos cuando se implementan a gran escala. Me refiero a este antipatrón como el Non-Euclidian Horror.
Así, enfrentando una clase de problemas - es decir, supply chain challenges - que simplemente no pudieron ser resueltos con una aplicación única, comenzamos, en parte por accidente1, a abordar en su lugar el meta-problema: cómo entregar aplicaciones hechas a la medida donde cada aplicación se dedicaría a la resolución de un único problema para una situación dada, por ejemplo, la optimización de reabastecimiento para una empresa específica.
Entregar software hecho a la medida para empresas no es nada nuevo. La industria del software comenzó de esa manera en los años 60, y más tarde evolucionó durante los años 80 hacia el dominante modelo shrinkwrap que conocemos hoy. Como regla general, el software hecho a la medida tiende a tener muchas propiedades indeseables comparado con el shrinkwrap: mayores inversiones iniciales, instalaciones prolongadas, mayores costos de mantenimiento, mayores riesgos, etc.
Sin embargo, la experiencia que adquirí durante los primeros años de Lokad indicó que, en lo que respecta a la optimización de supply chain, el software hecho a la medida tenía una ventaja clave: en realidad, ofrecía resultados excelentes. De hecho, mientras que nuestra aplicación original ofrecía, en el mejor de los casos, resultados aceptables2 sin importar lo precisos que fueran los forecast, esos prototipos frecuentemente funcionaban excelentemente. Además, el único truco involucrado era la extrema especialización de la pieza de software destinada al problema en cuestión.
Después de agotar lo que parecía ser todas las alternativas, concluimos que entregar aplicaciones hechas a la medida era el único camino a seguir. Sin embargo, la escalabilidad; cómo entregar muchas aplicaciones, y la mantenibilidad; cómo mantener los costos de mantenimiento bajo control, eran dos preocupaciones fundamentales. Primero, tuvimos que elegir un lenguaje de programación. En ese momento, consideramos muchas opciones: R, Python, JavaScript, Lua, C#, … y desarrollar nuestro propio lenguaje de programación específico de dominio (DSL), que más tarde sería conocido como Envision. Discutir los pros y los contras de todas esas opciones resultaría algo tedioso3, por lo que, para mayor claridad, la discusión se concentró en la elección entre Python y Envision; siendo Python el competidor más fuerte frente a desarrollar nuestro propio DSL.
Python resultó atractivo por su simplicidad y por todo su rico ecosistema de bibliotecas de terceros, especialmente en el área de machine learning4. También era una opción de bajo costo para Lokad: dado que Python, y prácticamente todas sus bibliotecas populares, son open source, simplemente habríamos reempaquetado un subconjunto reducido de Python, incluyendo en una lista blanca unas pocas docenas de paquetes seleccionados, y listo. La mayor parte del trabajo para Lokad se habría centrado en ofrecer una experiencia PaaS en torno a Python al estilo Heroku, pero lo más hecho a la medida posible hacia los supply chain challenges.
Sin embargo, aquí hay una prueba decisiva que consideramos: ¿era razonable esperar que un analista de negocio - más tarde conocido como un supply chain scientist - que trabajara 1 día a la semana durante 6 meses entregara una aplicación de grado producción para resolver un desafío de supply chain crítico, como el reabastecimiento, para una empresa de $10M? Al considerar la opción de Python, quedó claro que nunca podríamos siquiera acercarnos a tal nivel de eficiencia operativa.
En primer lugar, Python requiere ingenieros de software. De hecho, Python, como cualquier lenguaje de programación completo, expone toneladas de intrincadas cuestiones técnicas a quien esté escribiendo código en Python. Aunque el rol del supply chain scientist solo se formalizó más tarde, tuvimos la intuición desde temprano de que, incluso considerando personas talentosas e inteligentes, esperar que fuesen expertos tanto en ingeniería de supply chain como en ingeniería de software era demasiado. Necesitábamos capacidades programáticas accesibles a un amplio espectro de personas con mentalidad técnica, no solo a ingenieros de software profesionales.
Así, diseñamos Envision como un lenguaje para eliminar toda una serie de problemas técnicos que son inevitables con Python. Por ejemplo:
- Los objetos pueden ser null, las fechas pueden estar absurdamente en el pasado o en el futuro, NaN puede propagarse felizmente a través de tu canal de datos, las cadenas pueden volverse absurdamente grandes… En supply chain, estas “características” no son más que problemas esperando a suceder.
- Los elementos orientados a objetos (es decir, las clases) están garantizados a ser mal utilizados5, y lo mismo se puede decir de las excepciones personalizadas o las Regexes. La mera presencia de esos elementos es, en el mejor de los casos, una distracción poco saludable.
- Múltiples operaciones básicas como analizar diferentes archivos tabulares (incluida la hoja de cálculo de Excel) no forman parte del lenguaje, y requieren lidiar con muchos paquetes dispares, cada uno con sus propias intrincadas cuestiones técnicas.
Ninguna de estas clases de problemas técnicos puede ser eliminada de Python sin perjudicar el lenguaje en sí. Envision, como lenguaje de programación, es accesible a supply chain specialists (vs software specialists), solo por su enfoque sumamente preciso en problemas de optimización predictiva de supply chain.
Piensa en la última vez que tuviste que realizar cálculos con una hoja de Excel, e imagina dictando todos los cambios que realizaste en esa hoja por teléfono sin poder verla por ti mismo. Así es como se ve una iniciativa de optimización de supply chain impulsada por practicantes, pero implementada por ingenieros de software (no especialistas en supply chain). El negocio gasta una enorme cantidad de tiempo en transmitir lo que quiere a TI; y TI gasta una enorme cantidad de tiempo tratando de descifrar lo que el negocio desea. Tras una década de experiencia en Lokad, observo que depender de desarrolladores de software, que no son supply chain specialists, para entregar una iniciativa de optimización de Supply Chain Quantitativa multiplica los costos por al menos un factor de 5, sin importar lo ágil y talentoso que pueda ser el equipo de software.
En segundo lugar, los costos de mantenimiento de los prototipos apresurados en Python se disparan. Fuera de la industria del software, pocas personas se dan cuenta de que la ingeniería de software6 se trata principalmente de mantener los costos de mantenimiento bajo control. Sin embargo, resolver problemas de optimización de supply chain es un proceso desordenado: los datos de muchos sistemas (poco) confiables deben ser canalizados de forma confiable, procesos imperfectos y en constante cambio deben ser documentados y modelados, las métricas de optimización reflejan una estrategia empresarial en un estado constante de cambio, etc. Como resultado, cualquiera sea la pieza de software que se escriba para entregar la optimización de supply chain, siempre incorpora una dosis masiva de complejidad específica del dominio, simplemente afrontando lo que el mundo nos arroja.
Sin embargo, el tiempo es esencial. No tiene sentido tener el plan perfecto para el plan de producción del año pasado. Como regla general, es seguro asumir que el día en que el prototipo de software comience a funcionar, se trasladará a producción en cuestión de semanas, sin importar si el prototipo está bien o mal escrito.
Esperar que la alta dirección apruebe un retraso de 6 meses para reescribir el prototipo y hacerlo de grado producción desde la perspectiva de mantenimiento es un pensamiento ilusorio. Sin embargo, poner un prototipo apresurado en Python en producción es la receta para costos de mantenimiento épicos, luchando una batalla cuesta arriba con un flujo incesante de errores que tendrán que ser reparados con cinta adhesiva 24 / 7.
Así, la única manera práctica de mantener la producción en orden es escribir el prototipo con un lenguaje de programación que garantice un alto grado de correctitud por diseño. Por ejemplo, a diferencia de Python, Envision ofrece:
- Tiempo de ejecución finito garantizado en tiempo de compilación: al procesar múltiples terabytes de datos, se vuelve muy tedioso esperar horas antes de darse cuenta de que un cálculo simplemente nunca va a terminar. Consumo de memoria limitado garantizado en tiempo de compilación: luchar contra errores de falta de memoria en el lote nocturno de producción no es nada divertido y, en la práctica, interrumpe gravemente las operaciones.
- Lecturas y escrituras atómicas: Envision previene, por diseño, lecturas y escrituras concurrentes dentro del sistema de archivos, incluso cuando se están enviando archivos a través de FTP mientras se ejecutan scripts. El sistema de archivos que respalda a Envision es básicamente un Git hecho a la medida para archivos planos giganormales. Sin una adecuada versionación de data, muchos errores se convierten en heisenbugs: para cuando alguien profundiza en el problema, los datos han sido actualizados, y el problema ya no se puede replicar.
- Ejecución scale-out ambiental del programa sobre una computación en la nube de recursos computacionales, eliminando todos los obstáculos para la paralelización que son inevitables en cuanto los datos superan algunas decenas de gigabytes.
Los lenguajes de programación genéricos ofrecen poca correctitud por diseño; y Python, inclinándose fuertemente hacia el late binding, ofrece excesivamente poco en esta área. Incluso al considerar mejores alternativas – desde la perspectiva de la correctitud por diseño – como Rust, esas alternativas están lejos de ser satisfactorias para la optimización de supply chain.
Aquí hay algunas áreas adicionales donde Envision brilla de maneras que simplemente no son accesibles para Python:
Defensa en profundidad: Tan pronto como alguien comienza a escribir código en tu organización, a menos que se tomen precauciones muy especiales7, su código se convierte en una responsabilidad inmediata desde la perspectiva de seguridad de TI. Con Python, es prácticamente posible hacer cualquier cosa en la máquina que ejecuta el script de Python. Restringir Python adecuadamente en la práctica es un problema diabólicamente complicado. En particular, cualquier cadena producida por el script de Python es un vector de inyección potencial. Aunque las inyecciones SQL son notorias, (demasiada) poca gente se da cuenta de que incluso archivos de texto plano como CSV son vulnerables a ataques de inyección. Envision ofrece un grado de seguridad que simplemente no puede ser replicado con Python. Las filtraciones de datos están en aumento, y esparcir fragmentos de Python por todas partes no va a hacer ningún bien para la seguridad de TI.
Rendimiento transparente: Si un programa es imprácticamente lento para ejecutarse, entonces este programa ni siquiera debería compilar en primer lugar8. Si se hace una línea más corta en un programa, entonces el programa debería ejecutarse más rápido. Si solo se cambia una línea, únicamente esa línea debería ser recalcada9 al volver a ejecutar el programa sobre los mismos datos. Al compilar, el compilador no debería dirigirse a una máquina en particular, sino a una computación en la nube de recursos, ofreciendo una paralelización automática impulsada por datos. Envision avanza mucho en lograr todas estas propiedades por defecto sin ningún esfuerzo de codificación. En contraste, sí requiere un uso masivo de librerías especializadas en Python para siquiera empezar a aproximarse a tales propiedades.
Actualización transparente: Lo último en tecnología es un objetivo siempre cambiante en lo que respecta al software. En 2010, el mejor toolkit de machine learning era SciPy (según se dice). En 2013, era scikit. En 2016, era Tensorflow. En 2017, era Keras. En 2019, era PyTorch. Existe un dicho en ingeniería de software que dice que puedes datar el año de nacimiento de cualquier proyecto de software observando su pila de software y sus dependencias. De hecho, en cuanto implementas tus propios scripts en Python, incorporarás múltiples dependencias que pueden no envejecer bien. En contraste, con Envision, estamos aprovechando extensamente las reescrituras automáticas de código10, para mantener los scripts “legacy” actualizados con un lenguaje en constante cambio.
Stack empaquetado: Los scripts de Python no pueden vivir en un vacío11. El código necesita ser versionado (e.g. Git) con derechos de acceso (e.g. GitHub). Necesitan un entorno en el que ejecutarse que no sea tu máquina (e.g. una VM Linux en la computación en la nube). Se necesita un programador de tareas para orquestar el canal de datos (e.g. AirFlow). Se necesita una capa de almacenamiento columnar distribuido para la preparación de datos (e.g. Spark). Se requiere un toolkit de machine learning para análisis predictivo (e.g. TensorFlow). Se precisa un toolkit de optimización para tratar con problemas combinatorios de supply chain (e.g. GLPK). Los resultados en crudo deben exponerse en algún lugar para su consumo posterior (e.g. servidor SFTP). Los compañeros practicantes de supply chain deben poder monitorear lo que sucede (e.g. una interfaz de usuario web). Se deben hacer cumplir los derechos de acceso (e.g. Active Directory), etc. Envision agiliza todo esto en una única meta-aplicación, eliminando la carga de ensamblar docenas de piezas de software para entregar incluso la aplicación más básica.
Luego, aunque es un lenguaje excelente, Python no está exento de críticas:
- El rendimiento de cálculo es malo, y es una batalla cuesta arriba encaminar cada cálculo individual a través de la librería correcta (e.g. NumPy) para evitar obtener un rendimiento abismalmente deficiente en tareas de procesamiento de datos. Además, el uso de múltiples librerías tiende a crear mucha fricción cuando los datos tienen que ser trasladados de una a otra.
- El rendimiento de la memoria es malo también, y en particular, la recolección de basura por conteo de referencias de Python está desfasada - y todos los lenguajes de programación más recientes como Java, C# o JavaScript están utilizando tracing en su lugar. Cuando se trata de tareas intensivas en memoria con big data, esto afecta negativamente.
- La gestión de paquetes en Python ha sido un desastre durante mucho tiempo, y se necesita un especialista en paquetes para hacerlo bien. Además, este problema se ha visto agravado por actualizaciones de lenguaje de alta fricción.
- La mayoría de las (pocas) comprobaciones de corrección sólo se realizan en runtime, cuando se ejecuta el programa, lo que genera una frustración interminable al tratar con el procesamiento de datos. Los problemas evidentes sólo se manifiestan después de varios minutos de ejecución, reduciendo la productividad.
En conclusión, aunque Python es asombroso (lo es), no es una respuesta satisfactoria para la optimización de supply chain. Construir y mantener una app de machine learning de nivel producción en Python es muy posible, pero los costos son significativos, y a menos que tu empresa esté preparada para tener al menos un pequeño equipo de ingeniería de software dedicado al mantenimiento de esta app, todo esto no va a ofrecer resultados satisfactorios para tu supply chain.
Desarrollar Envision, un lenguaje de programación específico de dominio dedicado a la optimización predictiva de supply chain, no fue nuestra primera opción. Ni siquiera fue nuestra décima opción. Fue más bien la única solución funcional que teníamos tras agotar una larga lista de alternativas más convencionales durante cinco años. Siete años después y muchas empresas clientes más tarde, cada nuevo cliente aún logra sorprendernos, de una forma u otra, con otro giro inesperado en su supply chain, que jamás habríamos podido abordar con un enfoque clásico de enterpriseware. Se necesitaba programabilidad, pero Python no era la solución que requeríamos.
-
En 2013, aún tenía la impresión de que era posible ofrecer una app satisfactoria para la optimización de supply chain. Fue, en realidad, el enfrentamiento con desafíos de pricing lo que, de alguna manera, nos forzó y orientó a Lokad hacia la creación de su propio lenguaje de programación específico de dominio. Este lenguaje estaba destinado inicialmente únicamente a la optimización de pricing, pero rápidamente nos dimos cuenta de que este enfoque era exactamente lo que se necesitaba para la optimización de supply chain. ↩︎
-
La idea de que ofrecer precisión superior en forecast conduciría, por sí sola, a un rendimiento superior de supply chain, probablemente fue una de las mayores ideas erróneas que tuve al fundar Lokad. Mira este episodio de Lokad TV para obtener una perspectiva más sensata sobre el asunto. ↩︎
-
La mayoría de los problemas que detectamos en Python no tenían nada que ver con Python per se, que es un gran lenguaje de programación, sino simplemente con el hecho de que Python es un lenguaje de programación genérico. ↩︎
-
En 2013, Python aún no había alcanzado el dominio que llegó a obtener en los años siguientes en el campo del machine learning, R seguía siendo un contendiente fuerte; sin embargo, SciPy y NumPy, dos excelentes bibliotecas, ya estaban presentes y en auge en ese momento. ↩︎
-
Mira esta excelente charla Stop Writing Classes de Pycon 2012. Incluso los ingenieros de software más experimentados tienden a equivocarse. ↩︎
-
La ingeniería de software en contraposición a la ciencia de la computación. La primera se trata de garantizar sistemas de producción, mientras que la segunda se ocupa de descifrar problemas complejos, como descubrir algoritmos más rápidos. ↩︎
-
Desafortunadamente, en cuestiones de seguridad del código, hay poco o ningún sustituto para las revisiones sistemáticas por pares del código. ↩︎
-
Debido al problema de detención, el lector atento podría inferir que Envision no es un lenguaje Turing completo. De hecho, Envision no lo es. ↩︎
-
Envision se basa en las diferencias entre gráficos de cómputo y trata de minimizar la cantidad de recalculaciones entre cambios incrementales para permitir un prototipado muy rápido sobre grandes conjuntos de datos. Sin embargo, dependiendo de la situación, cambiar una sola línea puede requerir el recálculo de todo el script. ↩︎
-
Las reescrituras automáticas de código son sumamente difíciles para un lenguaje de programación genérico. A menos que el lenguaje y toda su biblioteca estándar hayan sido diseñados con precisión teniendo en cuenta este requisito, las herramientas de actualización automática hacen poco en la práctica. Al diseñar Envision, sabíamos que cometeríamos muchos errores (y lo hicimos), por lo que prestamos mucha atención para asegurarnos de que el lenguaje fuera particularmente adecuado para reescrituras automáticas. Hasta la fecha, hemos realizado más de 100 reescrituras incrementales desde la creación de Envision. ↩︎
-
Irónicamente, “Batteries Included” es uno de los lemas de Python. Sin embargo, la gran cantidad de ‘pegamento’ necesaria para unir todos los elementos requeridos para construir una app destinada a la optimización predictiva de supply chain es abrumadora. ↩︎