Buscar este blog

Cargando...

miércoles, 27 de mayo de 2015

Registrar un Plug-in en Microsoft Dynamics CRM 2015

Ahora si, llegó el momento prometido. Hemos hecho plugins, hemos llamado a webservices desde los plugins... pero ¡no hemos dicho como registrarlos para poder usarlos! Bueno, ahora mostramos cómo (es muy fácil!)

Igual, quiero aclarar que no pretendo dar información exhaustiva, sino solo la necesaria para probar los plugins que escribimos, y por lo tanto las indicaciones que voy a dar son muy básicas. Para más detalles y profundizar en el registro de plugins en el CRM, favor de remitirse a documentación más precisa.

Lo primero es descargar el SDK del Dynamics, esto se consigue acá. Después de descomprimirlo, vemos que hay una carpeta /tools y allí dentro, una carpeta llamada /PluginRegistration. Allí es dónde está la herramienta que se usa para registrar los plugins.

La abrimos, y vemos que necesitamos conectarnos al Dynamics. Creamos la conexión y entramos. Si, así de simple. Una vez dentro, vemos una pantalla igual -o similar- a ésta:



Daremos click a "Register" y luego "Register New Assembly":




Luego nos aparece una ventana para elegir el ensamblado que queremos agregar. Obviamente, el ensamblado es el de nuestro plugin, el cual ha compilado perfectamente. Seleccionamos la DLL correspondiente a nuestro plugin. Para buscar la DLL, le damos click a los 3 puntitos:


Una vez seleccionado el ensamblado, le damos click a "Register Selected Plugin", y si todo sale bien, aparece un cuadro de diálogo informándonos de dicha situación. Además, el plugin figura ahora en la lista de los plugins y workflows registrados.

Con ésto ya tenemos registrado el plugin, es decir, ya está "adentro" del CRM. Pero no hemos dicho cuándo queremos que se ejecute, por lo que ahora solo nos resta registrar un paso. Desplegamos el elemento de nuestro plugin y hacemos click derecho y "Register New Step":

Aparecerá una ventana así, o similar:


Aca detengámosnos un poco. El campo Message indica el "evento" sobre el cual queremos actuar. En este caso, yo seleccioné el evento de creación de una nueva entidad. Otra opción podría ser "Update", "Delete", etc.
El campo Primary Entity permite especificar la entidad sobre la que vamos a atender el evento de creación. Yo seleccioné "account" por ser una que viene por default. Y finalmente, indiqué que el plug-in se ejecute previamente a la validación (pre-validation) de los datos ingresados. Esto lo hice para evitar que me almacene siempre una nueva account, ya que yo solo quiero probar si funciona el plugin, no andar registrando una nueva cuenta cada vez. Aquí por supuesto elijan la opción más conveniente para su caso.

Finalmente, le damos a "Register New Step" y se registrará el paso. Con esto, ya podemos ir al CRM, y probar de crear una nueva cuenta y ver si el plugin se ejecuta, o no.

Un tip: el campo "Run in User´s Context" indica bajo cuál usuario el plugin se ejecutará. Con la opción "Calling User", con cualquier usuario que intente registrar una cuenta se ejecutará el plugin.

Espero que haya sido útil, y bienvenidos los buenos comentarios y sin spam! ;)

Saludos!

martes, 26 de mayo de 2015

Llamar a un Web Service desde un Plug-in de MS Dynamics

En este post vamos a ver como se hace para que un plug-in que hemos realizado nosotros mismos realice una llamada a un web service (que puede o no ser nuestro). Como siempre, estoy utilizando la versión de Dynamics 2015.
En este caso vamos a utilizar un web service que se pueda encontrar por Internet. Se trata de un conversor de unidades que encontré en la siguiente página:

http://www.webservicex.net/

El servicio en cuestión está en http://www.webservicex.net/ws/WSDetails.aspx?CATID=2&WSID=10, aunque si por algún motivo no se encuentra, no tienen más que buscar el servicio "Currency Convertor" desde la página principal. Ahora, si la página principal no funciona más, mala surte. Eso ya es algo que me trasciende.

Primero: Agregar la referencia al servicio.

Bien, primero lo primero: agregamos la referencia al servicio web haciendo click con el botón izquierdo sobre la carpeta "References" del proyecto, y después en "Add Service Reference".
Cuando se abre la vetana, vemos un cuadro de texto que dice "Adress". Bueno, allí vamos a copiar el WSDL del servicio.

El WSDL es un archivo XML que contiene el contrato del Web Service: qué hace, y con qué lo hace. Así podemos saber qué métodos tiene para ofrecernos, y qué parámetros requieren esos métodos. Ah, y también -lógicamente- que datos devuelven!
Para nosotros, esta URL es la siguiente:

http://www.webservicex.net/CurrencyConvertor.asmx?WSDL

Bien, una vez que ponemos la URL del WSDL del servicio que vamos a usar, le damos a "Go". Aparecerá una lista con los servicios que podemos utilizar. Abajo de la lista, hay una cuadro que dice "Namespace". Allí pondremos el nombre del namespace que "contedrá" el servicio después. Para nuestro caso, podría ser, por ejemplo: "WS_Curr" (que como habéis adivinado viene de "Web Service CURRency" ;)
Le damos aceptar.
Con esto, ya podemos usar los métodos y tipos que provee el web service sin que Visual Studio se enoje y lo subraye con rojo. La variable channel es la que está representando la instancia de nuestro web service.

Segundo: Instanciar el Web Service

