Big Data Spain 2012: CloudMC

Hola,

Hace un par de semanas estuve en el evento Big Data Spain 2012 presentando un pequeño proyecto que he venido desarrollando en mi tiempo libre en este último año con un par de amiguetes.

Acabo de leer el post de David Salgado sobre “Cuando el software retrasa la investigación” y no puede venir más en la línea. Coincido mucho en todas sus apreciaciones. Yo también no paro de sorprenderme cuando mi curiosidad me lleva a sacarle a mis amigos todos los entresijos de sus trabajos, y veo como el software con el que tienen que lidiar les lastra una y otra vez. Y que muy pocas de las mejoras en nuestro terreno permean realmente en otras áreas y, cuando lo hacen, es con muchos años de retraso.

En este caso concreto, un buen amigo, radiofísico de profesión, me comentó sus malas experiencias ejecutando simulaciones de MonteCarlo para resolver problemas de transporte de radiación. Y el resultado podéis verlo en el vídeo de la charla…

 

[Video] Modeling and Code Generation on the .Net platform

Hola!

Acaban de publicar en InfoQ el vídeo de la presentación que hice, junto con mi compañero Pedro J. Molina, en el Code Generation 2012, un evento que se celebra todos los años en Cambridge en el que se reúnen las principales empresas interesadas en el Model-Driven Software Development.

En nuestra presentación mostramos cómo usamos la plataforma .Net en Icinetic para construir herramientas de modelado y generación de código. Básicamente hicimos un recorrido sobre los aspectos a considerar a la hora de emprender el desarrollo de este tipo de herramientas, y revisamos los frameworks y utilidades que tenemos disponible en .Net sobre los que podemos apoyarnos para no hacerlo todo desde cero.

Para finalizar mostramos un par de demos de nuestra implementación específica de MDSD (Radarc), generando dos pequeños ejemplos de aplicaciones basadas en NServiceBus y WP7, respectivamente.

 

Code Generation 2012

[VSX] DTE How-to’s reunidos (I)

Hola! Siguiendo la estela del gran Carlos Quintero, con su auténtica enciclopedia online sobre Visual Studio Extensibility (que tantas horas nos ha ahorrado a algunos), intentaré ir documentando algunas de la operaciones de VSX más “tricky”.

 

How-To: “Add Item As Link” programmatically

 

La operación sobre Visual Studio consiste simplemente en seleccionar “Add” –> “Existing Item” sobre el elemento al que queremos agregar el link:

image

A continuación buscamos el archivo que queremos agregar como link y seleccionamos “Add As Link” en el selector del botón “Add”:

image

Y listo.

Pues bien, para hacer esto “programmatically” desde un package o una macro de VS, primero tenemos que obtener el “Project” o “ProjectItem” que albergará dicho link. Sobre cómo recorrer la estructura de proyectos y archivos de una solución hay documentación extensa, por ejemplo podemos consultar el siguiente recurso. Ambas interfaces, “Project” y “ProjectItem”, nos proporcionan una propiedad “ProjectItems” que representa la colección de sus elementos hijos en dicho árbol de soluciones. Sobre la colección “ProjectItems” podemos usar el método “AddFromFile”:

hostProjectOrProjectItem.ProjectItems.AddFromFile(realPathOfTheLinkedFile);

Si el elemento está en la ruta correspondiente al “Project” o “ProjectItem” sobre el que estamos ejecutando el método, se agregará el archivo sobre Visual Studio normalmente. Si las rutas no coinciden, el elemento será agregado como un link.

 

How-To: Obtener el path de un archivo alojado en una carpeta de soluciones

 

En la mayoría de los casos si tenemos un “ProjectItem” de una solución y accedemos al método “get_FileNames(0)” obtendremos la ruta del fichero al que representa en VS.

Sin embargo, si tenemos un “ProjectItem” cuyo padre es directamente una carpeta de soluciones como en este ejemplo:

 

image

La llamada a get_FileNames(0) provocará una excepción. En este caso concreto tendremos que hacer dicha llamada con index 1: get_FileNames(1)

 

How-To: Crear un ProjectTemplate con links

 

En el caso en que estemos creando plantillas de proyecto o solución que contengan links a rutas relativas, podemos ver como, al ser desplegadas, dichos links quedan rotos:

 

image

 

Simplemente el problema es que apuntan a la ruta desde la que estamos desplegando la plantilla, en lugar de a la nueva ruta donde la nueva solución se ha creado. Para evitar este problema podemos usar el atributo CreateInPlace:

 

image

 

Que nos permitirá que los links se actualicen a la ruta de la nueva solución.

[VS11] Los nuevos VSIX

Hola!

Seguro que muchos estáis ya probando la beta de Visual Studio 11. Yo también estoy sufriendo la atrofia en los conos de mi retina en detrimento de mis bastones, en claro estado de overflow… En el caso de que vayamos a probar los paquetes de extensión para Visual Studio (VSIX) lo primero es descargarnos el SDK de Visual Studio 11 Beta. Una vez instalado podemos seleccionar el tipo de proyecto "Visual Studio Package" bajo la categoría de "Other Project Types" en el menú "New Project":

 

