DSL. Domain Specific Languaje.

image

Qué son exactamente los DSL y qué posibilidades nos ofrecen?

 

En su definición más generalista, un DSL [Domain-Specific Programming Languaje] o "Lenguaje de Programación de Dominio Específico" es un lenguaje diseñado para realizar tareas específicas para un dominio concreto; es decir, a diferencia de un lenguaje de uso general, como C# o VB, un DSL permite abstraerse a una tipo de problema concreto, como puede ser, ejecutar procedimientos almacenados.

 

Si lo que queremos es ejecutar procedimientos almacenados, un lenguaje generalista como VB, C o C#, permitiría realizarlo sin problemas, pero un lenguaje diseñado específicamente para esta actividad, debería hacer el trabajo más fácil. Un DSL, por ser un lenguaje específico, dejaría de lado las funciones que no son necesarias y se centraría sólo en lo importante para realizar dicha actividad.

 

  image

Un DSL debe permitir definir las entidades del dominio, que serían las piezas del puzle con las que el programador especificará los detalles concretos del problema.

 

Un DSL para ejecutar procedimientos almacenados podrían tener los siguientes elementos de dominio: Base de Datos, Procedimiento Almacenado, Esquema, Paquete, Parámetro, Cursor de Salida, Campo, etc., etc..

 

El lenguaje nos debería permitir definir las propiedades y la interrelación entre estos elementos de dominio, y con esa información, permitir realizar la operación deseada.

 

 

image

Un DSL no tiene porqué ser un lenguaje de programación escrito, que haya que teclear. Puede ser gráfico, permitiendo definir las relaciones entre sus elementos mediante un lenguaje Visual.

 

 

Ejemplos de Lenguajes Específicos pueden ser: Logo para niños, Verilog y VHSIC, R y S para estadísticas, Mata para programación matricial, Mathematica y Maxima para matemáticas, fórmulas de hojas de cálculo y macros, SQL para consultas a bases de datos relacionales, Yacc para crear parseadores, expresiones regulares para crear análisis léxico, Generic Eclipse Modeling System y DGML de Visual Studio para crear lenguajes con el objetivo de diagramar, Csound un lenguaje para síntesis digital, y los lenguajes de entrada de GraphViz y GrGen, paquetes de software usados para graficar y reescribir gráficas. También podrían serlo Alice, un lenguaje para la programación de mundos virtuales y ANTLR, que permite definir compiladores.

 

 

image

 

Pasando un poco de las definiciones más generalistas, vamos a ver qué son las DSL dentro de Visual Studio.

 
Dentro del SDK de Visual Studio (a partir de la versión 2005), se encuentran las DSL Tools, que permiten la definición de los elementos de la DSL, la creación de diseñadores gráficos y la generación automática de código usando una notación bastante sencilla, basada en plantillas, que pueden ser escritas en C# o en VB.net.

Está bien, parece interesante, pero cómo se hace esto?

El ejemplo en la siguiente entrega 😉

 

 

 

Fuentes:

http://msdn.microsoft.com/en-us/library/bb126259.aspx

http://msdn.microsoft.com/en-us/vstudio/cc677260.aspx

http://en.wikipedia.org/wiki/Domain-specific_language

http://cuartageneracion.blogspot.com/2005/06/microsoft-y-mda-mdd-domain-specific.html

DSL Con Visual Studio

Dentro del SDK de Visual Studio (a partir de la versión 2005), se encuentran las DSL Tools, que permiten la definición de los elementos de la DSL, la creación de diseñadores gráficos y la generación automática de código usando una notación bastante sencilla, basada en plantillas, que pueden ser escritas en C# o en VB.net.

Está bien, parece interesante, pero cómo se hace esto?

Lo primero, es la instalación del SDK de la versión correspondiente a Visual Studio que tienes instalada.

Para crear un DSL debemos crear un proyecto de tipo Doman-Specific Languaje Designer

image

Al crear la solución, se mostrará un asistente que nos guiará en la creación del proyecto. Existen plantillas, que contienen elementos del dominio y diseñadores predefinidos, en las que podemos basar nuestro DSL. 

Los posteriores pasos del asistente son triviales. Piden información acerca del nombre del proyecto, la compañía, etc.

Para el ejemplo, seleccionaremos la plantilla MinimalLanguaje.

image

image

Finalizado el asistente, se crean en la solución, dos proyectos: Dsl y DslPackage.