Segundo lo segundo: creamos una factory utlizando un Endpoint y un Binding para crear canales de comunicación con el web service. En realidad, nosotros solo vamos a utilizar un canal.

BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Name = "CurrencyConvertorSoap";
myBinding.Security.Mode = BasicHttpSecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

EndpointAddress endPointAddress = new EndpointAddress("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL");
ChannelFactory factory = new ChannelFactory(myBinding, endPointAddress);
CurrencyConvertorSoap channel = factory.CreateChannel();

Tercero (y último): Utilizar el servicio.

Esta es la parte más sencilla de explicar para mi, y entender para ustedes -o para mí si me olvido :)-
Para usarlo, se usa como se usaría cualquier método que está en otro namespace. Si queremos ver a cuantos pesos argentinos está el euro, no tenemos más que llamar al método adecuado, con los parámetros adecuados. Y en la segunda y última linea, mostramos una excepción desde el plug-in para ver si esto funcionó o no. He aquí:

double lalala = channel.ConversionRate(Currency.EUR, Currency.ARS);
throw new InvalidPluginExecutionException("No se si te interesa, pero el EURO está a: " + lalala.ToString());


Al ejecutarse este plug-in en MS Dynamics, deberíamos ver una excepción que mostrara el mensaje con el preciod el euro.
En definitiva, llamar a un web service desde un plug-in en Dynamics es algo extremadamente simple, como pueden ver. A continuación dejo el código completo del ejemplo, y sigue la promesa de en un próximo post mostrar como registrar un plug-in en Ms Dynamics.

using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Plugin_Prueba
{
    public class Class1 : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));            
                                    
            BasicHttpBinding myBinding = new BasicHttpBinding();
            myBinding.Name = "CurrencyConvertorSoap";
            myBinding.Security.Mode = BasicHttpSecurityMode.None;
            myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
            myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

            EndpointAddress endPointAddress = new EndpointAddress("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL");
            ChannelFactory factory = new ChannelFactory(myBinding, endPointAddress);
            CurrencyConvertorSoap channel = factory.CreateChannel();

            double lala = channel.ConversionRate(Currency.EUR, Currency.ARS);
            throw new InvalidPluginExecutionException("No se si te interesa, pero el EURO está a: " + lala.ToString());
        }
    }
}


Saludos y bienvenidos los comentarios con buena onda -y sin spam!-

viernes, 22 de mayo de 2015

Escribir un Plug-In para MS Dynamics CMR 2015

Esta vez vamos  a escribir un poco de código. Hoy quiero mostrar cómo escribir un plug-in para ejecutar desde Microsoft Dynamics. Si bien yo estoy utilizando la version 2015, sirve para algunas anteriores, aunque desconozco exactamente hasta donde se aplica. Próximamente, en otra entrada del blog, voy a mostrar como registrar el plugin en MS Dynamics y asociarlo a algún evento particular.

Bien, la verdad es que crear un plug-in, en términos básicos, es muy, pero muy simple! De hecho vamos a comenzar con lo primero: agregar las referencias necesarias.

1. Primero lo primero.

Obviamente, comenzamos creando un proyecto. Este proyecto será simplemente una librería de clases (Class Library).

2. Agregar las referencias necesarias.

Lo segundo que tenemos que hacer es agregar las siguientes referencias:

  1. System.Runtime.Serialization
  2. System.ServiceModel
  3. Microsoft.Xrm.Sdk.dll
  4. Microsoft.Xrm.Client.dll
  5. Microsoft.Crm.Sdk.Proxy.dll

Las dos primeras se encuentran dentro de los ensamblados del framework. Las tres restantes debemos buscarlas dentro de la carpeta /bin de la carpeta descargada del "Dynamics CRM SDK".

3. Comenzar a escribir el plug-in.

Lo primero que vamos a tener en cuenta, es que la clase del plug-in debe implementar la interfaz IPlugin, el cual nos va a obligar a implementar el método Execute, cuyo código será ejecutado por el motor de ejecución de plug-ins dentro del CRM. En definitiva, tendremos esto:

public class Class1 : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {

        }
    }
Dentro de Execute escribimos nuestro plug-in. Por supuesto, podemos valernos de otras clases y métodos para implementar lo que querramos.

4. Firmar el Plugin

Este paso es escencial, de lo contrario ¡no podremos registrar el Plugin! Igualmente es fácil: Vamos a las propiedades del proyecto (Click izquierdo sobre el nombre del proyecto, y después en properties), y alli buscamos la pestaña "Signing". Checamos "Sign the assembly" y en "Choose a strong name key file" seleccionamos "New". Allí penemos un nombre cualquiera, pero SIN contraseña. Y listo, ya podemos compilar y registrar el plugin.

Trazas para la ejecución.

Bastante común es el caso de utilizar traces para hacer una traza de la ejecución. ¿Y ésto por qué? Porque un plug-in, como podréis imaginaros, es bastante difícil de debuggear. De hecho, la única forma es ejecutando es plug-in desde el CRM y mirando luego la traza de la ejecución. Para esto, creamos el servicio de traza con lo siguiente:

ITracingService tracingService;
tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));


y luego ir escribiendo algo que nos permita seguir la traza. Esto lo haremos llamando a:
tracingService.Trace("Paso 1");


Si intercalamos llamadas a tracingService.Trace("Paso X") dentro de nuestro código, podremos saber hasta dónde se ejecutó el plug-in. Si, por ejemplo falla, veremos que la traza nos muestras el lugar al que llegó antes de lazar la excepción. Acá muestro un ejemplo de traza:
using Microsoft.Xrm.Sdk;
using System;