clip_image002

 

Al igual que en Visual Studio 2010, lo primero que nos encontramos es un wizard para configurar el paquete, eligiendo el lenguaje a usar, namespace, proyectos de test, etc. Una vez finalizada esta preconfiguración Visual Studio generará nuestro paquete de extensión y nos mostrará su correspondiente manifiesto:

 

image

 

Podemos comprobar que aunque el estilo del diseñador del manifiesto ha cambiado, así como el namespace de su correspondiente xml, los elementos que se describen son los mismos. Tal como se definía en los paquetes de VS2010

imageimage

 

Se siguen definiendo los metadatos del paquete, las versiones de Visual Studio compatibles, las referencias que requiere el paquete y los artefactos que se van a instalar. En cuanto a esto último, el tipo de contenido instalable con un paquete, sí han habido pequeños cambios:

imageimage

 

Se puede ver que ya no disponemos de los elementos “Custom Extension Type” y “Template Wizard”. El primero de ellos nos permitía crear extensiones VSIX para Visual Studio 2010 que a su vez podían ser extendidas por otras extensiones VSIX. Es decir, con esta opción podíamos crear paquetes VSIX que consumían otros paquetes VSIX, ambos manejados por el mecanismo de extensibilidad de Visual Studio, el Extension Manager. En el caso de las “Template Wizard”, nos permitían personalizar la creación de un nuevo proyecto o solución de Visual Studio a partir de plantillas de proyecto. Es el mecanismo que usa, por ejemplo, el propio proyecto de creación de VS Packages para que el usuario configure a modo de wizard el lenguaje del paquete, su namespace, sus proyectos de test, etc.

 

En escenarios de migración, la teoría dice que el asistente de conversión debería hacer el trabajo por nosotros. Sin embargo, para mí lo más rápido y efectivo ha sido crear un nuevo proyecto de VSIX vacío desde el VS11 y migrar el contenido. Pero claro, ¿qué hacemos si tenemos contenido de tipo “Custom Extension Type” o “Template Wizard”?

 

Bueno, el caso de las “Custom Extension Type”, se trata de un escenario bastante particular que tendremos que resolver de una forma mucho más manual si queremos compatibilizar con VS11. En el caso de usar “Template Wizard”, es mucho más sencillo. Simplemente si teníamos un paquete VSIX que usaba “Template Wizard”, sustituimos el tipo de contenido por “Assembly”, con la referencia al ensamblado donde se encuentra la clase que implementa “Microsoft.VisualStudio.TemplateWizard.IWizard”, y listo, la “Template Wizard” funcionará en VS11.

DSL con diseñador WPF

 

En los últimos años la comunidad NetFxFactory ha venido desarrollando artículos muy influyentes relacionados con las DSL Tools de Microsoft. Han aportado excelentes soluciones en temas como el multidiagrama o el uso de patrones en modelos.

En Septiembre de 2009, publicaron “Provide an improved user experience to your DSL’s” en el que anticipaban una de las principales características  incorporadas en la versión de DSL Tools de 2010: los diseñadores basados en WPF; dando una primera aproximación para Visual Studio 2008. Una vez lanzado Visual Studio 2010 publicaron “Magnify your diagram”, artículo en el que migraban su prototipo de 2008 haciendo uso de todas las características lanzadas en la nueva versión de DSL Tools.  

Como bien dice Pascal Recchia, autor de estos artículos, a pesar de que entre estas nuevas características no se propone ninguna mejora directa sobre los mecanismos de layout de los diseñadores generados (que supone, sin lugar a dudas, un de lde la herramienta) se puede entrever que la estrategia que se quiere seguir para afrontarlos es precisamente el uso de WPF.

En el ejemplo que se propone en dichos artículos se desarrolla un DSL para modelar una red de aeropuertos y vuelos entre aeropuertos.

image

 

 

Un ejemplo bastante simple y “específico del dominio”. Indudablemente de eso se trata. No obstante, si lo que queremos es desarrollar un diseñador basado en WPF algo más completo y genérico, que nos sirva de referencia tanto para crear un diseñador de clases, como para un entidad-relación o un CUIP, la cosa se nos queda algo corta.

Tampoco nos sirve de mucho la plantilla de DSL con diseñador WPF que viene incluida en la instalación de las DSL Tools de VS2010.

 

image

 

En este caso, el diseñador que se genera desde nuestro metamodelo es, en efecto, un formulario WPF… pero bastante discreto:

 

image

 

 

 

Por tanto, para poder empezar a crear DSLs “con sustancia” usando esta prometedora característica, hay que hacerse con un buen ejemplo de diseñadores de diagramas en WPF.

