lunes, marzo 20, 2006

Problemas derivados de usar palabras reservadas

Una vez tenemos el DomainModel.dsldm completo y hemos sincronizado el Designer.dsldd (utilizando la herramienta de Modelisoft por ejemplo), llega la hora de pulsar el botoncito de "Transform all templates" , que nos generara el código C# que compilaremos para que se nos cree la libreria de nuestro Lenguaje de Dominio con la que podremos ya empezar a generar nuestro código y nuestras cosas.

Voy a exponer algunos problemas derivados de nuestro modelo de dominio en concreto.

Nuestro proyecto consiste en un Modelo Multidimensional Orientado a Objetos. Se trata de un lenguaje de modelado multidimensional para almacenes de datos. El problema que hemos tenido ha sido por la nomenclatura de nuestras clases. Aqui podeis ver la estructura de nuestro DomainModel.dsldm en la que podemos destacar cosas como la clase "Class" o "Base", cuyas relaciones llamadas "class" y "base" nos van a dar alguna que otra sorpresita desagradable.



Las palabras reservadas, no se pueden usar y eso es algo que todavia al estar en fase beta, las DSL Tools no impiden. Puesto que no se nos ha impedido, hemos podido utilizar nombres de clase como "class", "base", utilizar tipos de datos no definidos,...

  • Problemas de las palabras reservadas "class" y "base":
El primer problema que hemos tenido que solventar ha sido el de compilacion producido por utilizar la palabra reservada "class" en nuestro DomainModel. Esta palabra reservada la hemos utilizado en la relacion entre "Esquema" y "Class". La solucion es tan sencilla como cambiarle el nombre a por ejemplo "classRole".

Identico problema hemos tenido entre las clases "Dimension" y "Base", cuyo rol se llamaba "base" y ha sido reemplazado por baseRole.

Una vez hecho esto , tendremos que sincronizar los cambios del DomainModel, con el Designer y aplicar mas tarde el botoncito de "Transform all templates" para que nos vuelva a generar las plantillas de código y veremos otros errores distintos al compilar la solucion.

  • Error de tipo de datos mal definido:
Ahora veremos que los errores de antes han desaparecido y nos aparecen otros errores. Nos centraremos primero en uno un tanto extraño en el cual podemos ver que la generacion de código ha producido una línea c# no válida. Simplemente hace falta saber dónde ha sido declarada esa propiedad en el DomainModel, para darse cuenta que el error viene dado por no haber declarado correctamente sus tipos.

La propiedad en cuestion que da error al compilar es la siguiente:

private Proyecto.Fincarrera.ObjectOrientedMultidimensionalModel.DomainModel.AssociationType typePropertyStorage = Proyecto.Fincarrera.ObjectOrientedMultidimensionalModel.DomainModel.AssociationType.0;

En ella podemos ver claramente como le intenta poner a la propiedad , como nombre el número "0", lo cual es sintacticamente incorrecto y nos avisa el compilador con un estupendo error. Para arreglarlo, nos vamos a la declaracion en el DomainModel y nos damos cuenta que el error es porque tiene como tipo de datos "AssociationType" y valor por defecto 0. Si sabemos que va a ser un desplegable, pues le ponemos como tipo de datos entero y valor por defecto 0 y arreglado.


Una vez corregido esto, volvemos a transformar todos los templates y a recompilar.

  • Problema del caracter no válido dentro de una enumeracion:

Debido a nuestro Modelo de dominio en concreto, donde uno de los conectores tiene por nombre Rolls-upTo, al generarse los ficheros de código a partir de nuestras plantillas, ha vuelto a surgirnos un error de sintaxis.

public enum AssociationType
{
Rolls-upTo=0,
Completeness=1,
}

Como vemos, ese signo "-" es sintacticamente incorrecto y va a hacer que el compilador nos diga que esperaba un ";". Pues bien ahora hay que ir a detectar donde se ha declarado y cambiarlo. Veremos pues que en este caso se ha generado a partir de uno de los miembros de la enumeracion "AssociationType" de la que antes hablábamos porque tenia otro error y que su solucion vuelve a ser tan simple como eliminar ese signo "-".