namespace Plugin_Prueba
{
    public class Class1 : IPlugin
    {

        public void Execute(IServiceProvider serviceProvider)
        {

            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            tracingService.Trace("Paso 1");

            Entity entidad = (Entity)context.InputParameters["Target"];

            tracingService.Trace("Paso 2");

            if (entidad.Attributes.Contains("name") && entidad.Attributes["name"].ToString().Length > 5)
            {
                tracingService.Trace("Paso 3");
                throw new InvalidPluginExecutionException("Epa! El nombre tiene que tener más de 5 caracteres.");
            }
            tracingService.Trace("Paso 4");
        }
    }
}
Entonces, si durante la evaluación de la primera condición del if lanza una excepeción (si por ejemplo, el atributo "name" no existiera), se lanzará una excepción en el CRM y tendremos la opción de ver la traza. En la misma, figurara algo parecido a esto:
Paso 1
Paso 2
Pero no veremos "Paso 3" porque se lanzó la excepción y no se llegó a ejecutar esa parte. En la próxima entrada, veremos como registrar el plug-in para que el CRM lo pueda ejecutar. Es también algo muy sencillo.

Saludos!

miércoles, 31 de diciembre de 2014

¿Cómo testear métodos privados?

A la hora de hacer los unit testing, tarde o temprano nos llega indefectiblemente la pregunta: ¿cómo testeo un método privado?

El asunto en cuestión es motivo de distintos puntos de vista, opiniones, y discusiones. Sin embargo basado un poco en la experiencia personal y la ajena, más un poco de literatura, ofrezco mi punto de vista.

Existen dos opiniones diferentes al respecto: unos dicen que los métodos privados no deben testearse, y otros que si. Ah, y bueno, están los grises que dicen que "depende de la situación". Yo me incluyo en este último grupo. La ingeniería de software es una ciencia muy "gris" todavía.

La curda realidad, es que con muchos de los frameworks no podemos testear métodos privados, por la simple razón de que son privados y no podemos acceder a ellos. (No lo dije antes, pero doy por hecho que los tests se encuentran en un proyecto aparte de aquel que contiene el código que estamos testeando y por eso no podemos accederlos).

Los que dicen que no deben testearse métodos privados, tienen sus razones. Principalmente sostienen que solo debe testearse la interfaz de, pongámosle, una clase. Es decir, todos aquellos métodos públicos que sirven de interfaz al mundo exterior (los programadores que utilizan estos métodos). Y que a su vez, los métodos privados son solo "ayudantes" de los métodos públicos. Estos pueden cambiar con mayor frecuencia que los métodos públicos, y por tanto, una eventual modificación de los métodos privados que no debiera alterar los resultados de los métodos públicos, podría hacer fallar los tests que testean los métodos privados. Es decir que se cambió el comportamiento interno sin alterar el comportamiento externo y que, por lo tanto, solo debemos preocuparnos por testear el comportamiento externo.

Yo no estoy precisamente de acuerdo con este punto de vista. Si queremos testear el método, deberíamos poder. La realidad es que así nomás no se puede. Entonces salen alguna alternativas que voy a mencionar, y me alegraría siempre de escuchar o leer nuevas.

1) Mover los métodos privados a una nueva clase.
Si el/los método/s privados que queremos testear lo ameritan, los refactorizamos creando una -o más- nueva clase que solo los contenga a ellos -pero como métodos públicos- y no formen parte de la interfaz de nuestra clase. De esta forma seguirán estando "ocultos" hacia el mundo exterior (porque no pertenecen a la interfaz), y sin embargo ya podemos accederlos tranquilamente desde el proyecto de testing.

2)  Convertir los métodos privados en públicos.
No soy un gran entusiasta de esta opción. Creo que si un método se pensó privado, privado debe permanecer. Si se cambia a público, la razón debería tener que ver con otras cuestiones y no con el testing. Pero ya dicho, es una opción más.

3) Convertir los métodos en internal.
Desconozco si existe en otros lenguajes el equivalente a internal de C#. Con esto permitimos que las clases dentro del mismo ensamblado se puedan ver. Sin embargo, fuera del ensamblado siguen permaneciendo ocultas. Y debemos especificar a qué ensamblado le damos visibilidad (con [assembly:InternalsVisibleTo("MyTests")]).

Cuando puede utilizarse, soy partidario de la tercera forma, ya que es bastante más limpia. En otro caso, habrá que evaluar qué hacer, o incluso si coincidir con quienes dicen que los métodos privados no tiene estrictamente que testearse.

Hasta pronto!

jueves, 25 de diciembre de 2014

Fakes, Stubs y Mocks... ¿cuál es la diferencia?

Buenas!
Como me viene pasando últimamente, pasan décadas de un posteo a otro. Sin embargo y pese a ello: sigo posteando ;)

El tema de este post surgió nada menos que de darme cuenta que los conceptos que voy a explicar, no estaban adecuadamente explicados en la facultad a la que asistí. Quizás esto ya haya cambiado, pero considero que son términos importantes como para estar mezclándolos cual ensalada de frutas.

Básicamente, donde yo estudié la idea -muy genérica y nada desarrollada- de un Stub nunca se mencionó la diferencia entre Stubs y Mocks, y tampoco la diferencia entre éstos dos con un Fake. Es más, me atrevo a decir que nunca se habló de Fakes y Mocks. Pero bueno, no es el fin de este artículo evaluar ni criticar lo que tuve que estudiar, sino más bien, aclarar los conceptos.