En CodeProject hay una serie de cuatro artículos, con su correspondiente código, que desgranan paso a paso el desarrollo de un diseñador de diagramas basado en WPF. Si descargamos el código de ejemplo podemos ejecutar la aplicación y veremos algo como esto:

 

 

image

 

Nos decidimos a integrar estos ejemplos de CodeProject sobre un pequeño DSL de entidades con atributos generado con las DSL Tools.

A la hora de crearlo seleccionamos la plantilla “Minimal Language”.

 

image

 

 ¿Y por qué no usar la plantilla “Minimal WPF Designer” si lo que queremos es desarrollar un diseñador WPF? Pues porque con la plantilla WPF no se nos permite definir, y por tanto generar, desde el metamodelo, lo relativo al diseñador y al mapeo entre sus elementos y los correspondientes elementos del modelo. Esto merece una explicación un poco más en profundidad.

Como vemos en la siguiente imagen, un metamodelo en DSL Tools está representado por dos partes: Elementos del modelo (Classes and relationships) y Elementos del diagrama (Diagram Elements).

 

image

 

Mientras los primeros definen el dominio: entidades y atributos en nuestro ejemplo, aeropuertos y vuelos en el de NetFxFactory; los segundos definen la representación en un diseñador de cada una de las instancias de los elementos de ese dominio, tanto en forma visual, como en posición, tamaño o Zindex. Los pequeños conectores que relacionan ambas partes marcan el mapeo entre los elementos de las respectivas regiones, es decir, qué elemento de diseñador representa a cada elemento del dominio.

Con la plantilla de diseñador de WPF por defecto, que es la que se usa en el ejemplo de NetFxFactory, la parte de diseñador esta deshabilitada, y no se nos permite mapear elementos de diseñador a elementos de dominio. Esto implica que nuestro modelo sólo mantendrá información sobre los elementos del dominio y no de cómo se representan los mismos en el diseñador. Asimismo el mecanismo de persistencia de esta información de diseñador queda deshabilitada, es decir, no tendremos el archivo “.diagram” en nuestro modelo y, por tanto, no se guardarán, entre otras cosas, las posiciones de los elementos en el diseñador.

Por todas estas cosas utilizamos la plantilla “Minimal Language”  y creamos nuestro DSL de entidades (Podéis ver el metamodelo en la imagen anterior).

A la solución creada le agregamos el proyecto que comentamos de los artículos de CodeProject. En este caso usamos el código que acompaña al artículo 4. Previamente lo convertimos en biblioteca de clases y eliminamos el App.xaml que ya no necesitaremos.

 

image

 

 

En este punto, si ejecutamos la solución actual, obviamente vemos el diseñador generado por defecto, basado en WinForms:

 

 

image

 

Para usar nuestro nuevo diseñador, basado en WPF, tenemos que añadir algo de código “custom”. La responsabilidad del diseñador recae sobre tres objetos: EditorFactory, DocData y DocView (se encuentran en la carpeta GeneratedCode del proyecto DslPackage). El objeto DocView corresponde a la interfaz del diseñador, el DocData contiene la representación en memoria del documento y maneja el guardado y cargado del mismo, mientras el EditorFactory es el encargado de construir objetos de las dos anteriores clases.

En este caso creamos una clase parcial del DocView para directamente cambiar la interfaz del diseñador al Designer de WPF.

 

image

 

 

En la clase parcial básicamente sobrescribimos la carga de la vista y su contenido para albergar una instancia del WPF Designer.

        public override object Content

        {

            get

            {

                if (content == null)

                {

                    content = this.CreateControl();

                }

                return content;

            }

        }

 

        protected Wpf::ContentControl WpfViewControl

        {

            get

            {

                if (this.Content != null)

                {

                    return this.Content as Wpf::ContentControl;

                }

                else

                {

                    return null;

                }

            }

        }

            

        protected global::System.Windows.UIElement CreateControl()

        {

            return new DiagramDesigner.Designer();

        }

 

        protected override bool LoadView()

        {

            base.LoadView();

 

            global::System.Diagnostics.Debug.Assert(this.DocData.RootElement != null);

 

            bool returnValue = false;

 

            if (this.DocData.RootElement != null)

            {

                returnValue = true;

                WpfViewControl.DataContext = this.DocData.RootElement;

                SelectionPusher.Add(WpfViewControl);

            }

            return returnValue;

        }

 

 

 

 

Podemos comprobar el resultado si ejecutamos la instancia experimental y observamos el proyecto Debugging. Queda curioso, pero realmente aún no sirve para nada.

 

image

 

 

Para sacarle partido hay que meterse de lleno en el XAML de nuestro Designer y darle un par de vueltas. Pero por esto pasaré a muy alto nivel, que para enseñar XAML ya hay blogs mejores que éste. La base del diseñador la podemos ver en el siguiente esquema:

 

image

 

 

La parte azulada corresponde a la interfaz del diseñador, mientras la parte anaranjada corresponde a la infraestructura generada por las DSL Tools que lo sustenta.

