De compiladores y máquinas de pila

[English Version]Este enlace se abrirá en una ventana nueva

Uno de los principios que he intentado aplicar tanto en el desarrollo de nuestros productos como de los proyectos en los que hemos participado, es el de acercar la tecnología al usuario de forma sencilla. Buscando en todo momento maximizar la funcionalidad sin, por ello, olvidar la excelencia técnica.

Dentro de esta serie de iniciativas voy a contaros como aplicamos conceptos de compiladores y maquinas de pila para simplificar la operación de los administradores de nuestros productos.

En Divisa iT ya contábamos, dentro de nuestra plataforma Proxia®Este enlace se abrirá en una ventana nueva, con mucha experiencia en el desarrollo de sistemas de automatización de formularios. Pero éstos, llegado un punto, y como bien me gusta insistir a mis clientes, no hacen magia, y era necesario arremangarse para obtener el resultado deseado. La pregunta era, ¿se puede dar a esto una vuelta de tuerca adicional? ¿podemos hacer algo más por el usuario?

La respuesta desde el punto de vista del qué hacer, vino de la mano, como muchas veces, del análisis comparativo. Si un niño – mis hijos – eran capaces de manejar ScratchEste enlace se abrirá en una ventana nueva con soltura, ¿por qué no una persona adulta y con cierta iniciativa? Si bien Scratch no era directamente aplicable, si lo era la idea. Lógicamente no íbamos a desarrollar algo de cero – el time-to-market sería excesivo –, así que opté por utilizar BlocklyEste enlace se abrirá en una ventana nueva de GoogleEste enlace se abrirá en una ventana nueva, que nos proporcionaba la base para lo que necesitábamos.

Para los que no lo conozcáis, lo que Blockly nos permite es programar arrastrando bloques, que pueden incluir secuencias de control (si, si no, repeticiones, llamada a funciones, eventos, …), generando un código en un lenguaje de alto nivel (JavaScript entre otros).

blockly-workingblockly-working

El problema venía de la interpretación del resultado de Blockly, lo que queríamos hacer era tanto poder controlar un flujo de aprobación (con o sin bifurcaciones) como simplificar las llamadas al backoffice del cliente.

Para realizar esto, la mejor opción era interpretar este código en servidor, tanto por las implicaciones de seguridad, como por el propio control del flujo de aprobación, sin olvidar que la necesidad de que el código fuera independiente del cliente – caso de aplicaciones nativas desarrolladas en Swift, Kotlin o Java –. Podía haber generado gramáticas complejas en servidor para interpretar el lenguaje de alto nivel (usando ANTLREste enlace se abrirá en una ventana nueva, por ejemplo, cosa que hemos utilizado en otras ocasiones), pero me parecía matar moscas a cañonazos.

La solución pasó por volver a los principios. Si nos preguntamos qué elementos básicos (pero muy básicos) influyen en una actividad de programación sin duda diremos, la codificación y la compilación. Desde ese punto de vista y abstrayéndolo al caso que nos ocupa

compilacioncompilacion

Por tanto lo único que teníamos que hacer era que Blockly hiciera esa compilación, no ya a un lenguaje de alto nivel, ni siquiera a un DSLEste enlace se abrirá en una ventana nueva que hubiéramos definido con una gramática concreta, sino directamente a un pseudo-ensamblador que pudiéramos implementar en una máquina de pila construida ad-hoc. Así pues el primer paso fue incluir un nuevo generador de código en Blockly para generar un código como el que podéis ver en la siguiente figura.

flujoflujo

Para los que no lo tengáis tan fresco, ese ensamblador no es sino una serie de instrucciones básicas a ejecutar que son interpretadas por una maquina virtual, que en este caso vamos a crear nosotros. Esas instrucciones pueden incluir desde guarda esta variable, compara el resultado con cero, si el resultado es cierto salta a la instrucción 35, etc. Como podéis ver estas instrucciones no sólo incluyen pasos o secuencias, sino también permiten almacenar el estado del programa en memoria en un momento determinado. La memoria es, en este caso, una pila, puesto que toda la operación de guardar y/o leer datos se realiza mediante un algoritmo LIFOEste enlace se abrirá en una ventana nueva.

flujo-explicadoflujo-explicado

El uso de esta maquina de pila no sólo facilita la interpretación del código en servidor, sino que también permite cumplir con otro requisito que teníamos desde el principio y que era el de permitir que la aplicación fuera robusta frente a fallos o caídas del servicio y que permitiera montar esos procesos de aprobación. Tened en cuenta que un proceso de aprobación se caracteriza por:

  • Debemos notificar al usuario que va a aprobar la solicitud.
  • Solo ese usuario puede realizar dicha aprobación
  • Y, muy importante, hasta que no se apruebe el proceso debería quedar suspendido.

Como no íbamos a hacer la barbaridad de tener procesos corriendo en el servidor ad-infinitum - en una escucha pasiva o activa - , la solución pasaba por persistir el estado completo de ejecución del programa: la pila, y la información de donde se encontraba el proceso - la línea de la instrucción - . Así combinamos: la máquina de pila, una máquina de estados finita y una persistencia física de datos. ¡Problema resuelto!

bpm-enginebpm-engine

Si te interesa lo que hacemos no dudes en aplicar a nuestras ofertas de empleoEste enlace se abrirá en una ventana nueva, no vas a hacer siempre estas cosas, pero que sepas que en Divisa iT sabemos como hacerlas y podemos ayudarnos mutuamente para hacer cosas mucho mejores. ¡Animate!

Créditos

Los iconos empleados son cortesía de FlatIconEste enlace se abrirá en una ventana nueva