Los límites de la interoperabilidad Elm/JS

Muchos lenguajes tienen una “interfaz de funciones foráneas” (FFI por su sigla en inglés) que nos permite llamar directamente a funciones del lenguaje “anfitrión”. Por ejemplo, Scala puede llamar directamente a funciones de Java. Lo mismo ocurre en los casos de Clojure con Java, Python con C, Haskell con C, y muchos otros.

Elm no tiene una interfaz de funciones foráneas tradicional con JavaScript. No es posible llamar arbitrariamente a funciones de JavaScript cuando uno quiera. Es una limitación que trae beneficios que mucha gente aprecia, pero no es para cualquiera. Si te encuentras evaluando si usar Elm con fines comerciales, te recomiendo que revises estos ejemplos de interoperabilidad para saber si puedes cubrir tus necesidades usando flags, puertos y elementos personalizados.

Pero, ¿por qué Elm tomó una decisión diferente en comparación con otros lenguajes de programación?

Ventajas y desventajas

Los puertos son un caso atípico en la historia de los lenguajes de programación. Hay dos principales estrategias para la interoperabilidad, y Elm no adoptó ninguna de ellas:

  1. Retrocompatibilidad total. Por ejemplo, C++ es un superconjunto de C, y TypeScript también lo es de JavaScript. Es decir, ofrecen estrictamente más capacidades que el lenguaje que buscan reemplazar. Esta es la estrategia más permisiva, y ha resultado ser muy efectiva. Visto de cierta manera, los usuarios del lenguaje anfitrión ya son usuarios de nuestro lenguaje nuevo.
  2. Interfaz de función foránea (FFI). Permite crear vínculos directos hacia funciones en el lenguaje anfitrión. Por ejemplo, Scala puede llamar funciones de Java directamente. Lo mismo ocurre con Clojure con Java, Python con C, Haskell con C, y muchos otros. Esta también es una estrategia que ha resultado ser muy efectiva.

Estos caminos son atractivos para facilitar un crecimiento rápido y tener máxima flexibilidad, pero no son ideales para Elm por dos razones:

  1. Pérdida de garantías. Una de las mejores cosas sobre Elm es que hay categorías enteras de problemas de las que simplemente no te tienes que preocupar. No hay excepciones inesperadas que capturar, y las funciones no pueden mutar datos a su gusto. Creo que este es el principal valor que Elm ofrece sobre sus alternativas, pero si pudiéramos llamar código JS directamente, todo se evapora. ¿Este paquete producirá excepciones en tiempo de ejecución? ¿Cuándo? ¿Mutará los valores que le paso? ¿Necesito chequear? ¿El paquete produce efectos secundarios, como comunicarse con servidores externos o escribir passwords en sus logs? Mucha gente que programa Elm tiene interés en el lenguaje justamente porque al usarlo no necesitan estar constantemente cubriéndose las espaldas.
  2. Avalancha de paquetes. Hay una gran demanda de traducciones literales de APIs de JavaScript a Elm. En los dos años antes de que existiera elm/html, estoy seguro de que, de ser posible, alguien hubiera escrito un paquete para usar jQuery. Esto ya ha ocurrido con otros lenguajes funcionales tipados que compilan a JS, pero que tienen una estrategia más tradicional de interoperabilidad. Hasta donde sé, este tipo de situación es más o menos única en lenguajes que compilan a JS. No existe esa presión en Python, por ejemplo, así que probablemente es un problema producto de la cultura e historia del ecosistema de JavaScript en específico.

Dados estos problemas, los puertos y los elementos personalizados son atractivos porque nos permiten lograr cosas usando JavaScript, sin sacrificar los beneficios de Elm. Ideal. Pero por otro lado, también significa que Elm no puede simplemente colgarse del ecosistema JavaScript para sumar librerías más rápidamente. Si adoptamos una visión más a largo plazo, creo que es una buena estrategia. Como consecuencia:

  1. Los paquetes están diseñados para Elm. Mientras la comunidad Elm adquiere experiencia y confianza, empezamos a ver nuevas y propositivas estrategias para enfrentar la diagramación y la visualización de datos que se acoplan perfectamente con la Arquitectura Elm y con el ecosistema en general. Anticipo que esto se repetirá con muchos otros problemas.
  2. El código es portátil. Si Elm llegara un día a compilar a x86 o WebAssembly, todo el ecosistema seguiría funcionando, ¡pero más rápido! Los puertos garantizan que todos los paquetes estén escritos completamente en Elm, y el lenguaje mismo está diseñado para que nuevos destinos de compilación sean viables.
  3. Los paquetes son más seguros. Lenguajes como JavaScript tienen serios problemas de seguridad con sus paquetes. Frecuentemente oímos noticias sobre robo de credenciales o de llaves de API, y esto causa un costo permanente en auditoría de todos estos paquetes. Es hasta posible instalar un keylogger en window. Los paquetes de Elm garantizan que categorías completas de vulnerabilidades simplemente no pueden ser explotadas, lo que reduce el costo de la auditoría y los riesgos de seguridad en general.
  4. Es más fácil de optimizar. El estilo del código generado ha cambiado considerablemente de versión a versión. Por ejemplo, en la versión 0.19 pudimos reducir dramáticamente el tamaño de los exportables, por (1) generar código que funciona mejor con los minificadores de JavaScript, y (2) representar los tipos personalizados en forma diferente dependiendo del nivel de optimización elegido. Seguramente volveremos a hacer cambios para permitir compilar en múltiples archivos separados, o si encontramos una forma de mejorar el rendimiento de cada llamada a una función “currificada”. Además, el compilador puede asumir que todo el código es puro, lo que le permite manipularlo mucho más que otros compiladores. Si nos casáramos con una específica convención de llamada a funciones, muchas de estas optimizaciones serían imposibles.

Es un camino más largo y arduo, pero los lenguajes de programación pueden vivir mucho más de 30 años, tienen que sostener a equipos y empresas por décadas. Y cuando pienso en cómo será Elm en 20 o 30 años, las ventajas otorgadas por los puertos me permiten ser muy optimista. Mi charla “¿Qué es el éxito?” (en inglés) empieza lenta, pero eventualmente toca este tema.

Y repito, este no es un camino para cualquiera. Hay muchos lenguajes alternativos que tienen una interfaz de función foránea tradicional, y te sugiero que los investigues si crees que serían una mejor opción. ¿El ecosistema de paquetes es igual de coherente? Tal vez no. ¿Tendrás más excepciones en tiempo de ejecución? Tal vez sí. Pero tal vez la flexibilidad vale la pena para ti. Así que te animo a que revises estos ejemplos de interoperabilidad para decidir si las flags, los puertos y los elementos personalizados cubren todas tus necesidades. Esto es especialmente importante si estás considerando usar Elm con fines comerciales.

results matching ""

    No results matching ""