[Languages] Mi lenguaje de programación (Parte I – Ideas)

Hace algún tiempo que vengo pensando y me vengo autoconvenciendo de que el nivel de abstracción que normalmente se utiliza en el desarrollo de aplicaciones dirigida por los datos no es el adecuado. Este tema ya lo toqué en otros post sobre Domain Specific Language y sobre Software Factories así le doy una vuelta más de rosca y presento mi lenguaje de programación.

Veamos como se desarrolla un software: Nos llegan los requerimientos de nuestro Program Manager/Team Leader y, después de las reuniones de rutina y una vez que tenemos las ideas y los documentos,  llega la hora de echarle mano al código y entonces comenzamos así:

C# Code
using System.IO;


public class Product
{
   private string productName;

   public string Name
   {
       get {...} 
       set {...} 
   }
}

La pregunta es: puede ser esta la manera más natural de especificar el comportamiento y las cualidades de un componente de catálogo de productos? No estaremos hilando demasiado fino? Es más, me atrevo a preguntar: no debería estar hecho ya por alguien más o es que acaso nadie nunca escribió un producto que trabajase con productos?. Está bien, acepto que para algo así falta mucho, que habria que estandarizar bloques de construcción y un montón de cosas más pero la pregunta inicial sigue en pie. Son los lenguajes de propósito general los adecuados para todos los casos particulares? Claro que no. Aquí es donde entran, entre otras cosas, los DSLs o Lenguajes específicos de un dominio.

A mi humilde entender, no es posible seguir construyendo software como lo venimos haciendo hasta ahora, reescribiendo bloques de código enteros, con un nivel de abstracción bajísimo y todavia muy lejos del lenguaje natural, tiempos largos, costos altos, impedancias de todo tipo (All vs. OOP); lo que resumiendo es calidad pobre. 

Pienso que una alternativa a todo esto es la generación automática de mucho (realmente  mucho) código y en este punto entran los DSL (Domain Specific Language), lenguajes especialmente diseñados para un propósito muy particular como SQL, HTML, UML, COBOL y otros (por favor no piensen en DSL Tools porque no estoy hablando de ellos, o al menos no solo de ellos).  

De repente hoy existen un gran número de lenguajes de propósito general con frameworks, paquetes, componentes, librerias para todo lo imaginable pero con un poder expresivo que no se compara con el de un lenguaje de propósito particular. Por ejemplo, en DBase III+, Clipper y Fox Pro podemos hacer cosas como esta:

USE CLIENTES
DISPLAY FOR CODIGO > 50000 TO PRINT

(imprimir el listado de todos los clientes cuyo campo codigo es mayor a 50.000)

El problema (y la ventaja) con los lenguajes de propósito general es que nos llevan a trabajar a un nivel de detalle que muchas veces es innecesario, al escribir una clase creamos un campo y debemos decidir si es int, float o double y luego crear la propiedad que muchas de las veces es un simple recibir y devolver el valor crudo del campo, innecesario!. Al pensar en una factura, todo el mundo piensa en un papel,  en un documento comercial, en un impuesto, en la agencia federal de ingresos públicos, mientras que los informáticos pensamos en una cabecera y un conjunto (colección, array, etc) de items con productos, un cliente, y un mapeo a la DB. Estamos acostumbrados a pensar en términos de las herramientas que utilizamos!

Como deberíamos codificar una factura? se me ocurre que de una manera algo mágica considerando «el estado actual del arte» podriamos declararla así:

XN Code
package Business 
{ 
    entity Factura persistent
    { 
        field readonly auto id ID;
        field options ('A' | 'B' | 'C') type; 
        field date operationDate;
        field numeric total;
        field numeric discount;
        field ref(Customer) customer;

        entity Item *
        {
             field numeric count;
             field numeric unitPrice;
             field numeric total;
             field ref(Product) product;

             init: count = 1;
             invariant: count > 0;
             invariant: unitPrice >= 0;
             invariant: total >= 0;
             let: total = count * unitPrice; 
        }

        init: operationDate = DateTime.Now;
        invariant: discount >= 0 and discount <= 100;
        invariant: Item.Length > 0;
        let: total = Item:{item| t+=item.total, return t; } * (100-discount)/100;
    } 
}

Este no es un pseudo código sino la visión de un lenguaje declarativos que estoy comenzando a definir. Como puede apreciarse, este es un lenguaje sencillo de un gran poder expresivo y que sirve principalmente para declarar la metadata para una posterior fase de compilación que generará código y sí, este es un lenguaje orientado a entidades o simplemente un DSL para el desarrollo de entidades de negocio. Este lenguaje mezcla el concepto de entidad con expresiones similares a OCL para la especificación de invariantes y otros constraints.

Alguna ideas sobre el lenguaje XN

  • Los generadores de código se nutren de medadatos para hacer su trabajo, por lo general, estos metadatos son los de las bases de datos, es decir, se genera código a partir de la estructura de una base de datos. Cuando se necesita reestructurar el sistema se debe modificar la estructura de la base de datos  y generar todo de nuevo perdiendo así parte de la lógica de negocios más elemental como los invariantes, los cálculos sencillos, las inicializaciones y los constraints. Todo esto no parece muy natural.
  • Las entidades se componen de otras entidades utilizando composición. Esto es, la entidad contenedora controla el ciclo de vida de la entidad contenida tanto en memoria como a nivel de base de datos. Cuando una entidad se elimina, todas las entidades contenidas por esta también se eliminan. Cuando una entidad se va a salvar en la base de datos, se inician transacciones para salvar también a las entidades contenidas, en otras palabras, una entidad es una unidad atómica.
    Solo se puede acceder a una entidad contenida a traves de su entidad contenedora.
  • La persistencia en la base de datos debe ser transparente al desarrollador. Parece una locura y puedo estar de acuerdo con todos aquellos que piensan distinto y que saben argumentar bien sus puntos de vista pero es hora de buscar una solución radical al problema y yo creo que esta es una opción: generar la base de datos junto con el código. Esta alternativa presentará problemas para extender las aplicaciones pero es muy factible generar automaticamente los scripts de migración ante un gran cambio en las entidades.
  • La estrategia de carga de las entidades debe ser inteligente. Ante la pregunta, Lazy load o no? cada cual tiene una respuesta como: «ver cada caso y estudiar en que puntos conviene y en cuales no», «yo nunca uso lazy load, cuando me hace falta algo lo cargo», «es muy bueno tener el modelo de objetos completo en memoria», «el muy lento, incrementa el tráfico en la red y casi siempre trae cosas que no vamos a necesitar», etc. Pienso que el sistema debería llevar estadísitcas de las consultas y actuar en concecuencia de manera inteligente y liberar al desarrollador para que piense en los requerimientos reales. 
  • No me agradan las siguientes cosas: ORMs, código legacy, One-off development, aplicaciones de negocios en lenguaje C, migraciones de aplicaciones, ni XML for all. Por otro lado, pocos desarrolladores son a su vez DBAs, expertos en .Net, Java, Python y PHP.
    Con un lenguaje declarativo como XN que genere código a partir de templates e integradas a entornos como VS2008 es posible mitigar algunas de estas limitaciones de gustos y/oo experiencias. 

Escribiré más sobre esto apenas tenga algo de código.

Lucas Ontivero