Todo esto viene a colación de la importancia que han tomado los Unit Tests (Tests de Unidad) de los cuales no voy a hablar ahora para no extenderme en el tema. Doy por hecho que ya sabes lo que son.

Pero, ¿por qué es importante? 

Es de suprema importancia realizar UTs que sean legibles, que cualquier persona que nunca los vio antes pueda leerlos y darse cuenta de inmediato qué quiso testear quien lo escribió. Si esto no es así, se pierde la filosofía que está detrás de los UT, que es justamente proporcionar un método muy rápido de testeo. Si un programador tiene que dedicar mucho tiempo a entender un test que ha dado FAIL (o peor aún: muchos tests!) por el solo hecho de que se escribió mal o que es ilegible, el resultado es terriblemente predecible: no lo va a leer y lo va a dejar de lado porque entender y/o arreglar ese test le va a consumir mucho tiempo, y seguramente "tiene cosas más importantes que hacer". Se ignora el test, se lo marca como obsoleto, etc. Y allí comienza la decadencia del sistema. Y de la calidad. Y de la mantenibilidad. Y etc, etc.

Siempre es una necesidad que tengas claro los conceptos referidos a tu especialidad, a lo que te dedicas a hacer.

Antes que nada, esta entrada presupone que ya sabes lo que es un test de unidad, cual es su finalidad, y que significan las tres A (Arrange-Act-Assert). Si no es asi, sería bueno que le googlearas por ahí.

Bien, comencemos entonces:

¿Qué es un Fake?
El verbo "to fake" en inglés es fingir, falsificar. Eso es lo que es un Fake: una falsificación de un objeto. (Hablo de "objetos" por que normalmente en mi blog me refiero a la OO (orientación a objetos) por ser la que más utilizo, pero es aplicable también a otros paradigmas.)

Es decir, es un objeto que es una falsificación de otro. Se ve "igual" pero se comporta distinto.

¿Y para qué sirve?
Porque si queremos realizar pruebas de unidad, es indispensable que estas sean rápidas! Pero no sólo por esto! Sobre todo que el comportamiento de la clase (o unidad de trabajo) que estamos testeando (llamémsole UUT de "Unit Under Test") no se debe ver influenciado por el comportamiento de algún otro objeto del que pueda hacer uso. Si por ejemplo queremos testear el método de una clase que por dentro hace uso de un objeto que se comunica con la base de datos, tenemos dos problemas:

  1. El objeto que utiliza la base de datos (llamemosle "ConexionConBD") hará muy lento el testing, ya que debe conectarse con la mismísima base de datos, entorpeciendo este principio.
  2. Si el objeto "ConexionConBD" falla cuando nosotros esperamos que no falle, entonces fallará también el UUT (nuestra unidad bajo testing)..
  3. Si la mismísima base de datos falla (por la razón que fuere, cualquiera), nuevamente fallará también nuestro UUT.

Y el problema con las fallas que son "ajenas" a nuestro UUT, es que finalmente no vamos a saber si lo que falla es el UUT, o es alguno de los objetos que éste utiliza. Y pierde sentido el concepto de "Test de UNIDAD".

Entonces, para solucionarlo, inventemos un "ConexionConBD" que responda lo que nosotros queramos, cuando nosotros queramos, y como nosotros queramos. Es decir, falsifiquemos esa clase. Para ello, crearemos un Fake de la clase "ConexionConBD", la cual podemos controlar desde el test que estamos escribiendo.

No voy a entrar en detalles técnicos de como se hace, ya mucho en internet sobre como hacerlo.

Entonces....

¿Qué es un Stub?
El Stub, es ni más ni menos, un subtipo de Fake. Si, asi de simple: los Fakes se dividen en dos clases: o son Stubs, o son Mocks. ¿Y de qué depende? De según como se use, de eso depende!

En el caso anterior, podemos utilizar el Fake "ConexionConBD" para que siempre nos devuelva un valor esperado, así no nos encontramos con sorpresas. Una vez que el fake nos devuelve el valor que esperamos, podemos proseguir con el test.

Pero al usar este fake como un Stub, éste sólo puede utilizarse para devolver un valor o arrojar una exepción. Pero nada más. NADA MÁS! Es decir, el test se sigue haciendo directamente contra nuestro UUT.



¿Y qué es un Mock?
En el caso anterior, el fake se utiliza solo para que devuelva un valor esperado, es decir, que realice un comportamiento definido y así poder proseguir con nuestro test.

Pero en otras ocasiones, el test mismo consiste en saber si el UUT se comunicó de forma esperada con otro objeto. Por ejemplo, queremos saber si el UUT llamó al objeto "ConexionConDB" de forma correcta. En este caso, no podemos hacer un assert directamente contra la UUT, ya que la UUT mismo no sabe si la llamada -a un método por ejemplo- fue realizada con éxito. Quién sabe esto, es el objeto llamado en cuestión, es decir, el objeto "ConexionConBD". Pero el "ConexionConBD" original  (aquel que se conecta con la base de datos) no está programado para decirnos si la llamada que le hicieron fue correcta, y encima, se conecta con la base de datos! (algo que queremos evitar!).

Solución: le hacemos un fake. Pero este fake no devuelve un valor, sino que simplemente recibe la llmada que le hace la UUT y, nuestro test, en lugar de hacer un assert contra la UUT, lo hace contra el Fake.



Y esta es la clave: cuándo nuestro test verifica (assert) contra un fake, este fake es un Mock.
Si en cambio la verificación se hace contra la UUT, entonces cualquier fake que haya será un Stub.

Resumiendo.

