Buscar este blog

Cargando...

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.

martes, 12 de abril de 2011

Instalar AspectJ en NetBeans 6.9.1

English version

Hola. Finalmene, después de horas de intentos, logré copilar AspectJ en NetBeans 6.9.1.
Ahora les muestro la forma de hacerlo. Pero quiero aclarar que no voy a instalar un plug-in de netbeans, sino que voy a mostrar la forma de compilar aspectos en netbeans con AspectJ. Veamos los pasos:

1) Descargar la última versión estable de AspectJ en este sitio.
2) Descomprimir el archivo ".jar" en algún directorio donde pongan librerías. No debería ser en el directorio de librerías del proyecto, ya que quizás quieras usar esta librería en otros proyectos.
3) Crear un proyecto en netbeans, basta con un simple "Java Project".

Ahora, los próximos pasos deben seguirlos en cada nuevo proyecto que hagan:

4) Ir a las propiedades del proyecto, y en el panel de "librerias", seleccionar "Add Jar/Folder". Ahora, seleccionar los siguientes archivos del archivo descomprimido:
  • aspectjrt.jar
  • aspectjtools.jar
  • org.aspectj.matcher.jar

5)Una vez que se agregaron estos archivos, hay que editar el archivo build.xml creado en el directorio del proyecto.
6) Entre los tags <project> y </project> pegar el siguiente código:


<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>


De forma tal que el archivo build.xml les quede así:


<?xml version="1.0" encoding="UTF-8"?>

<project name="pruebaAspectJ_nb6.9.1" default="default" basedir=".">
<description>Builds, tests, and runs the project pruebaAspectJ_nb6.9.1.</description>
<import file="nbproject/build-impl.xml"/>

<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>

</project>


7) Ahora, modificar las lineas 7 y 14. En la línea 7 hay que especificar la ruta completa del archivo "aspectjtools.jar". Esto se hace donde descomprimiste aspectj. En la línea 14 hay que hacer lo mismo, pero apuntando al archivo "aspectjrt.jar".

8) Eso es todo!

Consideraciones

1) Bajar el archivo aspect{version}.jar, no el archivo aspectj{version}-src.jar.
2) Tener cuidado con las rutas de los archivos, siempre causan problemas!
3) No estoy seguro, pero es posible que las otras lineas que agregaron en build.xml tengan errores. A mi me funcionaron bien, pero puede que esto dependa del proyecto creado, así que si esto les causa problemas, hay que chequear los directorios a los que apunta el resto del archivo, y otras causas posibles de errores.

Espero que esto te ayude. Vuelvan a comentar si anduvo y/o si tienen sugerencias que crean que puede mejorar esto.

lunes, 11 de abril de 2011

Install AspectJ in NetBeans 6.9.1

Versión en español

Hi. First, sorry my English, it's not my native languaje.
Second, after hours trying, I managed to compile with AspectJ in NetBeans 6.9.1
Now I'll show the way to make it possible. But I want to clarify that I wont install a NetBeans's plugin, but it is the way to make it possible to compile aspects in netbeans with AspectJ. Now, let's go on the steps:

1) Download the AspectJ Latest Stable Release, on this page.
2) Unzip de ".jar" file in the directory you like to put your libraries. It should not be in the proyect's lib directory, because you may want to use it in other projects too. You will unzip about 4 ".jar" files.
3) Create a project in netbeans, just a simple "Java Project".

Now listen, you have to follow the next steps in every new project you make:

4) Go to the project's propierties and in the libraries panel, select the "Add Jar/Folder". Now, select this files from the unzipped file:
  • aspectjrt.jar
  • aspectjtools.jar
  • org.aspectj.matcher.jar

5) Once this files were added, you must edit the build.xml file created inside you project directory.
6) Between the tags <project> and </project> paste this code:


<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>


So the complete build.xml file can be like this:


<?xml version="1.0" encoding="UTF-8"?>

<project name="pruebaAspectJ_nb6.9.1" default="default" basedir=".">
<description>Builds, tests, and runs the project pruebaAspectJ_nb6.9.1.</description>
<import file="nbproject/build-impl.xml"/>

<taskdef classpath="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjtools.jar"
resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/>

<target name="aspectj">
<echo level="info">--- aspectj (start) ---</echo>
<iajc destDir="${build.classes.dir}">
<inpath>
<pathelement location="/home/ignacio/NetBeansProjects/lib/aspectj/aspectjrt.jar"/>
<pathelement location="${build.classes.dir}" />
</inpath>
<sourceroots>
<pathelement location="${src.dir}"/>
</sourceroots>
<classpath>
<pathelement location="${javac.classpath}"/>
<pathelement location="${j2ee.platform.classpath}"/>
</classpath>
</iajc>
<echo level="info">--- build.xml by Ignacio Rigoni email: {name}.{lastname}@gmail.com ---</echo>
</target>

<target name="-post-compile" depends="aspectj"></target>

</project>


7) Now, modify the lines 7 and 14. In line 7 you must specify the "aspectjtools.jar" with the full path. This is where you unzipped aspectj. In line 14 you must do the same, but pointing to the "aspectjrt.jar" file.

8) That's all.

Considerations

1) Use the aspect{version}.jar file, no the aspectj{version}-src.jar file.
2) Be careful with the paths, it always cause problems!
3) I'm not shure, but may be possible that the other lines you added in build.xml could have errors. It worked fine for me, but may be it depends on the project, so if that causes a problem, you should check the dirs, and other possible error sources.

I wish this helps you! Please, come back and comment or suggest if you think this could be improved in any way.

sábado, 9 de abril de 2011

Colorear código fuente en Bolgger con "Syntax HighLighter"

Esto si que me costo encontrarlo, y mas aun hacerlo funcionar. ¿Por que? Porque en la mayoria de las web esta mal explicado, como en esta.

Luego encontré cómo se configura blogger para que realmente funcione esto: es muy facil. Lo pasos son los siguientes:

1º) Modificamos la plantilla de Blogger.
Para esto vamos a Diseño -> Edición de HTML. Ahi buscamos la etiqueta </head>. Y justo una linea encima de esta agregamos el siguiente código:


<!--SYNTAX HIGHLIGHTER BEGINS-->
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'></script>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'></script>
<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf';
SyntaxHighlighter.all();
</script>
<!--SYNTAX HIGHLIGHTER ENDS-->


2º) Verificar si todo anduvo bien haciendo click en "Ver Blog".

3º) Agregar el código fuente que quieras.
Para esto, cuando estamos editando una entrada, tenemos que hacer click en la pestaña que dice "Edicion de HTML" y ahi agregar las siguientes líneas:


<pre class="brush:java">
Aca va tu codigo en java
</pre>


Donde dice java, ponen el lenguaje que esten usando. Para ver una lista de lenguajes disponibles y como se nombran, vean este link.

Por ultimo, me gustaria recalcar algo. Conviene formatear el codigo fuente, al final de la edición del post, ya que si se hace cambiando el tipo de edición (de "Edicion de HTML" a "Redactar") se pierde el formato de saltos de lineas y espaciados del codigo fuente. Por lo tanto, recomiendo escribir el post completo, y al final poner todo el código fuente que se quiera.

Saludos!