El resultado es un DSL totalmente funcional con un diseñador en WPF y del que, por ejemplo, podemos generar código mediante plantillas T4:

 

 

image

image

 

 

El siguiente paso sería sacar factor común y obtener un conjunto de clases base más un conjunto de plantillas para que, dada una definición de un metamodelo cualquiera en un archivo DslDefinition, obtengamos el correspondiente diseñador basado en WPF automáticamente, tal y como se hace actualmente con los diseñadores basados en WinForms.

Este creo que es el camino en el que se están centrando desde NetFxFactory… estaremos atentos a sus resultados!

DSL + UML = Pragmatic Modeling

 

DSL + UML = Pragmatic Modeling es el título de un artículo de Cameron Skinner, General Manager del Visual Studio Ultimate team, en el
que relata la sintonía que intenta alcanzar Microsoft en cuanto a filosofía de
modelado y lo absurdo de las discusiones UML vs. DSL.

En cuanto a esto, a lo absurdo del tema UML vs. DSL, el mejor que
conozco es uno titulado: “UML or DSL: Which bear is best?”.
En este se relata el gran paso que supone Visual Studio 2010 en la convivencia
entre UML y DSLs en el mundo Microsoft, quedando bien delimitada la estrategia
que a lo largo de tantos artículos nos habían mostrado.

No obstante, pasando al lado más práctico del asunto, hemos
visto ejemplos de cómo generar código desde los modelos UML de modo similar a
como lo hacíamos con los DSLs de DSL Tools, gracias al Visualization and
Modeling Feature Pack, pero no es tan fácil encontrar ejemplos prácticos de
cómo manejar esta convivencia que comentamos entre modelos UML y DSLs.

Un buen ejemplo para experimentar sobre esto me llegó a las
manos gracias a Pedro J. Molina, un experto en modelado y generación de código
que realizó su tesis sobre modelado de interfaces de usuario. Podéis visitar su
página en castellano y en inglés.
Fruto de su investigación desarrolló CUIP (Conceptual User Interfaces
Patterns), un metamodelo para la definición de interfaces de usuario, cuyo
prototipo está implementado con DSL Tools. Dicho prototipo se compone realmente
de dos metamodelos: M8, un metamodelo de entidades de negocio y BizUI, que
define los patrones CUIP. Ambos metamodelos están relacionados, de modo que si
en M8 tenemos Facturas y Clientes, en BizUI podremos definir una interfaz
Population de Facturas, que representará un listado de Facturas, o una interfaz
Service de Clientes, que representará un formulario para dar de alta un
cliente.

Al igual que en la mayoría de estas soluciones, se hace uso
de un DSL similar a los diagramas de clases de UML como base del modelado. Es
el pequeño truco que se usaba para suplir a UML en aplicaciones de modelado en
Visual Studio previas a la incorporación de UML. Incluso una de las plantillas
para generar DSLs en DSL Tools era (y sigue siendo) un diagrama de clases muy
similar al de UML. Sin embargo, con la llegada de Visual Studio 2010, esto
podría empezar a cambiar.

Mi idea inicial con CUIP era sustituir M8 por un diagrama de
clases de UML, con todas las ventajas que esto supondría, y relacionarlo con
BizUI, el DSL de interfaces de usuario por medio del ModelBus. El ModelBus es
otra de las grandes novedades de Visual Studio 2010. Básicamente consiste en
una plataforma que nos permite referenciar elementos de modelo entre diferentes
modelos, independientemente de si corresponden al mismo metamodelo o a metamodelos
diferentes.

Como veremos, si bien ModelBus es realmente útil para
realizar estas labores entre DSLs, cuando intentamos atravesar la frontera y
aventurarnos con los nuevos modelos UML, el tema se nos escapa de las manos.

Vayamos por partes, antes de meternos con UML probaremos el
ModelBus para relacionar elementos de M8 y BizUI. En concreto intentaremos
asignarle a cada UI definida en BizUI una clase de M8.

El proceso se compone de dos partes.

El primero es habilitar el ModelBus en el metamodelo origen de
la relación, en este caso M8. En esta imagen podemos ver dicho metamodelo:

Simplemente botón derecho sobre el diseñador, elegimos el
comando ‘Enable ModelBus’ y seleccionamos la opción de exponer nuestro DSL al
ModelBus.

El resultado será un nuevo proyecto en nuestra solución con
un adaptador para consumir las referencias a cualquier elemento de dicho
metamodelo.

Para poder usar este metamodelo, con sus recién creados adaptadores, instalamos el DSL transformando las plantillas de la solución, generándola y ejecutando el vsix
que obtenemos en el proyecto DslPackage.

El segundo paso consiste en consumir los elementos expuestos
en el ModelBus por el M8.

Para ello, vamos al metamodelo que referenciará a M8, en
este caso BizUI:

 

Para definir las referencias a los elementos de M8 creamos propiedades de tipo
ModelBusReference. En nuestro ejemplo, definimos una propiedad llamada Class
en el elemento InteractionUnit (clase base de las UIs) que hará referencia a la
clase sobre la que está definida dicha interfaz de usuario.

