Mostrando las entradas con la etiqueta Fowler. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Fowler. Mostrar todas las entradas

viernes, julio 31, 2009

Plugin Pattern II

En la practica cotidiana existen muchas oportunidades en la que se desea extender la funcionalidad de un sistema, tal sea para implementar de otra forma un funcionalidad existente como agregar una que no exista.

Una alternativa de solución

Usando herencia se puede implementar de otra forma una funcionalidad existente respecto a una clase original.

Por ejemplo en un sistema simple de validación de datos de entrada en donde tenemos que validar los campos tipo string, valores requeridos y uno alfanumérico con un formato predefinido, se podría implementar de la siguiente forma




La clase ValidateEngine permite validar todos los datos de entrada, obviamente esta implementación está muy simplificada pues se debería agrega toda la lógica de validación de datos de entrada de un determinado formulario del front end de la aplicación.

Esto trae como problema que se deba implementar lógica para validar tipo de datos, longitud, expresiones regulares (por ej para un ISBN) y valores requeridos, es decir una implementación con una muy baja cohesión.

Una mejora sería que la clase ValidateEngine sea una clase abstracta del cual se deba heredar para implementar cada tipo de validación.


De esta forma tenemos diferentes validaciones implementadas en clases separadas, lo que permite que cada una de ellas tenga alta cohesión.

Para utilizar este modelo podríamos aplicar el patrón estrategia [3] tal como muestra la figura.


Aplicando este patrón tendríamos un sistema más flexible, por ejemplo en C# se podría implementar de la siguiente manera:


http://codepaste.net/ocb7gy

Como resultado de la ejecución de este ejemplo obtenemos la siguiente respuesta



Si deseamos agregar una nueva forma de implementar una validación deberíamos heredar otra clase y configurarla en la clase de contexto.

Esta solución es mucho mejor que utilizar una sola clase para todo pero tiene el gran inconveniente que para agregar nuevas funcionalidades se debe crear una clase heredada lo que hace el sistema poco flexible.

¿Cómo mejoramos está solución?

Supongamos que deseamos crear un sistema en donde se pueda expandir su funcionalidad pero en forma dinámica, configurable y en tiempo de ejecución, la solución mencionada ya no satisface ese requerimiento.

La implementación del patrón Plugin permite agregar funcionalidad a nuestro sistema en forma dinámica utilizando configuración o un estándar de implementación predefinidos. Los módulos que agregan funcionalidad al sistema se denominan plugins.

Ejemplos de la vida real

Este patrón es muy utilizado en múltiples sistemas como sistemas multimedia que permiten agregar en forma muy simple nuevos módulos para edición de audio, transformación entre formatos, skins, analizadores de espectro etc.

En el mundo del desarrollo este patrón se aplica mucho, el más claro ejemplo es el IDE Eclipse,

la arquitectura de este entorno de desarrollo está exclusivamente basada en plugins, pues por si solo no tiene funcionalidad significativa más que proveer un entorno que permite agregarlos [4].

En sus orígenes fue creado como un entorno de desarrollo para Java, pero actualmente se puede usar para muchos otros lenguajes (C++, Python, PHP, Perl, Intel C++ para Linux, Cobol, ABAP , Google apis etc.), también se puede usar para modelado (UML, Base de datos, Data Warehouse etc.), herramientas de soporte al desarrollo como gran cantidad de editores diferentes, clientes Subversion, para soporte de programación en pares distribuida (Distributed XP) , comerciales como herramientas para el BPM de Tibco, generación de interfases para el broker de Software AG etc , al día de la fecha existen más de 1200 plugins publicados.

Visual Studio .Net tiene una api que permite crear plugins (addons), esta api esta implementada en System.Addin. La versión para desarrolladores del Visual Studio Team System posee plugins para revisión de código (basado en el FXCop) para pruebas unitarias, para análisis de performance, cobertura de código, control de fuentes, implementación etc.

Se pueden utilizar plugins comerciales o bien integrarlos al Visual Studio mediante un desarrollo especial.


Veamos una aplicación práctica

En el siguiente ejemplo vamos a extender el sistema de validación para aplicar el patrón Plugin, en este caso se va a utilizar configuración xml y reflection para poder agregar en forma dinámica nuevos mecanismos de validación.

Las nuevas validación estarán implementadas en assemblies separados y usarán el patrón Separate Interfase [5] para implementar la interfase IValidate que está en el assembly Context.

Cada implementación de una validación diferente se implementa en assemblies separados y mediante configuración se agregan como plugin al sistema original.


En este ejemplo usamos el siguiente archivo de configuración.


<ValidatePluginsConfigFile>

<plugins>

<plugin>

<name>ValidateRegularExpresions name>

<fullName>ValidationExample.ValidateRegularExpresions,Version=1.0.0.0,Culture=neutral,

PublicKeyToken=3d10efd7d0a5d829fullName>

<type>ValidationExample.ValidateRegularExpresions.ValidateRegularExpresionstype>