Una vez conseguido esto, ya compila nuestro DSL y podemos hechar un primer vistazo al modelo. Claro esta, tendremos que retocarlo mas adelante pero ya tenemos un primer paso conseguido.

miércoles, marzo 15, 2006

Sincronizar DomainModel.dsldm y Designer.dsldd

Cuando escribo estas lineas, estoy utilizando el Visual Studio 2005 SDK CTP Febrero 2006, que trae las DSLTools integradas dentro de el. En esta revision de las DSL Tools existe un gran problema para el desarrollador de lenguajes de dominio, la sincronizacion del Modelo de dominio y del Diseñador grafico.

El modelo de dominio lo definimos graficamente ayudados por la interfaz gráfica que nos proporciona Visual Studio 2005. En el, desarrollamos restricciones de cardinalidad, herencias entre clases, agregaciones, conectores,...para definir nuestro Modelo de Dominio. Esta definicion gráfica, se nos genera un fichero denominado DomainModel.dsldm dentro del proyecto DomainModel. Hasta aqui todo correcto, el problema viene luego a la hora de sincronizarnos con el diseñador gráfico, que es el que van a usar los "modeladores" o personas que usaran el Lenguaje de Dominio específico que hemos creado para ellos. En esta version de Febrero de las DSL Tools no se incluye ningun tipo de diseñador gráfico para el fichero Designer.dsldd por lo que te toca editar cientos de lineas XML formateado para especificar las dependencias, formas de figuras,...es decir un lio tremendo.

Para esta tarea, de forma no oficial, la empresa ModeliSoft ha creado un programa externo que se encarga de procesar el fichero DomainModel.dsldm y permitirnos en funcion de el, que sincronicemos nuestro diseñador gráfico. Es de muy agradecer esta herramienta porque como veremos, aunque no es facil utilizar las DSL Tools en esta etapa temprana, con esta herramienta, una de las mayores pegas con las que nos podemos encontrar ahora se disipan, la sincronizacion dsldm y dsldd.

Mi intencion en este post no es hacer un tutorial de uso de la herramienta , puesto que se encuentra en la misma web antes mencionada, sino exponer los problemas con los que nos estamos encontrando al utilizarla.

El primer problema que nos encontramos es que si hacemos el DomainModel.dsldm directamente y una vez hecho abrimos la aplicacion Dsldm2Dd.exe y cargamos el archivo Designer.dsldd de nuestro proyecto, vamos a ver un terrorifico error que nos va a hacer creer que no podemos utilizar la herramienta teniendo que programar a mano el XML. Nada mas lejos de la realidad puesto que veremos como con unos sencillos cambios arreglaremos esta situacion.

Si al abrir la herramienta Dsldm2Dd.exe y cargar la configuracion de nuestro Designer.dsldd nos da un error del JIT de .NET o que no es posible realizar la carga porque parece que el archivo que intenta cargar no es un archivo dsldd válido, es porque la clase raiz, es decir, la que le dice la superficie en la que pintar (el esquema propiamente dicho donde vamos a dibujar nuestro modelo) ha cambiado y no hay relacion ninguna entre el DomainModel.dsldm y el Designer.dsldd. Para saltarnos este error y poder comenzar a trabajar con la herramienta, lo que debemos hacer es abrir el fichero Designer.dsldd y reemplazar la cadena "ExampleModel" por la cadena que identifique la clase raiz de nuestro modelo; en nuestro caso "Esquema". Una vez hecho eso y guardado veremos como ahora si que nos funcionará la herramienta y ya podremos continuar usándola.

Por ejemplo, una ocurrencia que tendriamos que cambiar seria esta:
<>
<>
<>
<>
....DomainModel.ObjectOrientedMultidimensionalModel/ExampleModel
< /class>
< /childCollections>
...
Cambiaríamos "ExampleModel" por "Esquema".

Esto es debido a que cuando comenzamos la creacion de nuestro modelo de dominio, lo que hacemos es comenzar desde un "lenguaje mínimo", y este lenguaje mínimo si que viene ya sincronizado en las plantillas dsldm y dsldd pero cuando editamos el dsldm, el dsldd no se modifica y por eso tenemos que darle una ayudita a la herramienta de Modelisoft, para que empiece sabiendo por lo menos el punto de partida o nombre del esquema.