Mediante esta propiedad podremos asignar, por ejemplo, una
clase Factura, creada en un modelo M8, sobre una UI Population creada en BizUI,
mediante el enlace sólido y persistente que nos proporciona ModelBus.

Una vez definidas las referencias instalamos el DSL como
hicimos con M8.

Con ambos metamodelos instalados, procedemos a probar las referencias
creadas en instancias de modelos de M8 y BizUI. Creamos un proyecto de prueba y añadimos
un modelo de cada tipo:

 

A continuación abrimos el M8 y añadimos un par de clases de
prueba:

 

Guardamos el modelo M8 y creamos el modelo de interfaces de
usuario:

 

 

Para definir la propiedad Class de las UIs, por ser de tipo
ModelBusReference, disponemos de un editor especial que nos permite definir
fácilmente el vínculo entre modelos que relacionará las UIs de BizUI y sus correspondientes clases de M8.
Simplemente indicamos el modelo que queremos referenciar, y qué elemento en
concreto dentro de ese modelo.

 

 

En este caso, por ejemplo, hemos definido que
FacturaPopulation del modelo Facturacion.bizui referencia al elemento Factura de Facturacion.m8, así como
ClientePopulation, ClienteInstance y ClienteMasterDetail referencian al
elemento Cliente.

Una vez que tenemos ambos modelos relacionados, podremos
acceder a sus elementos y navegar por las propiedades ModelBusReference de uno
a otro gracias a los adaptadores.

Esto nos facilita un gran número de tareas arduas pero
frecuentes en los proyectos de modelado como validaciones cruzadas entre
metamodelos, definición de modelos multidiagrama o accesos a diferentes modelos
en plantillas de generación de código. (Para esto último necesitamos generar un
adaptador especial para el contexto de las T4, tal como se indica en este
artículo)

Por último volvemos a la cuestión que nos planteábamos
inicialmente… ¿por qué no usar UML en lugar de DSLs “pseudo-UML” como M8?

Pues sí, podemos hacerlo. Simplemente agregamos un proyecto
de modelado a nuestra solución de ejemplo, y le agregamos un diagrama de clases
al que llamamos Facturacion.classdiagram:

 

En Facturacion.classdiagram definimos las clases Factura y
Cliente, al igual que hicimos en M8:

Volvemos a nuestro modelo Facturacion.BizUI y modificamos las
propiedades Class de los elementos UI, para que apunten a las clases de nuestro
nuevo modelo UML. Simplemente volvemos a abrir el editor de ModelBusReference,
y elegimos el elemento de Facturacion.classdiagram que queremos referenciar en
cada caso:

 

 

 

De este modo obtenemos nuestro modelo Facturacion.bizui con
las referencias correspondientes al diagrama de clases de UML
Facturacion.classdiagram:

 

 

Hasta aquí todo fácil. Esto nos permitiría desechar DSLs como M8 que solapan contextos
en los que UML nos da completa expresividad y crear una convivencia “sana” con
DSLs que aporten donde realmente UML no llega, como es el caso de BizUI.

Pero como casi todo en la vida, esto tampoco es perfecto. Si
las referencias entre DSL y DSL mediante el ModelBus y los adaptadores nos
proporcionaban infinidad de ventajas en cuanto a generación de código,
validación de modelos, etc., en el caso de DSL – UML dichas ventajas no están
tan accesibles. El problema viene del hecho de que no podemos generar
adaptadores al ModelBus para modelos UML. Esto nos lo tendría que proporcionar
Microsoft y, por ahora, no tienen planes de hacerlo, como bien nos comentó en
este foro Alan Cameron Wills.
Ojalá cambien de opinión… estaremos expectantes 😀

 

Generando búsquedas mediante el patrón especificación

Como ya comenté en mi anterior post, llevo un tiempo trabajando sobre la arquitectura DDD NLayer, con el objetivo de generar gran parte de los artefactos que la componen a partir de modelos. En la solución de ejemplo ya se adjuntan ciertas plantillas T4 para generar las self-tracking entities y el context de EF. Sin embargo, hay bastante más código «generable» que nos podría servir de soporte y que nos permitiría rápidamente centrarnos en los procesos de negocio realmente complejos. Una de estas partes con posibilidad de ser fácilmente generable es la de las búsquedas basadas en el patrón especificación. Para entender su implementación en DDD NLayer sólo hay que leer el post de su autor Unai.

La piedra angular de dicha implementación se basa en las clases Specification, que contienen los criterios de búsqueda (método SatisfiedBy), junto a los parámetros que se usan en dicha búsqueda. Por ejemplo:

public class BankAccountSearchSpecification
        :Specification<BankAccount>
    {
        string _CustomerName;
        string _BankAccountNumber;

        public BankAccountSearchSpecification(string bankAccountNumber, string customerName)
        {
            _CustomerName = customerName;
            _BankAccountNumber = bankAccountNumber;
        }

        public override System.Linq.Expressions.Expression<Func<BankAccount, bool>> SatisfiedBy()
        {
            Specification<BankAccount> spec = new TrueSpecification<BankAccount>();

            if (!String.IsNullOrEmpty(_BankAccountNumber) &&
                !String.IsNullOrWhiteSpace(_BankAccountNumber))
            {
                spec &= new BankAccountNumberSpecification(_BankAccountNumber);
            }
            if (!String.IsNullOrEmpty(_CustomerName) &&
                !String.IsNullOrWhiteSpace(_CustomerName))
            {
                spec &= new DirectSpecification<BankAccount>(ba => ba.Customer.ContactName.ToLower().Contains(_CustomerName.ToLower()));
            }

            return spec.SatisfiedBy();
        }
    }

Nuestro objetivo es generar una clase Specification por cada entidad, que nos proporcione las búsquedas parametrizadas básicas sobre sus propiedades y relaciones. El problema es que en el caso de entidades con un número alto de propiedades, los constructores de estas clases Specification se llenarían de parámetros. Una primera opción sería usar información del modelo para obtener grupos de propiedades que formen especificaciones autónomas dentro de cada entidad. Así obtendríamos conjuntos de especificaciones como los que encontramos en la solución de DDD NLayer. Por ejemplo, para la entidad Order podemos encontrar OrderDateSpecification, OrderFromCustomerDateRangeSpecification, OrderFromCustomerSpecification u OrderShippingSpecification. Con esta solución ganamos en la ubicuidad del lenguaje que tanto buscamos en DDD, pero no conseguimos nuestro objetivo de definir búsquedas de manera estándar y simple si no poseemos el nivel de expresividad adecuado en nuestros modelos.

Ese era nuestro caso, ya que partíamos de un modelo similar al de Entity Framework o al modelo de clases de UML. Para estos casos podemos introducir un nuevo artefacto por cada entidad al que llamamos SearchValues, y que tiene la única responsabilidad de encapsular los parámetros de búsqueda. De este modo, la clase Specification sólo tiene la responsabilidad de definir los criterios delegando el contenido de los parámetros, como hemos dicho, a la clase SearchValues. En el constructor recibirá un objeto de este tipo y en el método SatisfiedBy decidirá si los parámetros contenidos en ese objeto SearchValues cumplen o no con los criterios definidos.

De modo que para cada entidad, por un lado generamos una clase SearchValues, con una propiedad por cada propiedad de la entidad (strings para tipos string, rangos para decimal, int o datetime, e int para filtrar por claves en relaciones), ademas de otra propiedad de tipo SearchValues para hacer búsquedas por elementos que «no cumplan los criterios de ese otro SearchValues», propiedad a la que llamamos NotInSearch. Y por otro lado generamos una clase Specification que contiene la correspondiente propiedad de tipo SearchValues y define los criterios de búsqueda en el método SatisfiedBy a partir de los valores de esa propiedad. En código queda más claro:

public class BankAccountSearchSpecification
        :Specification<BankAccount>
    {
		public BankAccountSearchValues SearchValues { get; set; }
				
                public BankAccountSearchSpecification(BankAccountSearchValues searchValues)
                { 
			SearchValues=searchValues;
		}

               public override Expression<Func<BankAccount, bool>> SatisfiedBy()
               {
 			Specification<BankAccount> spec = new TrueSpecification<BankAccount>();
				if(SearchValues.CustomerName != string.Empty)
				{
					spec &= new DirectSpecification<BankAccount>(element => element.CustomerName == (SearchValues.CustomerName));
				}
				if(SearchValues.BankAccountNumber != string.Empty)
				{
					spec &= new DirectSpecification<BankAccount>(element => element.BankAccountNumber == (SearchValues.BankAccountNumber));
				}
				if (SearchValues.NotInSearch != null)
                               {
                                       spec &= new NotSpecification<BankAccount>(new BankAccountSearchSpecification(SearchValues.NotInSearch));
                               }  
			
	        return spec.SatisfiedBy();
        }
    }
    public class BankAccountSearchValues
    {	
	public string CustomerName { get; set;	}
	public string BankAccountNumber	{ get; set; }
	public BankAccountSearchValues NotInSearch { get; set; }
    }

Las expresiones que usamos para las búsquedas por propiedades de tipos básicos son triviales. En el código anterior se pueden ver para tipos string por criterio de «igual a». Otros criterios como «contenida en», «menor que», etc. son igualmente triviales, así como el uso de otros tipos como rangos de datetime, int, etc. En cuanto a las relaciones, la cosa se complica un poco cuando intentamos filtrar por extremos con cardinalidad «*» (Many). Por inercia la tendencia es usar una expresion del tipo:

spec &= new DirectSpecification<BankAccount>(element => element.BankTransferFromThis.Contains(SearchValues.BankTransfer));