<active>trueactive>

plugin>

<plugin>

<name>ValidateStringsname>

………………………...

plugin>

………………………...

plugins>

ValidatePluginsConfigFile>


Por lo tanto podemos agregar nuevos nodos plugin por cada componente de validación y el programa automáticamente los invocará.

Un poco más de código

En el siguiente fragmento de código se muestra como se puede ejecutar en forma dinámica un método de un assembly externo usando reflection y un poco de lógica para leer la configuración


http://codepaste.net/k9bih8

Considerando que para que funcione correctamente los plugins deben estar en la GAC el resultado de la ejecución de este programa es idéntico al caso anterior.


Código

El código de ejemplo mostrado es parcial , de este link pueden bajar el proyecto completo para probar en sus maquinas, fue creado con el Visual Studio 2005 SP1.

Conclusión

El patrón plugin es muy útil para extender la funcionalidad de un sistema de forma tal que podemos construir una sistema base que permita agregar plugins y luego esos plugins pueden ser construidos por terceros, esta filosofía la usa el IDE Eclipse ya mencionado y también es muy utilizada en el navegador Firefox (Firefox extensions) y el Chrome de Google.

También se usa en sistemas comerciales cuyos plugins requieren el pago de licencias adicionales al sistema principal.

Como desventaja se debe considerar el aumento del complejidad para permitir el agrego de los plugins en forma simple por un usuario que no tiene porque conocer los detalles del sistema principal.

Como en muchos casos para hacer un sistema que permita utilizar este patrón se debe considerar en el diseño original de la arquitectura del mismo.


Bibliografía


[1] Pattern to Enterprise Applications Architecture - Plugin Pattern ,http://martinfowler.com/eaaCatalog/plugin.html


[2] Log4Net Framework , http://logging.apache.org/log4net/index.html


[3] Erich Gamma et at, “Design Patterns: Elements of Reusable Object-Oriented Software” (Addison-Wesley Professional Computing Series) , pag


[4] Eclipse plugin central web site, http://www.eclipseplugincentral.com/


[5] Erich Gamma et at, “Design Patterns: Elements of Reusable Object-Oriented Software” (Addison-Wesley Professional Computing Series) , pag


[6] Pattern to Enterprise Applications Architecture - Separate Interface pattern, http://martinfowler.com/eaaCatalog/separatedInterface.html



martes, julio 21, 2009

Plugin pattern

Como inicio de una seria de articulos sobre patrones empiezo con uno muy relacionado con mi ultimo post,

Patron Plugin.

“Links classes during configuration rather than compilation.” (Fowler, POEAA, p.4990)[1]

El patrón Plugin permite agregar funcionalidad a nuestro sistema en forma dinámica utilizando configuración, por lo general se usan en frameworks que permitan agregar nuevas formas de implementar funcionalidades ya existente, por ejemplo el log4net [2] permite agregar nuevas implementaciones para los adaptadores a los repositorio donde registrar los mensajes de Log (IAdapter) o formato de los mensajes (IFormater).
Otro sistema que usaba el patrón plugin fue el EDRA de P&P, este framework implementaba el patrón Pipes & filters [3] en donde se podían agregar handlers que ejecuten determinada funcionalidad antes de ejecutar una acción personalizada, después o en ambos casos, ejemplo de un handler de “antes” sería un handler de autenticación, de “después” un handler de validación del formato de respuesta y para ambos casos un handlers que agregue información adicional al mensaje de entrada y al de salida a la acción, por ejemplo para medir tiempo transcurrido entre le ejecución de la llamada a la acción y la recepción del mensaje de respuesta.

Otro ejemplo de implementación del patrón plugin es cuando se usa en la implementación del patrón Chain and Responsability [4], básicamente en este patrón participan un conjunto de objetos de comandos y una serie de objetos de procesamiento, mediante configuración se pueden agregar en forma dinámica nuevos objetos de comandos.
Para implementar este patrón el sistema a extender debe disponer de un mecanismo de configuración donde se puedan agregar los nuevos componentes que implementan interfases definidas para determinadas funcionalidades del sistema.
Siguiendo con el ejemplo de log4net el archivo de configuración de la figura se indica el mecanismo que utiliza este Framework para aplicar el patrón plugin.

En este ejemplo se tienen 3 appenders, uno que envía los registro de Log a la consola, el segundo a un archivo que puede llegar a un máximo de 100kb (y luego se genera otro) y un aprender personalizado que envía los logs a otro repositorio no contemplado en la configuración estándar de log4Net (por ej MSMQ o WCF).



Mas info

[1] Pattern to Enterprise Applications Architecture - Pluging Pattern ,http://martinfowler.com/eaaCatalog/plugin.html

[2] Log4Net Framework , http://logging.apache.org/log4net/index.html

[3] Enterprise Integration Patterns – Pipes & Filters , http://www.enterpriseintegrationpatterns.com/PipesAndFilters.html

[4] Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series)