Todo fake será indefectiblemente un Stub o un Mock dependiendo de cómo se lo utilice. Es más, un fake puede ser Stub en un test, y Mock en otro test. La diferencia está en el uso que se le da a ese fake. Nada más y nada menos.

Según Roy Osherove (The Art Of Unit Testing, un libro que recomiendo totalmente y del cual saqué la idea para las imágenes) cada UT (Unit Test) no debería tener más de un Mock, y sí puede tener más de un Stub. Osherove es partidario de que si un UT tiene más de un Mock, el test pierde legibilidad y se hace más complicado de entender "inmediatamente" qué es lo que se quiere testear.

Espero que haya sido suficientemente claro, ya que es un tema de muchas confusiones por lo que he visto yo.

Hasta pronto, espero!

jueves, 16 de mayo de 2013

Ejemplo: Implementacion del Patron Singleton en C++

Buenas! Si, después de casi dos años de inactividad, volví para mostrar la implementación de un patrón Singleton en C++.

Como sabemos, una clase que implementa este patrón, tiene una característica muy importante: no puede crearse mas que una instancia (objeto) de esa clase. Pero claro, esta caracteristica es relevante o toma importancia en algunos casos. Personalmente, donde mas utilizo este patron es cuando creo "fabricas", es decir, utilizo el patron Factory para con alguna finalidad. El patron Factory lo dejo para otro momento, y es igual de interesante y util que el Singleton pero ahora no viene al caso.

Entonces, lo importante que debemos tener en cuenta, es que sin importar cuantos objetos queramos crear, solo estaremos creando una y solo una instancia de esta clase. Si por ejemplo creamos 5 variables de una clase llamada MiClase e instanciamos dichas variables, todas las variables corresponderán a la misma instancia. Es decir, sera indistinto utilizar una u otra de estas variables para acceder a los métodos y atributos del objeto.

Pero este patron tiene dos puntos que hay que tener en cuenta:

Punto 1. No puede inicializarse "manualmente".
Es decir, no podemos hacer la asignación con new:
MiClase ObjetoA = new MiClase();

Es imposible! Y por que? Porque el constructor debe ser privado. De esta forma nos aseguramos que no se pueda andar creando instancias libre y salvajemente por ahí. Bueno, si no se pueden crear instancias... cómo hacemos para exista esa famosa única instancia?

Punto 2. Alguien debe crear la instancia única.
Y si, nada es magia en esto de la programación. Quien puede crear la instancia? Bueno, pues la misma clase! Es decir, que de alguna manera, la clase debe crear una instancia de si misma y asegurarse que sea solo una. Esto lo haremos con un método que le llamaremos, por convención nomás: getInstance().

Es decir, que para obtener la unica instancia de una clase que implementa el patron Singleton, haremos algo asi:
MiClase ObjetoA = MiClase()::getInstance();

Súper fácil! Y ahora si, ObjetoA apunta directamente a la instancia única de la clase MiClase. Ahora veamos que se esconde detrás de todo esto, en términos de C++. Como toda clase de C++ tendremos los archivos .h y .cpp:

MiClase.h
En este archivo lo importante a tener en cuenta es:
  • El constructor MiClase() es privado. No podrá usarse la palabra clave new.
  • Tenemos un atributo estático llamado unica_instancia que es un puntero a la clase que lo contiene y que tambien es privado. No podra accederse desde fuera de un objeto.
  • El método getInstance() es también estático! Claro, sino no podría accederse hasta tener un objeto de la clase, y justamente este el método que crea el primer (y único) objeto, con lo cual debe ser estático si o si.
class MiClase
{
private:
 MiClase(void);
 static MiClase* unica_instancia;
 
public:
 ~MiClase(void);
 
 static MiClase *getInstance()
 {
  if(unica_instancia == NULL)
   unica_instancia = new MiClase();
   
  return unica_instancia;  
 } 
};


MiClase.cpp
Acá lo importante es inicializar la variable estática unica_instancia. La inicializamos en NULL de forma que nos aseguremos que no se crea ningún objeto hasta que se llame por primera vez a getInstance().
Atención! El caso particular de C++ requiere que las variables estáticas sean definidas en el archivo .CPP y no en el .H. Caso contrario se obtiene un error de compilación.
#include "MiClase.h"

MiClase* MiClase::unica_instancia = NULL;

MiClase::MiClase(void)
{
}
MiClase::~MiClase(void)
{
}

Por ultimo, cabe explicar brevemente lo que hace el método getInstance(). Básicamente, crea una instancia de la clase solo en el caso de que no exista una (por eso el if). Luego devuelve la instancia creada o, sino creó porque ya existia, devuelve la existente. Asi es seguro que no tendremos mas de una instancia.
Saludos!

viernes, 8 de julio de 2011

Error: Clase No Registrada.

Tenía un proyecto en .NET que en una máquina compilaba y corría sin problemas. Pero al querer pasar el proyecto a otra máquina, luego de compilar, me aparecía la siguiente excepción:

