En Xatkit  seguimos con nuestra búsqueda del mejor lenguaje para definir chatbots. Desde el principio decidimos que no queríamos forzar a la gente a crear su bot programando directamente en Java (o Javascript o lo que sea) si no proporcionarles un lenguaje de más alto nivel, con un vocabulario y semántica más cercana al mundo de los bots. Queremos, por ejemplo, que la gente pueda utilitzar directamente conceptos como intent o training sentence en lugar de tener que hablar solamente de Strings.

Esto es lo que se llama un Lenguaje Específico de Dominio (Domain-specific language o DSL, en inglés). En nuestro caso el dominio era el dominio de los chatbots. Y el lenguaje que definimos (nuestro Chatbot DSL) tenía esta pinta. Las ventajas de un DSL son obvias: menos errores y más productividad al ofrecer a los usuarios un lenguaje que utiliza conceptos más próximos a su trabajo diario.

Pero definir tu propio DSL no sale gratis. De hecho, tiene un coste a nivel de infrastructura muy elevado. Hay que definir la gramática del lenguaje, el parser que lo interprete, el generador que convierta ese lenguaje a algún otro que sea ejecutable, crear un editor que permita crear programas con ese lenguaje (y que tenga las funcionalides que, hoy en día, ya todo programador espera como el “autocomplete”, aunque no sea inteligente). Hay herramientas que te ayudan en todos estos pasos, los llamados Language Workbenches. El que usábamos nosotros es/era Xtext. Pero a pesar de toda esta ayuda, gestionar un DSL sigue siendo mucho más complicado (gestión de dependencias, utilización de librerías externas, tener que obligar a la gente a utilizar un editor concreto, en nuestro caso Eclipse,…) que utilizar un lenguaje general como Java.

¿Cómo combinar las ventajas de un lenguaje específico de dominio con la potencia de un lenguaje general como Java?. ¿La respuesta? Las interfaces fluidas. Click To Tweet

La solución para conseguir todas las ventajas de un DSL sin renunciar a la comodidad de usar un lenguaje de programación “estándar” son los DSL internosA diferencia de un DSL separado (“externo”) que se utiliza de forma independiente, un DSL interno se “incrusta” en un otro lenguaje que actúa de “host”. Normalmente, un DSL interno se implementa como una API/Interfaz Fluida (Fluent Interface en inglés).

De esta forma, programar con el DSL (programar chatbots en nuestro ejemplo) consiste en una serie de llamadas a la API del DSL. Utilizar una API Fluida permite que esta secuencia de llamadas se pueda encadenar de forma que la programación se parezca a la experiencia de utilizar un DSL externo manteniendo las ventajas de:

  • No tener que aprender un nuevo lenguaje, simplemente usar Java (o el lenguaje que sea dependiendo de donde alojéis vuestro DSL interno)
  • No tener limitaciones en las herramientas a utilizar. Cualquier IDE para Java se puede usar inmediatamente y con el mismo resultado.
  • Te puedes beneficiar de todas las herramientas que ya existen para Java al programar con el DSL (por ejemplo depuradores, profilers, frameworks de testing,…).
  • Posibilidad de usar todo el poder de Java (y cualquier librería Java que encuentres) si para casos complejos la API del DSL se te queda corta.

Todo esto al tiempo que sigues controlando la semántica de tu DSL y el nivel de abstracción deseado que permita a los usuarios escribir sus bots a más alto nivel.

Evidentemente, un aspecto clave es la calidad del diseño de la Interfaz Fluida. Como hemos comentado antes, se suele basar mucho en la técnica de method chaining  para eliminar variables intermedias y mejorar la legibilidad y abstracción del código intentando, en lo posible, ocular aspectos propios del lenguaje host. 

Para que veáis mejor el aspecto de una interfaz fluida, os pongo un par de ejemplos de la que hemos diseñado para Xatkit. Veamos como la utilizamos para definir un bot que simplemente nos saluda cuando le decimos hola.

  • Antes que nada podemos definir las intenciones que el chatbot debe reconocer al hablar con el usuario y los ejemplos que le damos al chatbot para que consiga identificar lo que le pide el usuario.

  • Después explicitamos qué debe hacer el bot para responder a lo que le estamos contando, utilizando semánticas de maquinas de estado (totalmente innecesaria en este ejemplo pero vital para construir bots “de verdad” que requieren la gestión de conversaciones complejas)

¿Qué os parece? Aunque a simple vista a lo mejor no lo parece, es puro código Java. Pero al mismo tiempo, el diseñador de bots no tiene porque lidiar con toda la complejidad de Java y puede centrarse en la semántica y primitivas de nuestro DSL para poder definir su bot.