martes, 26 de enero de 2010

Patrones de diseño: Singleton

En este artículo vamos a ver uno de los patrones creacionales más comunes, el Singleton. Este patrón garantiza que una clase sólo tenga una instancia, y proporciona un punto de acceso global a ella.

Este patrón se suele utilizar cuando una clase controla el acceso a un recurso físico único o cuando hay datos que deben estar disponibles para todos los objetos de la aplicación.

El patrón Singleton se implementa mediante una clase con un constructor privado. Existirá un método que creará una instancia del objeto llamando al constructor sólo si todavía no existe ninguna.

Se pueden producir problemas en programas con múltiples hilos de ejecución, si dos hilos de ejecución intentan crear la instancia al mismo tiempo y ésta no existe todavía. Para que sólo uno de ellos pueda crear el objeto se puede utilizar exclusión mutua (synchronized) en el método de creación de la clase que implementa el patrón.

Habría que decir también que si existen varios cargadores de clases para la aplicación puede existir una instancia de la clase en cada uno de ellos, aunque la instancia sea única dentro de ese cargador.

Una implementación correcta del patrón Singleton en Java podría ser la siguiente, propuesta por el investigador Bill Pough:
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}

/**
* SingletonHolder is loaded on the first execution of
* Singleton.getInstance() or the first access to
* SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

A pesar de que es ampliamente utilizado, existe una corriente contraria al uso de este patrón debido a los problemas que introduce. En esta página Scout Densmore expone los problemas que Brian Button achaca a los Singletons. A continuación, hago una adaptación de lo ahí se dice:
  • Los Singletons normalmente se usan para proporcionar un punto de acceso global para un servicio. De esta forma no hace falta pasar una referencia a este servicio, lo que viene a ser como usar una variable global. Al final lo que ocurre es que las dependencias de diseño permanecen ocultas dentro del código y no son visibles al examinar las interfaces. Hace falta inspeccionar el código para entender qué objetos están usando las clases.

  • Los Singletons permiten limitar la creación de los objetos. Esto es cierto, pero ahora se están mezclando dos responsabilidades diferentes en la misma clase. Una clase no debería preocuparse de si es o no un Singleton, sino que sólo debería preocuparse por sus responsabilidades de negocio. Para limitar la creación de clases se deberían crear factorías u otros objetos que limiten la creación. De esta forma, cada objeto mantendría una responsabilidad mejor definida.

  • Los Singletons promueven el acoplamiento fuerte entre clases. Un acoplamiento flojo entre clases permite sustituir implementaciones alternativas de las clases colaboradoras en las pruebas. Una mejor alternativa es modificar el diseño para pasar referencias a los objetos en las clases y métodos, de forma que se reduzca el acoplamiento.

  • Los Singletons mantienen el estado hasta la finalización del programa. Este estado persistente es perjudicial para las pruebas unitarias, puesto que cada prueba debe ser independiente de las demás. Si esto no se cumple, podría llevar a situaciones donde las pruebas fallen donde no deben y a que se estén ocultando errores. Esto se puede evitar pasando referencias a objetos a las clases y métodos.

Es por ello que parece un patrón de diseño a evitar dentro de lo posible.

Referencias:
Patrón Singleton en Wikipedia
Singleton Pattern — Patrones de diseño
Singletons en Java, el patrón instancia única por David Barral
Patrón Singleton en c2.com
Why Singletons are Evil por Scott Densmore
Otros patrones de diseño


domingo, 24 de enero de 2010

Pruebas funcionales con Selenium

Selenium HQ es un framework que permite automatizar las pruebas funcionales sobre aplicaciones web. Está formado por varias herramientas que permiten definir estas pruebas y automatizarlas. En concreto, vamos a ver:
  • Selenium IDE: Se trata de un plugin de Firefox que permite definir una prueba de una aplicación web guardando en un script las acciones que ejecuta el usuario sobre el navegador. Este script puede volver a ejecutarse después todas las veces que se quiera.
  • Selenium RC (Remote Control): Permite automatizar las pruebas sobre las aplicaciones web a partir de los scripts definidos mediante Selenium IDE.
Veremos a continuación un ejemplo de prueba funcional de una aplicación web.

En primer lugar debemos descarganos el plugin de Firefox para Selenium IDE. Podemos hacerlo desde esta página. Esto descargará el plugin de Selenium IDE y lo instalará en el navegador. A continuación lo reiniciaremos para completar la instalación.

Ahora vamos a hacer una prueba de una aplicación web. En este caso se trata de una aplicación que guarda todos los artículos de interés de las revistas que voy comprando, y la prueba consistirá en introducir un nuevo artículo.

En primer lugar, vamos a Herramientas->Selenium IDE. Esto abre una ventana que permite grabar el script con la prueba a realizar:

A partir de este momento todo lo que hagamos sobre el navegador se registrará en el script. En este momento se introducirá un nuevo artículo de nombre “Nuevo” y título “Nuevo”. Una vez introducido, se pulsa sobre el botón rojo de la ventana de Selenium IDE para que pare la grabación del script. Comprobamos que se ha introducido el artículo.

Ahora repetimos la prueba pulsando sobre el triángulo verde situado arriba a la derecha de la ventana de Selenium IDE. Esto repite la ejecución anterior y por tanto, en el listado de artículos vemos que ahora existen 2 artículos de nombre “Nuevo”.

Podemos grabar esta prueba desde Archivo->Save Test Case. Sin embargo para nosotros será más interesante la opción Archivo->Export Test Case As ->Java (JUnit) Selenium RC que exportará este script a un caso de prueba de JUnit que vamos a utilizar posteriormente para automatizar esta prueba:
package com.example.tests;

import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;

public class Prueba extends SeleneseTestCase {
public void setUp() throws Exception {
setUp("http://change-this-to-the-site-you-are-testing/", "*chrome");
}
public void testPrueba() throws Exception {
selenium.open("/RevisteroMyFacesWeb/");
selenium.click("link=Nuevo Artículo");
selenium.waitForPageToLoad("30000");
selenium.type("j_id_jsp_815202587_1:nombreArticulo", "Nuevo");
selenium.type("j_id_jsp_815202587_1:descripcionArticulo", "Nuevo");
selenium.click("j_id_jsp_815202587_1:j_id_jsp_815202587_35");
selenium.waitForPageToLoad("30000");
}
}

Una vez definida la prueba vamos ahora a automatizarla. Para ello usaremos JUnit y la herramienta Selenium RC (Remote Control). También usaremos el plugin de Selenium para Maven, que permite arrancar el servidor de Selenium RC cuando se ejecutan las pruebas.

Creamos un proyecto de Maven con el siguiente pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roldan</groupId>
<artifactId>RevisteroPruebasSelenium</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium.client-drivers</groupId>
<artifactId>selenium-java-client-driver</artifactId>
<version>1.0.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>selenium-maven-plugin</artifactId>
<executions>
<execution>
<phase>process-test-classes</phase>
<goals>
<goal>start-server</goal>
</goals>
<configuration>
<background>true</background>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Vemos que además de configurar el plugin de Maven para Selenium para que arranque el servidor de Selenium en la fase anterior a la de test (process-test-classes), define dos dependencias, JUnit y el driver de cliente Java para Selenium, que permite ejecutar los tests creados desde Selenium IDE.

Vamos a adaptar la clase de test generada desde Selenium IDE para que haga uso del driver de Java para Selenium:
package com.roldan.selenium;

import com.thoughtworks.selenium.*;

public class CrearNuevoArticuloTest extends SeleneseTestCase {

protected DefaultSelenium createSeleniumClient(String url) throws Exception {
return new DefaultSelenium("localhost", 4444, "*firefox", url);
}

public void testCrearNuevoArticulo() throws Exception {
DefaultSelenium selenium = createSeleniumClient("http://localhost:8080/");
selenium.start();

selenium.open("/RevisteroMyFacesWeb/");
selenium.click("link=Nuevo Artículo");
selenium.waitForPageToLoad("30000");
selenium.type("j_id_jsp_815202587_1:nombreArticulo", "Nuevo");
selenium.type("j_id_jsp_815202587_1:descripcionArticulo", "Nuevo");
selenium.click("j_id_jsp_815202587_1:j_id_jsp_815202587_35");
selenium.waitForPageToLoad("30000");

selenium.stop();
}
}

La diferencia está en que ahora al comienzo de la prueba se crea un cliente de Selenium y al final de la prueba se cierra este cliente.

Si ahora se lanzan los test para este proyecto con mvn test, se verá aparecer un navegador que repite la prueba definida, y se habrá grabado otro artículo más.

Referencias:
Web de Selenium HQ
Turorial de Adictos al trabajo sobre Selenium IDE
Turorial de Adictos al trabajo sobre Selenium RC
Tutorial de Dos Ideas sobre tests secuenciales con Selenium y JUnit
Web del plugin de Selenium para Maven

viernes, 8 de enero de 2010

Patrones de diseño

Cada vez que se comienza el desarrollo de una nueva aplicación, como ingenieros de software nos volvemos a enfrentar a los mismos o similares problemas que ya se han encarado en anteriores desarrollos. No sólo esto, nos estamos enfrentando en muchos casos a los mismo problemas que otros ya han tenido que resolver.

Aprovechar todo el conocimiento anterior es útil y permite ganar tiempo en el diseño y desarrollo de nuevas aplicaciones. Esto es algo de sobra conocido y por ello han surgido los patrones de diseño, como pautas a seguir en determinadas condiciones avaladas por el conocimiento previo.

En la construcción, el arquitecto Christopher Alexander propuso el aprendizaje y uso de una serie de patrones para la construcción de edificios de una mayor calidad. Según sus palabras, "cada patrón describe un problema que ocurre infinidad de veces en nuestro entorno, así como la solución al mismo, de tal modo que podemos utilizar esta solución un millón de veces más adelante sin tener que volver a pensarla otra vez."

Los patrones que Christopher Alexander y sus colegas definieron son un intento de formalizar y plasmar de una forma práctica generaciones de conocimiento arquitectónico. Los patrones no son principios abstractos que requieran su redescubrimiento para obtener una aplicación satisfactoria, ni son específicos a una situación particular o cultural; son algo intermedio. Un patrón define una posible solución correcta para un problema de diseño dentro de un contexto dado, describiendo las cualidades invariantes de todas las soluciones.

Llevando la idea de patrón al mundo de la informática, un patrón de diseño es una solución a un problema de diseño que debe poseer las siguientes características:
  • Debe haber comprobado su efectividad resolviendo problemas similares en ocasiones anteriores.
  • Debe ser reusable, lo que significa que es aplicable a diferentes problemas de diseño en distintas circunstancias.

Los patrones de diseño tuvieron un gran éxito a partir de la publicación del libro Design Patterns escrito por el grupo Gang of Four (GoF, en el que se recogían 23 patrones de diseño comunes. Estos patrones definidos por el GoF están divididos en 3 grupos, patrones creacionales, estructurales y de comportamiento.

Patrones creacionales: Tratan de solucionar los problemas que pueden surgir en la creación de objetos.
  • Abstract Factory: Proporciona una interfaz para crear familias de objetos o que dependen entre sí, sin especificar sus clases concretas.
  • Factory Method: Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidan qué clase instanciar. Permite que una clase delegue en sus subclases la creación de objetos.
  • Builder: Separa la construcción de un objeto complejo de su representación, de forma que el mismo proceso de construcción pueda crear diferentes representaciones.
  • Prototype: Especifica los tipos de objetos a crear por medio de una instancia prototípica, y crear nuevos objetos copiando este prototipo.
  • Singleton: Garantiza que una clase sólo tenga una instancia, y proporciona un punto de acceso global a ella.

Patrones estructurales: Tratan de facilitar el diseño identificando formas simples de establecer relaciones entre entidades.
  • Adapter: Convierte la interfaz de una clase en otra distinta que es la que esperan los clientes. Permiten que cooperen clases que de otra manera no podrían por tener interfaces incompatibles.
  • Bridge: Desvincula una abstracción de su implementación, de manera que ambas puedan variar de forma independiente.
  • Composite: Combina objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que los clientes traten de manera uniforme a los objetos individuales y a los compuestos.
  • Decorator: Añade dinámicamente nuevas responsabilidades a un objeto, proporcionando una alternativa flexible a la herencia para extender la funcionalidad.
  • Facade: Proporciona una interfaz unificada para un conjunto de interfaces de un subsistema. Define una interfaz de alto nivel que hace que el subsistema se más fácil de usar.
  • Flyweight: Usa el compartimiento para permitir un gran número de objetos de grano fino de forma eficiente.
  • Proxy: Proporciona un sustituto o representante de otro objeto para controlar el acceso a éste.

Patrones de comportamiento: Identifican patrones comunes de comunicación entre objetos y tratan de incrementar la flexibilidad de esta comunicación.
  • Chain of Responsibility: Evita acoplar el emisor de una petición a su receptor, al dar a más de un objeto la posibilidad de responder a la petición. Crea una cadena con los objetos receptores y pasa la petición a través de la cadena hasta que esta sea tratada por algún objeto.
  • Command: Encapsula una petición en un objeto, permitiendo así parametrizar a los clientes con distintas peticiones, encolar o llevar un registro de las peticiones y poder deshacer la operaciones.
  • Interpreter: Dado un lenguaje, define una representación de su gramática junto con un intérprete que usa dicha representación para interpretar las sentencias del lenguaje.
  • Iterator: Proporciona un modo de acceder secuencialmente a los elementos de un objeto agregado sin exponer su representación interna.
  • Mediator: Define un objeto que encapsula cómo interactúan un conjunto de objetos. Promueve un bajo acoplamiento al evitar que los objetos se refieran unos a otros explícitamente, y permite variar la interacción entre ellos de forma independiente.
  • Memento: Representa y externaliza el estado interno de un objeto sin violar la encapsulación, de forma que éste puede volver a dicho estado más tarde.
  • Observer: Define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambia de estado se notifica y actualizan automáticamente todos los objetos.
  • State: Permite que un objeto modifique su comportamiento cada vez que cambia su estado interno. Parecerá que cambia la clase del objeto.
  • Strategy: Define una familia de algoritmos, encapsula uno de ellos y los hace intercambiables. Permite que un algoritmo varíe independientemente de los clientes que lo usan.
  • Template Method: Define en una operación el esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos. Permite que las subclases redefinan ciertos pasos del algoritmo sin cambiar su estructura.
  • Visitor: Representa una operación sobre los elementos de una estructura de objetos. Permite definir una nueva operación sin cambiar las clases de los elementos sobre los que opera.

Con el tiempo, han ido surgiendo nuevos patrones, sobre todo dentro del ámbito del desarrollo Java empresarial. Algunos de ellos son:
  • Controlador frontal
  • Modelo Vista Controlador (MVC)
  • Vista de composición
  • Fachada de sesión - Sesion Facade
  • Localizador de servicio - Service Locator
  • Objeto valor - Value object
  • Objeto de Transferencia de Datos - Data Transfer Object (DTO)
  • Delegado de empresa - Bussiness Delegate
  • Objeto de acceso a datos - Data Access Object (DAO)
  • Dependency Injection(DI) - Inversion of Control (IoC)
  • Open Session In View (OSIV)
  • ThreadLocal Session

En este artículo sólo he tratado de dar una introducción a los patrones de diseño. En posteriores artículos trataré de desarrollar algunos de los patrones aquí expuestos analizando su utilidad, virtudes y defectos.

Referencias:
Design Patterns (Erich Gamma, Richard Helm, Ralph Johnson, Hohn Vlissides)
Professional Java Server Programming J2EE, 1.3 Edition (Subrahmanyam Allamaraju, Cedric Beust, Marc Wilcox, Sameer Tyagi, Rod Johnson, Gary Watson, Alan Williamson, John Davies, Ramesh Nagappan, Andy Longshaw, P. G. Sarang, Tyler Jewell, Alex Toussaint)
Patrones de diseño en Wikipedia
Introducción al diseño con patrones por Manuel Lagos Torres
Patrones de diseño en ingenierosoftware.com