Clase no registrada (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

La solución es simple: además de agregar las referencias al proyecto, debemos hacer click derecho (desde un adminsitrador de archivos) en los archivos DLLs que hemos referenciado, y luego click en "Registrar".

Con eso se soluciona el problema.

S2

viernes, 22 de abril de 2011

Programación Orientada a Aspectos. Implementando un Aspecto. (Parte 3)

En la parte 2 planteamos una situación utópica: que una clase realizara algo sin indicarle que lo hiciera. Bueno, sí, eso es utópico. Pero, podemos pensar en otra "entidad" que se encargue de realizar esa tarea (en nuestro caso es registrar un movimiento) detectando el momento preciso en el que debe realizarla. Es decir, tener "algo" que sepa cuando registrar un movimiento, pero que ese "algo" no tenga nada que ver con la clase Cuenta. Ese algo, es lo que llamamos aspecto. Un aspecto, entonces, es algo que entrecruza una o más clases. Dicho de otra forma, un aspecto es un concepto que ofrece funcionalidad transversal a los objetos del negocio.

Imaginémoslo como algo que vigila un programa a medida que este se ejecuta; y a partir de ciertas acciones que se producen en el programa, este algo realiza acciones propias de él. Llamemos a este algo "aspecto". Podemos decirle a un aspecto, que cuando se termine de ejecutar cualquier método que comience con la palabra "hacer" realice un registro de movimiento. La clase Cuenta de nuestro ejemplo, no se enteraría jamás de la existencia de este aspecto, pero este aspecto está atento a las ejecuciones hacerAlgo...() de esa clase.

Vamos a definir rápidamente este aspecto para poder visualizar mejor lo que estamos tratando de decir. Para poder escribir un aspecto y compilar el programa con este aspecto, es necesario tener instalado el plugin de AspectJ en el editor de Java que estemos usando, o poder compilar configurando el editor. Bueno, pasemos a definir el aspecto de una vez. Agregamos un nuevo archivo con extensión .aj (por "AspectJ") al proyecto:

public aspect RegistroDeMovimientos {

after():execution (public * hacer*(..)) {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}


Observemos este código. Lo primero que vemos, es la declaración del aspecto bajo el nombre de RegistroDeMovimientos. Por ende, al igual que las clases de Java, el archivo del aspecto debe llamarse RegistroDeMovimientos.aj. Si seguimos vemos la linea que dice:

after():execution (public * hacer*(..)) {


Esta línea es clave para definir unos conceptos que explicaré más adelante. Pero por el momento, analizaremos de manera simple qué significa. Si tuviera que decirlo en lenguaje informal, la describiría asi: "Después de la ejecución de cualquier método público, sin importar el tipo que retorne, que comience con hacer, y sin importar la cantidad y tipo de parámetros que requiera, hacer lo siguiente:". Eso significaría mas o menos. Ahora examinemos lo que significa cada parte:

  • after(): Esto indica que el cuerpo se ejecutará después de algo. Ahora veamos ese algo.
  • execution ( ): esto significa que se toma como referencia una ejecución de lo que sigue:
  • public * hacer*(..): public nos indica que se buscará un método público cualquiera. El asterisco que sigue, indica que ademas no importa el tipo que retorna el método. hacer* significa que el nombre del método debe comenzar con la palabra "hacer" y no importa cómo termine (para eso está el asterisco luego de "hacer"). Y finalmente, los dos puntos entre paréntesis significa que no importa ni el tipo ni la cantidad de parámetros del método.

Entonces, revisemos la descripción informal del método: "Después dela ejecución de cualquier método que sea público, que retorne cualquier tipo de dato, que comience con "hacer" y sin importar el tipo y cantidad de parámetros", se debe ejecutar lo que se indica en el cuerpo. El cuerpo es muy simple: no es mas que aquello que hacía el método RegistrarMovimiento() que hicimos antes. Esto es un aspecto. Simple, ¿no? El aspecto, se encargará de ejecutar ese cuerpo de código cada vez que ocurra esa descripción informal.

Con esto, hemos solucionado el problema del apartado anterior. ¿Por qué? Porque hemos logrado aislar el comportamiento de registrar un movimiento, de forma tal que la clase Cuenta no conoce de su existencia. Por lo tanto, no hemos tenido que repetir ningún código dentro de la clase, y además, al aislar ese comportamiento en un sólo aspecto, este se hace más fácilmente mantenible, ya que si queremos modificar la forma en que se registran los movimientos sólo debemos modificar el cuerpo de ejecución del aspecto, y no preocuparnos por las clases del negocio.

Por supuesto, para compilar aspectos, no podemos usar el compilador de java, para eso usamos el compilador AspectJ que lo que hace es armar un código complementando el código base con el código de aspectos. Una vez que esta herramienta genera el código final, ahí si se puede correr sobre la máquina virtual de java.

miércoles, 20 de abril de 2011

Programación Orientada a Aspectos. ¿Por qué usar POA? (Parte 2)

En la parte 1, di una introducción a lo que es la programación orientada a aspectos de una forma bastante teórica. En esta segunda parte, voy a mostrar un ejemplo práctico muy simplificado para poder asentar un poco más el concepto. Para el ejemplo utilicé el lenguaje Java, y la extensión del lenguaje Java que implementa aspectos AspectJ. Ya he contado como compilar con AspectJ en NetBeans.

Bueno, ¿en qué consiste la POA? Voy a poner un ejemplo muy fácil que ilustra el potencial que nos ofrece la POA Supongamos una aplicación de transacciones bancarias. (Este es el típico ejemplo que se menciona en todos lados, y lo voy a poner en mi versión porque es muy ilustrativo).

Vamos a tener una clase cuyo nombre es Cuenta y es una versión muy simplificada de una cuenta de un banco. Esta clase, tiene un atributo llamado saldo de tipo Double que indica el saldo en la cuenta. Y vamos a tener tres métodos: Uno que llamado hacerDeposito() con un único parámetro de tipo Double que indica la cantidad a depositar en la cuenta. Otro llamado hacerExtraccion() que cuenta con un solo parámetro que indica la cantidad de dinero que se quiere extraer de la cuenta. El método restante se llama hacerTransferencia() y tiene dos parámetros: uno indica la cantidad de dinero y el otro es la cuenta a la que se quiere hacer la transferencia. Además tendremos una típica -y muy simplificada- clase que representa un cliente del supuesto "banco" llamada Cliente. Para seguir simplificando (cosa que se me está haciendo mala costumbre ya) un cliente sólo puede tener una cuenta. Ilustremos con UML:



A continuación, les muestro un ejemplo en java bien simple. Lo que haré en el método Main() será crear dos clientes (Pepe y Juan) y crear una cuenta para cada uno. Después, le asignaré a Pepe una cuenta y a Juan la otra. Finalmente, haré una extracción de la cuenta de Pepe; y -felizmente para Juan- terminaré con una transferencia de dinero de la cuenta de Pepe a la de Juan. Aunque lo que realiza el método Main(), por el momento no nos interesa. Veamos el código de ambas clases (sin los getter y los setters porque son muy triviales).

Veamos la definición de los métodos hacer...() de la clase Cuenta:

public void hacerDeposito(Double cantidad) {
if(cantidad <= 0) {
System.out.println("No hay dinero suficiente para hacer el depósito");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
//Realizamos el depósito
this.saldo += cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
//Extraemos la cantidad del saldode la cuenta.
this.saldo -= cantidad;
//Registramos el movmiento
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}
}
Examinemos un poco el código: en todos métodos comenzamos con una verificación de la cantidad que se quiere extraer, depositar o transferir. Esta verificación es necesaria, ya que ciertamente sería un error, por ejemplo, depositar una cantidad negativa de dinero de una cuenta; también sería un error permitir una extracción de más cantidad de dinero de la que se dispone. Estas situaciones deben evitarse si o si.

Por otra parte, vemos que una vez que se comprueban las cantidades y que esta todo bien, se procede a realizar el deposito o la extracción o la transferencia (según sea el caso). Pero para esto, he supuesto (a modo de regla de negocio) que el banco necesita tener un registro (logging) de cada movimiento realizado en cada cuenta. Por eso es que creé una variable llamada hora y la mostré en pantalla. Lo más común no es mostrarlo en pantalla sino almacenarlo en un archivo de logs, pero lo hice así por practicidad.

Lo interesante, curioso, y que tenemos que tener en cuenta de estos métodos, es que los tres repiten el proceso de registrar un movimiento. Y no solo eso, sino que además se hace en los tres métodos de la misma forma! Lo cual es una muy mala práctica. Nunca debería repetirse código, eso lo sabemos bien. Entonces, he aquí un problema. ¿Cómo lo solucionamos?...

Algún iluminado podría indicar hacer lo siguiente: Creamos un cuarto método dentro de la clase al que podríamos llamar registrarMovimiento(). Este método se encargaría sólo de la parte del registro del movimiento; y cada uno de los anteriores tres métodos lo llama cuando ha concluido un movimiento. Genial. Veamos cómo quedaría registrarMovimiento():

private void registrarMovimiento()
{
Date hora = new Date();
SimpleDateFormat formatoDeFecha = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss");
System.out.println("Movimiento realizado a las " + formatoDeFecha.format(hora)) ;
}

Y ahora, el código de los otros tres métodos se modifica para llamar a registrarMovimiento() quedando así (sólo mostramos dos, pero el tercero seguiría la misma lógica que éstos):

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
//Registramos el movmiento
registrarMovimiento();
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
//Extraemos la cantidad del saldode la cuenta.
this.saldo -= cantidad;
//Registramos el movmiento
registrarMovimiento();
}
}
Pero lo malo de esta solución, es que si se efectuara otro movimiento que no fuera "dentro" de la clase Cuenta sino "dentro" de otra clase, esta clase tendría que tener su propio método registrarMovimiento(), y nuevamente estaríamos repitiendo código, pero entre clases. Ante este nuevo problema, podemos proponer otra solución: creamos una clase que se encargue específicamente de registrar movimientos; y cualquier método de cualquier clase puede instanciarla y llamar al método que registra movimientos. Podríamos, por ejemplo, crear una clase llamada RegistroDeMovimientos con un método público llamado registrarMovimiento(). Parece que esta es la mejor solución. Sin embargo no es así. Sigue habiendo "algo malo". ¿Qué es?...

Está claro: aunque tengamos una clase aparte que registre los movimientos, cada clase debe instanciar y llamar al método de esa clase. Es decir, seguimos repitiendo código. Cada método que deba registrar un movimiento, debe repetir el mismo código que los otros métodos que también deban registrar un movimiento. ¡Que feo! ¡Y no solo eso! Además, el hecho de registrar un movimiento -ya sea dentro del mismo método o llamando a RegistroDeMovimientos.registrarMovimiento()- significa introducir código que no pertenece exclusivamente al movimiento. El movimiento sólo debería realizar el movimiento y nada más. El registro debería hacerse aparte, no debería ser responsabilidad de un depósito, o una extracción o una transferencia. Esta forma de registrar un movimiento, ensucia el código que se refiere a los métodos de la clase Cuenta. Es decir, lo ideal sería que estos métodos se vieran así:

public void hacerDeposito(Double cantidad) {
if(cantidad <= 0) {
System.out.println("No hay dinero suficiente para hacer el depósito");
}
else {
this.saldo += cantidad;
}
}

public void hacerTransferencia(Double cantidad, Cuenta cuentaDestino)
{
if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la transferencia.");
}
else {
cuentaDestino.hacerDeposito(cantidad);
this.saldo -= cantidad;
}
}