Aqui podemos ver los dos archivos mencionados: DomainModel.dsldm y Designer.dsldd

Crear funciones para el parser

Tambien llamados "ClassFeatures", con su sintaxis <#+ ClassFeature #>, nos permiten definirnos funciones para que se ejecuten en el parser antes de generar el código y podamos hacer cambios en el mismo.

Un tipico ejemplo es el de el nombre de una tabla de sql. Obviando características especiales de SQL Server como poner los nombres entre corchetes; si hacemos "create table Tabla 3", nos dara un error porque no sabe que el nombre de la tabla tiene un espacio. Pues bien, podemos hacer para que o bien nos genere los corchetes ( quedando "create table [Tabla 3]") o que nos quite el/los espacio/s en blanco (quedando "create Table Tabla3").

Optando por la segunda forma porque de paso veremos como utilizar la directiva import y el uso de clases externas, lo que habria que hacer es lo siguiente:

  • 1) Importar el namespace System.Text.RegularExpressions
Esto se hace añadiendo al principio del template la siguiente directiva:
<#@ import namespace = "System.Text.RegularExpressions" #>
  • 2) Definirnos en cualquier parte la ClassFeature siguiente:

<#+
private string FixWhiteSpaces(string typeName)
{
//Usa el namespace System.Text.RegularExpressions importado antes
string checkName = Regex.Replace(typeName," ","");
return(checkName.ToString());
}
#>

  • 3) Ahora solo falta usarlo, y se usa como cualquier funcion, pero desde dentro de un bloque de sentencias <#...#>. Por ejemplo, este código es válido.

<# foreach(Table table in this.Schema.tables) { //Como vemos, cojemos el nombre de la tabla del diagrama
string nombreTabla = table.Name;
// Si el nombre de la columna contiene espacios en blanco, se los quito
nombreTabla = FixWhiteSpaces(nombreTabla);
#>

Create Table <#=nombreTabla#>
(
)

<# //Cierro el bucle foreach } #>


Esto creara ficheros como el siguiente:


Create Table Tabla1
(
)
Create Table NiNombreTabla
(
)

Para ello, los nombres de las tablas podian haberse puesto en el diagrama como " Ni NombreTa b l a", puesto que con la funcion de antes , se eliminan los espacios en blanco.

Comentarios en los Templates

Para poner comentarios dentro de las plantillas de generacion de código, es tan simple como recordar que las Sentencias <#...#> son para delimitar código compilado en .net y por tanto si creamos una directiva en la cual lo unico que tenemos es un comentario, esta no se vera representada en el fichero generado.

Aqui tenemos un ejemplo de comentario.

<# // Soy un comentario y no voy a verme reflejado en el fichero de salida
#>

El problema viene porque al estar en un estado temprano, el parser de DSLTools tiene problemas con los comentarios y cree que hay Sentencias donde no las hay.

Por ejemplo:
<# /* Esto lo he comentado porque no consigo depurarlo
<#@ template debug="true" #>
<#@ import namespace="System.Diagnostics" #>
*/
#>
Aunque es sintacticamente correcto, nos da error el compilador porque el parser del template se lia con los #> y cree que hemos cerrado la Sentencia cuando realmente tendria que pasar de largo porque esta dentro de un comentario. Esto hace que lo que le de al compilador de .net sea un código no valido y por eso nos saca warnings y errores.

La solucion es obvia, para salir del paso le podemos decir que son caracteres especiales; al estar dentro de un comentario no hara nada.

<# /* Esto lo he comentado porque no consigo depurarlo
<\#@ template debug="true" \#>
<\#@ import namespace="System.Diagnostics" \#>
*/
#>

Caracteres especiales en generacion de codigo

Bueno a partir de ahora voy a hablar de Templates de generacion de código y para abreviar mas aun, de Templates. De esta forma vamos a ver que para que en nuestros templates de generacion de código se nos generen caracteres especiales como las comillas " o el signo menor que "<" (por ejemplo), hemos de hacer tal y como haciamos al programar en C/C++. Es decir con el caracter especial "\". De esta forma, podremos hacer lo siguiente: <# string texto = "\"Texto entre comillas"\" #>
<#= texto #>

Con lo que se nos generara: "Texto entre comillas" (con comillas incluidas)