image

Dentro de la solución, en el proyecto DSL encontraremos estos elementos:

image

Al archivo DslDefinition, en el que definiremos todas las piezas de nuestro puzle.

El panel DslExplorer, que nos mostrará, de una manera organizada, los elementos, y la lógica que definirá el comportamiento de nuestro Dsl.

El panel DSL Details, que nos informará de algunas propiedades del elemento DSL seleccionado en diseñador DSL.

La Toolbox, en la que encontraremos los elementos que podemos arrastrar al diseñador.

image

Una cosa realmente curiosa, es que la herramienta que estamos utilizando para crear nuestro DSL, es decir el "DSL Designer" de Visual Studio es un DSL, es decir, un lenguaje visual a partir del cual crearemos en un lenguaje no específico, la solución a nuestro problema especifico. Simplemente, impresionante.

image

 

Como siguientes pasos para la demo, realizar las siguientes acciones:

 

Eliminar los elementos: ExampleElement, ExampleShape y ExampleConnector

 

Añadir, desde la Toolbox un image y llamarlo StoredProcedure

 

Añadir otro Named Domain Class y llamarlo Parameter

 

Añadir otro Named Domain Class y llamarlo Resulset

 

Añadir otro Named Domain Class y llamarlo Field

 

 

 

 

 

 

 

image

 

 

A continuación, los siguientes pasos:

 

 

Conectar ExampleModel con StoredProcedure mediante un image

 

Conectar StoredProcedure con Resulset mediante un Embedding RelationShip 

 

Conectar StoredProcedure con Parameter mediante un Embedding RelationShip

Conectar Resulset con Field mediante un Embedding RelationShip

 

 

 

 

 

 

 

 

 image

 

A continuación, más pasos:

 

Añadir un image y llamarlo StoredProcedureCompartmentShape.

Botón derecho sobre Decorators y Add new Text Decorator.

Botón derecho sobre Compartments y Add new Compartment.

Editar las propiedades de Compartment1 y establecer la propiedad Title a “Parameters”.

Conectar StoredProcedure con StoredProcedureCompartmentShape mediante un Diagram Element Map.

 

Añadir un CompartmentShape y llamarlo ResulsetCompartmentShape.

Botón derecho sobre Decorators y Add new Text Decorator.

Botón derecho sobre Compartments y Add new Compartment.

Editar las propiedades de Compartment1 y establecer la propiedad Title a “Fields”.

 

Añadir un image y unirlo mediante un image  con la relación que hay entre StoredProcedure y Resulset, es decir, StoredProcedureHasResulset.

 

 

 

 

 

 

Doble Click en la Línea que une  El StoredProcedureCompartmentShape y el StoredProcedure.

image

En la pestaña DSL Details, seleccionar, la pestaña Decorator Maps y en Decorators, marcar el check TextDecorator1.

En el drop Display Property que aparece más a la derecha, seleccionar la propiedad Name.

 

image

A continuación, cambiar a la pestaña Compartment Maps.

Seleccionar el check Compartment1 y en el TextBox de la derecha “Displayed elements collection path:” escribir:

StoredProcedureHasParameters.Parameters/!Parameter

En el drop “Display property:” seleccionar la propiedad Name.

 

Luego, exactamente lo mismo para la Línea que une  El ResulsetCompartmentShape y el StoredProcedure.

image

image

En la pestaña Compartment Maps, el texto de “Displayed elements collection path:” debe ser:

ResulsetHasFields.Fields/!Field

 

image

 

Finalmente, en el panel DSL Explorer, en el nodo SPDSL (Dsl)EditorToolbox TabsSPDSLTools

Eliminar ExampleElement y ExampleRelationShip

 

 

A continuación, click con el botón derecho sobre SPDSL Add new Element Tool

Editar las propiedades del nuevo nodo:

Class = StoredProcedure

Name = StoredProcedureTool

Toolbox Icon = Seleccionar un icono. (Se pueden agregar más iconos añadiendo imágenes a la carpeta Resources del proyecto en el Solution Explorer)

 

 

 

 

 

 

image

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Nuevamente, en el DSL Explorer, botón derecho sobre SPDSL, Add new Connection Builder.

Luego, botón derecho sobre el nuevo nodo, Add new Connection Builder Directive

image

Seleccionar el nuevo nodo, y en el panel DSL Details…

image