Sin embargo, nos encontraremos con el error: «No se pudo crear un valor de constante de tipo ‘Namespace.Entities.Oferta’. Sólo se admiten los tipos primitivos (‘como Int32, String y Guid’) en este contexto».

La tendencia entonces cambia a crear el Join con Linq para filtrar por los elementos relacionados. El problema es que implicaría un severo golpe al diseño y la simplicidad de este motor de búsquedas.

La solución óptima que encontramos fue usar Any(), con lo que se obtiene una forma elegante y simple de buscar en este tipo de relaciones, además de ser independiente de si se trata de «One to Many» o «Many to Many». La sentencia quedaría así:

spec &= new DirectSpecification<BankAccount>(element => element.BankTransferFromThis.Any(bt=>bt.BankTransferId==SearchValues.BankTransferId));

Y la sentencia SQL que genera es algo como esto (un poco simplificada):

SELECT * FROM  BankAccount

LEFT OUTER JOIN BankTransfer ON BankTransfer.BankAccountId = BankAccount.BankAccountId

WHERE  EXISTS (SELECT 1 FROM BankTransfer WHERE (BankTransfer.BankAccountId = BankAccount.BankAccountId) AND (BankTransfer.BankAccountId = @p__linq__0)

Una vez que hemos contemplado los casos de cada tipo diferente de propiedad, tanto si es escalar, como si es de navegación, sólo nos queda generar la plantilla que recorra las clases o entidades del modelo y vaya tratando cada uno de los casos comentados. Gracias a las T4, nos resultará fácil y sólo dependerá del metamodelo que estemos usando. En el caso de usar UML podemos seguir aquí una guía de cómo hacerlo, si queremos usar el modelo de EF podemos usar la guía que suponen las plantillas de T4 para STE o POCO, y en el caso de que usemos modelos de DSL Tools simplemente al crear el proyecto de DSL Designer se nos creará un proyecto Debugging con ejemplos de dichas plantillas. No obstante, espero escribir algún ejemplo de estas aproximaciones en próximos posts. 

Algo que creo que deberíamos tener en cuenta (y que siempre se ha de aplicar cuando usamos código generado) es que ni todas las búsquedas se deberían de usar tal como nos la genera la plantilla desde el modelo, ni tampoco, por ello, deberíamos crearlas todas «a mano». Habrá siempre zonas en nuestra aplicación, más o menos amplias, que puedan ser automatizadas. La cuestión es encontrar la frontera correcta y no dejar de tener el control de qué está haciendo nuestro código por mucho que se haya generado automáticamente. Por ejemplo, en soluciones basadas en self-tracking en que no disponemos de lazy loading, el hecho de cargar todas las colecciones (por medio de Include()) de todas las relaciones de nuestras entidades para luego poder usar este tipo de búsquedas ya generadas automáticamente mediante plantillas, nos tiraría abajo el rendimiento de ciertas partes de nuestra aplicación. Ni por ello debemos descartar usar las búsquedas generadas para algunas otras partes de la aplicación, ni tampoco sacrificar al usuario por el hecho de usar ese código generado en todos sitios. De nuevo, como en muchas otras cosas, es cuestión de sensatez y ponderación…

 

VSX, RAD & Cloud

 

Aquí comienzo mi camino en este blog, agradeciendo en primer
lugar a Plain Concepts y en especial a Rodrigo Corral, por esta oportunidad de
expresión en esta gran plataforma de referencia para buena parte del mundo .Net
en castellano.

 

Sobre qué intentarán aportar mis artículos ya adelanta algo
el título de éste. En primer lugar, intentaré dar una visión un poco más
cercana de cómo aprovechar las múltiples posibilidades que nos brinda Visual
Studio 2010 para ser extendido con nuestros «plugins». La irrupción
de los paquetes VSIX, la adopción de MEF y la explosión de Visual Studio Gallery
como repositorio de extensiones, nos demuestran la fuerte apuesta de Microsoft,
ahora más que nunca, por  lograr que Visual
Studio sea realmente una plataforma de desarrollo fácilmente extensible.

 

Esta primera línea temática navegará sobre otra, un poco más
profunda y que me han inculcado desde que comencé con esto profesionalmente, y
es la de tendencias o metodologías como Software Factories, desarrollo dirigido
por modelos, líneas de productos, generación de código, etc. En definitiva,
exprimir hasta la última gota de productividad de nuestras herramientas de
desarrollo.

 

Soy consciente de que hay mucha corriente en contra. Mucha
gente que prefiere los matices de Software Craftmanship y similares, y que
reusa de cualquier cosa que le impida escribir hasta el último punto y coma de
su código. No obstante, mis ideas no son caprichosas. No son fruto de la
teoría, sino del pragmatismo más extremo. Vivimos de servicios de software en
Andalucía, sin inversores, sin padrinos políticos ni aliados poderosos. Es un
escenario maravilloso para la evolución, y ella es la que nos ha puesto estas
ideas en nuestras cabezas. Claro que nos encantaría poder escribir código como
el que pinta un cuadro, y disfrutar una a una de cada una de nuestras obras y
cuidar cada uno de sus detalles. Pero no podemos. Simplemente es fruto de la pura
supervivencia.

 

Actualmente trabajo en un proyecto que me ilusiona bastante
y del que creo que podré comentar cosas interesantes relacionadas con las
líneas que comento. Se trata del desarrollo de una herramienta en la onda de
Data Dynamics y WCF RIA Services pero que busca rellenar el hueco de semántica,
flexibilidad y extensibilidad que éstas no cubren. El por qué no poder usar los
conceptos de alta productividad de estas herramientas en proyectos que
requieren de bases arquitectónicas mucho más sólidas fue lo que nos empujó a
materializar esta iniciativa.

 

A grandes rasgos, intentamos converger varias tecnologías
Microsoft como plantillas de proyecto para definir arquitecturas, plantillas T4
para definir artefactos, y DSL Tools para definir modelos, para dar lugar a una
plataforma de desarrollo dirigido por modelos siguiendo las líneas que marcaron
Greenfield y Short en su libro Software Factories (http://www.softwarefactories.com/TheBook.html).
Recientemente, y como prueba de fuego, usamos la arquitectura que están
desarrollando César de la Torre y Unai Zorrilla, entre otros, (http://microsoftnlayerapp.codeplex.com/)
basada en la que propone Eric Evans en su libro “Domain Driven Design” (http://domaindrivendesign.org/books).
Si queréis ver algún vídeo de los resultados, sólo tenéis que pedírmelo.

 

Entiendo que quizás pueda chocar un poco la dualidad de
DDD’s: una arquitectura surgida de Domain Driven Design con este tipo de
herramientas más afines al Data Driven Development. Sin embargo, encontramos
varios escenarios en los que la aleación de matices de ambos paradigmas puede
ser satisfactoria.

 

Detectamos, por ejemplo, clientes en estados de baja madurez
tecnológica que, pese a que concentran procesos de negocio relativamente
complejos o cambiantes, no tienen capacidad financiera, o consideran demasiado
costoso y prescindible emprender una solución acorde a sus necesidades. Una
solución que conllevaría, si somos partidarios de Eric Evans, un proceso de
desarrollo inmerso en un lenguaje ubicuo, que resultara en una capa de dominio
que plasme fielmente los procesos del negocio. Todo ello sobre una arquitectura
que permita que el negocio evolucione sin interferencias tecnológicas de ningún
tipo, entre otras cosas. Obviamente todo esto tiene un coste.

 

Normalmente el contraste de intereses entre ambas partes
hace inviable el proyecto. Una solución intermedia que se puede aportar es usar
herramientas de alta productividad  tipo
RAD (como las que antes comenté) para crear un producto intermedio, no
demasiado ambicioso, que pueda despertar el interés tecnológico del cliente, y
con el que pueda medir fielmente el aumento de productividad que le supone con
respecto a, por ejemplo, las herramientas de ofimática. Sin embargo, es
evidente que hay un lado oscuro en este tipo de soluciones.

 

El bajo grado de madurez de este tipo de clientes implica
procesos de negocio muy cambiantes. A su vez, la base arquitectónica del
producto desarrollado con herramientas RAD no es adecuada para entornos con
alto nivel de complejidad  y/o cambio.
Esto hace que, si bien solemos conseguir despertar el interés en el cliente por
desarrollarse tecnológicamente, nos volvemos a enfrentar a un conflicto de
intereses. Conflicto que viene dado porque el cliente no suele asumir los altos
costes de una refactorización completa del producto, desde el nivel
arquitectónico, lo cual resulta imprescindible para mantener el evolutivo junto
al aumento de interés por seguir perfeccionándolo.

 

Es aquí donde creo que una herramienta que ponga unas bases
arquitectónicas sólidas, con los parámetros de alta productividad de las
herramientas RAD puede ser óptima. No obstante, hay otros escenarios que se
encuentran mucho más exhaustivamente estudiados en los que también pueden ser
eficientes estas herramientas, como líneas de productos en dominios verticales, prototipado real
rápido, normalización de desarrollos en factorías, etc.

 

Por último, siguiendo una línea metodológica parecida que además aprovecha las nuevas oportunidades que nos ofrece el Cloud Computing, me
encuentro enfrascado en otro proyecto bastante innovador, sobre el que espero
escribir algún artículo. Se trata de usar la plataforma Windows Azure para aprovechar
su poder de paralelización en la generación de código. De este modo se pueden
construir servidores de generación de modo que el cliente modele en local y use
Azure para generar los artefactos correspondientes, totalmente en paralelo. El
proyecto aún está en fases tempranas de desarrollo, sin embargo, ya hemos
encontrado bastantes temas interesantes que iré relatando a medida que vaya teniendo
tiempo.

 

Y poco más, ya sólo queda ponerse manos a la obra. Al lío!!