public void hacerExtraccion(Double cantidad) {

if(this.saldo < cantidad) {
System.out.println("No hay fondos suficientes para la extracción.");
}
else {
this.saldo -= cantidad;
}
}
Como dije, sería ideal que a pesar de no llamar a registrarMevimiento(), el movimiento se registrara igual. Eso sería ideal, ¿no? No ensuciaríamos código y tampoco lo repetiríamos. La clase sería tremendamente cohesiva. Parece utópico ¿verdad? Bueno, para nuestra felicidad, esto es realizable y es acá donde entran en juego los "aspectos".

En la tercer parte, voy a mostrar cómo implementar un aspecto que solucione el problema planteado.

viernes, 15 de abril de 2011

Programación Orientada a Aspectos. ¿Qué es? (Parte 1)

Para explicar la programación orientada a aspectos, quizás lo ideal sería comenzar con una breve descripción de la historia de la ingeniería de software, como lo hacen la mayoría de los artículos o PDFs que podemos encontrar en la web, pero como justamente la mayoría lo hace así, yo no. Quien quiera verlo así, busque en la web el tema y ahí van a tener mucho para leer (y no está demás). Pero yo prefiero comenzar yendo al grano.

La programación orientada a objetos trata la manera de modularizar "conceptos comunes" de software. Sin embargo, existen otros conceptos o asuntos que se extienden a lo largo de estos "conceptos comunes" y que no pueden ser modularizados con el diseño orientado a objetos. En un intento más de subsanar lo que la orientación a objetos no puede, aparece una nueva solución: la Programación Orientada a Aspectos (y su consecuente Diseño Orientado a Aspectos).