Seleccionar en RelationShip la relación StoredProcedureHasResulset

En Source role directives, seleccionar StoredProcedure y en Target role directives, seleccionar Resulset.

 

Y ya por último, nuevamente en el DSL Explorer…

image

Botón derecho en SPDSL, Add new Connection Tool.

Editar las propiedades del nuevo nodo, y establecer el Connection Builder, el Name y el Tool Box Icon.

Ya ya, guardar todo,  click en el botón Transform All Templates del Solution Explorer y F5

image

 

Si todo ha ido bien, el resultado debe ser este:

image

Y la definición del DSL debe quedar así:

image

 

To be continued.

En la siguiente entrega, intentaré mostrar como agregar propiedades a los elementos del dominio, y hacer que las cajitas del diagrama sean más bonitas. Pero vamos, visto esto, todo lo que viene a continuación es muy sencillo.

 

Decargar el código

SQL DSL

Esta DSL permite generar consultas SQL a partir de la definición de unas tablas y sus relaciones.

La he desarrollado sobre Visual Studio 2005, pero como todo es muy básico, supongo que aplica a versiones posteriores.

image

Este es el aspecto de la DSL

 

 

image

Así es como quedaría la Query generada.

 

 

Los elementos del modelo

Las clases

image image

Representa una Query. Un diagrama puede tener una 0..N Queries.
Permitimos especificar un nombre y una descripción.

 

image image

Representa cada una de las Tablas que tendrá la Consulta.
Tiene la propiedad Alias por si es necesario darle otro nombre a la tabla.
Una Query puede tener 0..N Tablas

 

image  image

Representa cada uno de los campos de una Tabla.
Cada tabla puede tener 0..N Campos.
La propiedad Name y Alias permite referenciar el nombre del campo.
La propiedad Select indica si el campo debe aparecer en la cláusula SELECT de la Query. Si es false, se utilizará sólo para especificar una condición. 
Las condiciones de filtrado de la Query se especificarán en la propiedad FilterValue. En la imagen de ejemplo, se añadirá al WHERE de la SELECT la condición SHIP_COUNTRY=’SPAIN”. La propiedad DataType se utilizará para formatear adecuadamente el valor de la condición.

 

Las Relaciones

image

El modelo sólo podrá tener una Query como elemento primario.

 

image

La Query podrá tener una o varias Tablas.

 

image

y cada Tabla tendrá sus Campos.

 

image image

Por último, las Tablas podrán tener relaciones entre ellas, y en cada relación, deben especificar un campo en cada tabla, mediante el cual se pueden relacionar.

 

Los elementos UI

image image

Es una GeometryShape normal y corriente.

 

image image

Hemos modificado este CompartmentShape indicando que tendrá un Custom Parent Element, para que mediante código podamos especificarle que su padre será el GeometryShape de la clase Query.

 

image image

El conector tiene un par de Text Decorators para mostrar el Source y el Target Field de cada Tabla.

 

Customizations

Por defecto, en VS 2005 no se permite que un elemento del diagrama tenga como padre a otro elemento que no sea el propio diagrama.
El truco, es indicar en las propiedades del elemento hijo (el TableCompartmentShape en este caso) que vamos a especificar por código cuál será su padre.

image

Y en el código, le decimos que su padre será la clase Query.

image

 

 

Template

En la Template, todo el código es bastante simple. En la mayor parte se trata de recorrer los elementos del diagrama, para ir creando la Query.

 

image 

Recorrer las Queries del Modelo

 

 

 

image

Recorrer las Tablas de cada Query y por cada Tabla, recorrer cada Columna

 

 

 

Quizá lo más complejo es lo de leer las propiedades de la relación.

 image

TableReferencesTargetTables es la clase que representa la relación entre las tablas.

 

 

image

Esta clase expone el método estático GetLinksToSourceTables que devuelve las relaciones en las que la tabla especificada en el parámetro sea Origen, o tenga el rol “source”. Una vez que tengamos esta referencia, podemos leer el valor de las propiedades Source y Target, que son los campos por los que se relacionan las dos tablas.

 

 

Y para qué puede servir todo esto? Pues para además de generar la query, generar por ejemplo los procedimientos almacenados para las operaciones de Alta, Baja, Consulta y Modificación (CRUD), la capa de Acceso a Datos, incluso parte de la Lógica de negocio, Unit Tests, puede que hasta formularios.

 

Adjunto él código