La programación orientada a aspectos se ha planteado como un nuevo paradigma de programación (con lo que no estoy de acuerdo), el cual consiste en separar los conceptos que entrecruzan varias clases y se extienden a lo largo de éstas, pero que no pertenecen a esas clase en sí mismas. Incluso, los conceptos pueden aparecer no sólo en varias clases, sino de una sola. Ahora la pregunta: ¿de qué tipo de conceptos hablamos? Pensemos como ejemplo, en una aplicación que requiere del registro (logging) de las acciones que realiza. Bien, estos registros "alguien" tiene que llevarlos a cabo, y es normal cargar a muchas clases con la responsabilidad de hacerlo cuando, seguramente, no sea la función principal de esas clases hacer dicha tarea. Como vemos, se trata de una misma funcionalidad (registrar acciones) que se encuentra entrecruzada en varias clases, pero que a la vez no es parte de ninguna.

Otro ejemplo, simple de entender, es el manejo de errores. Los errores hay que tratarlos sí o si en una aplicación. Pero, desde un punto de vista "purista" de objetos, no tenemos clases que traten los errores por sí solos. Siempre las clases que definen la funcionalidad de la aplicación van a tener que lidiar con los errores, y esa no es su función principal. En cierta forma, esto hace a dichas clases menos cohesivas. Un tercer ejemplo puede ser el manejo de la sincronización. Nuevamente, los objetos del negocio deben tratar la sincronización además de su función principal.

En todo los ejemplos estamos viendo que hay ciertos asuntos que no pertenecen al negocio pero que sin embargo, deben ser tratados. Y lo negativo de esto, es que según el paradigma de objetos, son los objetos del negocio quienes deben tratar estos asuntos y, como si fura poco que hagan tareas que no les corresponden, estas tareas se esparcen a lo largo de toda la aplicación, llevando a dispersar código y enredarlo por la misma (a esto último se llama Code Tangling y Code Scattering).

Entonces, para darle más sentido a la POA, veamos en qué se afecta el desarrollo de aplicaciones cuando surgen estos asuntos:
  • Baja cohesión: las clases realizan tareas que no le corresponden específicamente a ellas.
  • Baja reusabilidad: Cuando una clase trata un asunto que no le corresponde, esta clase probablemente sea difícil de re usar en otro sistema.
  • Peor calidad de código: El código se complica, y cuesta más entenderlo y mantenerlo.
  • Evolución dificultosa: Se vuelve más costoso que el sistema evoluciones al tener código disperso y enredado por toda la aplicación.

Estos asuntos son denominados "conceptos transversales". La POA viene para tratar de separar y encapsularlos en una aplicación y aislarlos para independizar a los objetos del negocio de éstos conceptos. Este aislamiento se encapsula en "aspectos".

Por lo tanto, la POA permite la separación de conceptos transversales a través de mecanismos que permiten abstraer y encapsular estos conceptos en un sistema. Un aspecto es la unidad que encapsula uno o más conceptos transversales, y que con la programación orientada a objetos no es posible diferenciarlo de forma clara.

La definición actual de aspecto dice: "Un aspecto es una unidad modular que se disemina por la estructura de otras unidades funcionales. Los aspectos existen tanto en la etapa de diseño como en la de implementación. Un aspecto de diseño es una unidad modular del diseño que se entremezcla en la estructura de otras partes del diseño. Un aspecto de programa o de código es una unidad modular del programa que aparece en otras unidades modulares del programa.

La principal ventaja de la POA es que permite tratar la funcionalidad pura por un lado, y los aspectos por otro, de forma separada. Luego ambos se combinan con un tipo de programa llamado 'Weaver') para dar por resultado el sistema final.

Hay mucho más por hablar de POA aún. En la próxima parte (parte 2), voy a mostrar un ejemplo muy claro, para asentar toda esta teoría en algo más palpable, así que a no abandonar si esta pequeña introducción a resultado medio difícil de entender, en el ejemplo de la Parte 2 quedará muy claro de que se trata.