Archive for January, 2009

29 JanCuidado con @Override

Acabo de leer una curiosidad sobre la anotación @Override de la que resulta que hay que tener especial cuidado en el caso de que no usemos el mismo JDK en nuestros entornso de desarrollo y los de despliegue.

Resulta que si implementamos una interfaz y anotamos en la implementación uno de los métodos implementados con @Override, el compilador de JDK 6 no se quejará mientras que sí lo hará el de JDK 5.


public interface MyInterface {

 public void f();

}

public class MyClass implements MyInterface {

 @Override public void f() {  // TODO Auto-generated method stub

 }

}

Que conste que lo he probado fuera de Eclipse (¡¡sí, sí, he salido a la linea de comandos!!) y que el resultado es el esperado. Al ejecutar javac MyInterface.java y javac -cp . MyClass.java con JDK 1.6.0_11 no obtengo error alguno, sin embargo, cuando lo hago con JDK 1.5.0_12 obtengo “method does not override a method from its superclass”.

La verdad, a mi me parece que debería haberse quedado como en JDK 5 puesto que “override” significa “invalidar” y justamente eso es lo que se hace al sobrescribir un método: invalidar la implementación de la superclase. Pero bueno, habrá que guardarlo en esa lista de incongruencias peligrosas a tener en cuenta en los despliegues… :)

Tags:

28 JanJetty como proyecto Eclipse

Jetty significa malecón en españolAcabo de leer la propuesta que hay sobre la mesa para llevar Jetty a eclipse.org e incluso formar parte de Eclipse 3.5 (Galileo) para este verano. Es interesante sobre todo porque los planes a largo plazo son involucrarse en mejorar el HttpService de Equinox (y supongo que la especificación OSGi del mismo).

26 JanPruebas funcionales automatizadas de una aplicación web

Hoy voy a resumir cómo automatizar las pruebas funcionales de una aplicación web utilizando:
  • Maven. Con Maven gestionamos el ciclo de vida de la construcción y las pruebas, así como las dependencias entre artefactos.
  • Cargo. Con este plugin Maven realizamos el despliegue de la aplicación web en el contenedor de nuestra elección.
  • Selenium Webdriver. Con este framework y el correspondiente plugin Maven ejecutamos las pruebas funcionales.
  • Jetty. Éste es el contenedor web de mi elección. (Podría haber sido Tomcat, Glassfish o cualquier otro).
  • JUnit. Como framework de pruebas.
  • Wicket. Éste es el framework web de mi elección.

Todo el código fuente lo tenéis disponible en GoogleCode.

Pruebas unitarias

En Eclipse y con m2eclipse he creado el proyecto raíz con dos módulos: web (de tipo war) y web-integration-test (de tipo pom). El proyecto web lo he creado con el arquetipo “org.apache.wicket:wicket-archetype-quickstart:1.4-rc1″ y luego lo he tocado un poco.

< ?xml version="1.0" encoding="UTF-8"?>
 
  shopaas  shopaas  0.0.1-SNAPSHOT  4.0.0 shopaas web 
war Web Application 0.0.1-SNAPSHOT UI wicket para Shop As A Service   shopaas-web         src/main/resources          src/main/java         **             **/*.java                  src/test/java         **             **/*.java          
 
    maven-compiler-plugin    true         1.5     1.5     true     true        
    org.mortbay.jetty    maven-jetty-plugin         10            
8080       60000                   
    maven-eclipse-plugin         true                org.apache.wicket   wicket   ${wicket.version}       org.slf4j   slf4j-log4j12   1.4.2       log4j   log4j   1.2.14       junit   junit   4.5   test       org.mortbay.jetty   jetty   ${jetty.version}   provided       org.mortbay.jetty   jetty-util   ${jetty.version}   provided       org.mortbay.jetty   jetty-management   ${jetty.version}   provided    
  6.1.14  1.4-rc1 

No quiero entrar en detalles sobre cómo es una aplicación Wicket, pero sí explicaré los dos detalles más importantes:

Si quiero desplegar la aplicación en Jetty no tengo más que ejecutar Maven con el “goal” jetty:run, pero esto sólo nos sirve para probar manualmente nuestra aplicación. (Por cierto, el puerto 8080 es el puerto por defecto, pero me gusta explicitar esta configuración).

Wicket proporciona la clase WicketTester, que permite probar la aplicación fuera del contenedor, mediante una simulación del mismo. De esta manera podemos hacer pruebas unitarias de todos los componentes de nuestra GUI sin necesidad de empaquetarla y desplegarla. Más adelante, en futuros artículos, tengo previsto entrar en detalle en cómo desarrollar la GUI con Wicket haciendo TDD.

package shopaas;

import junit.framework.TestCase;import org.apache.wicket.util.tester.WicketTester;

/** * Simple test using the WicketTester */public class TestHomePage extends TestCase{ private WicketTester tester;

 @Override public void setUp() {  tester = new WicketTester(new WicketApplication()); }

 public void testRenderMyPage() {  //start and render the test page  tester.startPage(HomePage.class);

  //assert rendered page class  tester.assertRenderedPage(HomePage.class);

  //assert rendered label component  tester.assertLabel("message", "If you see this message wicket is properly configured and running"); }}

Esta prueba es muy simple, pero lo suficiente como para ver “por dónde van los tiros”. Como podéis comprobar, llegados a este punto podemos tener las pruebas unitarias de nuestra aplicación web completamente automatizadas y, por tanto, incluidas en nuestro sistema de integración continua sin mayor problema.

Pruebas funcionales

Pruebas funcionales o de integración son términos muy usados pero no tengo claro que todo el mundo entienda lo mismo cuando los usa. Lo que yo estoy llamando aquí pruebas funcionales o de integración son aquellas en las que pruebo el sistema desplegado (hasta donde se puede razonablemente). Pues bien, lo que voy a enseñar ahora es cómo desplegar de manera automática el war de nuestra aplicación y lanzar (automáticamente también) las pruebas.

Para esto he usado Cargo y he modificado el ciclo de vida de varios plugins (compiler, surefire y el propio cargo) para que se ejecuten en el orden adecuado. Además, he usado Selenium Webdriver para escribir y ejecutar las pruebas.

Al ejecutar (desde el proyecto raiz) Maven con el goal “integration-test”, el propio Maven estudia las dependencias entre artefactos y empaqueta el war (y ejecuta sus pruebas) antes de pasar a desplegar ese war en un Jetty 6 que se arranca y detiene solamente para ejecutar las pruebas de integración.



 4.0.0 
  shopaas  shopaas  0.0.1-SNAPSHOT  web-integration-test 
pom Functional Tests      shopaas   web   0.0.1-SNAPSHOT   war       junit   junit   4.5   test         org.openqa.selenium.webdriver   webdriver-htmlunit   0.6.685       org.openqa.selenium.webdriver   webdriver-support   0.6.685         org.mortbay.jetty   jetty   ${jetty.version}   provided       org.mortbay.jetty   jetty-util   ${jetty.version}   provided       org.mortbay.jetty   jetty-management   ${jetty.version}   provided       
 
    org.apache.maven.plugins    maven-compiler-plugin         1.5     1.5     true     true                          testCompile                   
    org.apache.maven.plugins    maven-surefire-plugin          
integration-test             test                   
    org.codehaus.cargo    cargo-maven2-plugin         false                          shopaas        web        war 
         /                          

               start 
pre-integration-test             start                      stop 
post-integration-test             stop                      
 
   jetty6x       true    
    6.1.14       
 
      org.codehaus.cargo      cargo-maven2-plugin                     jetty6x        embedded               
         8080         medium               
          

El único test que he incluido como prueba de concepto contiene dos tipos de prueba (una con Webdriver y otra sin él, la anotada con @Ignore).

package shopaas.web.integration.test;

import static org.junit.Assert.assertEquals;

import java.net.HttpURLConnection;import java.net.URL;

import org.junit.Before;import org.junit.Ignore;import org.junit.Test;import org.openqa.selenium.WebDriver;import org.openqa.selenium.htmlunit.HtmlUnitDriver;

public class WebappTest {

 @Ignore @Test public void testCallIndexPage() throws Exception {  URL url = new URL("http://localhost:8080/");  HttpURLConnection connection = (HttpURLConnection) url.openConnection();  connection.connect();  assertEquals(200, connection.getResponseCode()); }

 private WebDriver driver;

 @Before public void setUp() {  driver = new HtmlUnitDriver(); }

 @Test public void testHomepage() {  driver.get("http://localhost:8080/");  assertEquals("Wicket Quickstart Archetype Homepage", driver.getTitle()); }

}

He utilizado el HtmlUnitDriver que, aunque también es una emulación de una navegador, para mi es suficiente, no me complica mi entorno y además es más rápido. Pero si quisiera utilizar Firefox, Safari o Internet Explorer, no tendría más que cambiar el driver correspondiente. Lógicamente, podemos tener la misma prueba con un driver diferente y estaremos asegurando que nuestra aplicación funciona para varios navegadores. Mmmmm, veo que he captado vuestra atención… :-)

Problemas encontrados

Al poner todo esto en pie he estado bastante tiempo atascado porque cada vez que ejecutaba las pruebas de integración obtenía un mensaje de error en Jetty diciendo que no era capaz de arrancar la aplicación porque “No suitable Log constructor”. No entiendo de dónde sale el dichoso commons-logging, pero el caso es que poniendo el fichero commons-logging.properties en el classpath de la aplicación web (para que se empaquete en el war), todo pasó a funcionar perfectamente.

org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

El otro inconveniente que tuve es más un detalle al que prestar atención que otra cosa. Se trata del valor del contexto que hay que poner en la configuración de Cargo, que debe coincidir con el valor usado en el URL de la aplicación en nuestras pruebas y en el fichero web.xml de la aplicación web.

 
    org.codehaus.cargo    cargo-maven2-plugin         false                          shopaas        web        war 
         /                          

                                    ...       

Bien, creo que esto es todo. Si tenéis interés y el código de ejemplo no es suficiente, no dudéis en preguntarme y trataré de ayudaros.

14 JanArquitectura en Capas de Cebolla

Hay veces que se me hace un mundo el darle nombre a algunos conceptos cuyo nombre original es en inglés. Este es el caso de la “Onion Architecture“, cuya traducción literal sería “Arquitectura Cebollera”, lo cuál suena francamente mal, casi igual que “Arquitectura de cebolla”, que es como lo traduce Mario A. Chavez en la traducción de este artículo que hace en su blog. Yo, personalmente la llamaría “Arquitectura en Capas de Cebolla“, simplemente porque así me suena mejor.y, de paso, hacemos hincapié en que se trata de una arquitectura en capas (pero no una más).



Es bastante evidente el porqué de su nombre (incluso en español). :-)

No voy a hacer un refrito del artículo original ni de su traducción, pero sí os diré dos cosas:

1) que me parece especialmente relevante el comentario en la tercera parte del artículo original (lo siento, sólo en inglés) sobre qué es lo que está en el “corazón” de la cebolla: el modelo de dominio y NO el modelo de datos,
2) que he estado contrastando esta arquitectura (que no se queda en la mera representación visual de la misma) con la aplicación de demostración de DDD y, salvo algún detalle menor, encaja perfectamente y hace más fácil de entender el por qué de ciertas dependencias.

Como siempre, vuestros comentarios serán bienvenidos.

Tags:

13 JanMaterial para prácticas ágiles

Muchas gracias a Juan Palacio porque ha realizado una aportación excelente a la comunidad de agilistas en español con su material para prácticas ágiles. Se trata de una serie de fichas, presentaciones y apuntes sobre Prácticas ágiles, que vienen a complementar a los libros “Flexibilidad con Scrum” y “Manual de gestión de proyectos ágil“.

Recomiendo, por supuesto, también su selección de utilidades y documentos.

Insisto, muchas gracias Juan por tus aportaciones a la comunidad. Ojalá algún día yo pueda ofrecer siquiera la mitad de lo que tú ya has aportado.

Powered by ScribeFire.

Tags:

10 JanDiseño emergente

Mientras preparaba una sesión del curso online de Lean Software Development que imparte Alan Shalloway tuve que leer un artículo de él mismo titulado algo así como “Guía para desarrolladores ágiles sobre Lean Software Development” (traducción libre). En este artículo se recopilan detalles interesantes como los principios fundamentales del desarrollo de software “lean” (Nota: demonios, necesito una traducción para este término), pero lo que quizás más me ha gustado ha sido la definición de Diseño Emergente.

Shalloway explica que al abordar un diseño hay básicamente dos opciones: diseñar estríctamente para cubrir los requerimientos (con lo que el código resultante irá siendo progresivamente más difícil de mantener) o diseñar pensando en el futuro (con lo que frecuentemente introducimos más complejidad de lo necesario). Aquí introduce Shalloway una tercera opción que denominamos Diseño Emergente y que resulta de la combinación de tres disciplinas (ojo, dice disciplinas):

  • basar el diseño en patrones para crear arquitecturas resistentes y flexibles a la vez, abaratando así el coste de mantenimiento del código
  • limitar el diseño sólo a los requisitos actuales (no adelantarse a requisitos futuros), consiguiendo así reducir el tamaño y complejidad del código
  • escribir pruebas de aceptación y unitarias automatizadas antes de escribir el propio código, favoreciendo así la construcción de un mejor diseño y haciendo que sea más seguro aplicar cambios

Shalloway también dice que el Diseño Emergente nos ayuda a añadir código nuevo desacoplado del viejo pero sin incorporar complejidades innecesarias. Esto, dicho así, puede resultar un poco difícil de entender, pero en el contexto de desarrollos iterativos tiene mucho sentido.

Trabajar sin un diseño completo desde el principio es algo incómodo por el nivel de incertidumbre que se maneja, pero si lo pensamos fríamente, es muchor mejor postergar las decisiones de diseño mientras tengamos dudas sobre los requisitos. En cualquier caso, me gustaría añadir que trabajar con un Diseño Emergente NO significa trabajar SIN diseño o con un diseño IMPROVISADO. Me remito a las tres disciplinas que enumera Shalloway:

Patrones de diseño

Emplear patrones de diseño contribuye definitivamente a que tengamos un diseño fácil de transimitir (incluso fácil de documentar). (Nota para los arquitectos: es una buena práctica documentar con gran detalle los patrones empleados -aunque no sean del GoF y nos los hayamos “inventado”- y pedir a los desarrolladores que documenten en su código qué piezas de los patrones están implementando.)

Por otro lado, los patrones de diseño nos permiten construir soluciones extensibles puesto que no resuelven nuestro problema sino un problema más general.

Me gustaría añadir que también podemos añadir patrones de análisis (ver libro de Fowler “Analysis Patterns“, p.ej.) a nuestra caja de herramientas con el objetivo de ser capaces de plantear el diseño más adecuado a nuestro problema, pero con la “puerta abierta” a futuras necesidades.

No adelantarse al futuro

Nuestro pequeño gran ego de programador nos empuja indefectiblemente a demostrarle al mundo entero lo listos que somos al ser capaces de ver el futuro y adelantarnos a todos prediciendo las necesidades de los clientes. Para ello solemos diseñar soluciones tan virtuosas como inútiles para el 80% de las necesidades reales de los clientes. Frecuentemente nos encontramos con diseños que transforman datos entre capas una y otra vez hasta llevarlas a la base de datos, validando una y otra vez los datos (antes y después de persistirlos)… aunque esos datos en realidad el cliente nunca los ha necesitado guardar. Alguien decidió en algún momento que era mejor guardarlo todo “por si acaso” y la consecuencia es un código tremendamente difícil de explicar, con muchos defectos de desarrollo y un rendimiento muy mejorable. Muchas veces somos nosotros mismos los que diseñamos así: “por si acaso”.

Pues bien, está demostrado que es mejor no diseñar “por si acaso”. En la mayoría de las ocasiones no estamos haciendo una inversión sino introduciendo complejidad que nunca se verá compensada. En términos económicos eso no es rentable.

Propongo que hagáis el ejercicio de identificar algunas de esas “características avanzadas” que se incorporan “por un pequeño esfuerzo más” y que al final del proyecto nunca se han utilizado. Si además sois capaces de saber cuánto ha sido ese “pequeño esfuerzo más”, quizás lo podáis sumar a los defectos y retrasos provocados por esas “características avanzadas”. Claro, un diseño sin “características avanzadas” es menos “cool”. :-)

Pruebas automatizadas

Muchísimas veces me he encontrado con que teníamos tanto miedo de hacer cambios en el diseño que retorcíamos el diseño existente hasta límites insospechados. En ocasiones, cambiar aquí hacía que allí dejara de funcionar. Lo más terrible era cuando nos enterábamos de ese impacto cuando nos llamaba el cliente para decirnos que les había salido un mensaje muy extraño en la pantalla…. Ay, si hubieramos contado con un conjunto de pruebas automatizadas que cubrieran los requisitos de nuestros clientes…

Hoy día, este problema está claramente superado, si no tenemos un motor de integración continua y desarrollamos nuestras pruebas unitarias y de aceptación es o porque no sabemos o porque no queremos, pero no nos podemos escudar en que no es posible o que es muy costoso.

Instalar Hudson, Continuum o CruiseControl se hace en dos patadas y desarrollar pruebas unitarias con JUnit o TestNG está ampliamente documentado. Si tenéis un frontal web podéis usar Selenium, HttpUnit o algún otro framework similar. Si tenéis web services podéis usar SoapUI o haceros vuestro propio framework “ad hoc” basándolo en HttpUnit, por ejemplo. Y finalmente, para escribir las pruebas de aceptación tenéis desde el viejo Fit (o Fitnesse) hasta Concordion (lógicamente mi recomendación) o incluso easyb o jBehave. Para cada clavo seguro que tenéis vuestro martillo.

Pero Shalloway va un poco más allá y pide escribir las pruebas ANTES que el código. Hay mucho escrito sobre TDD (test-driven development), ATDD (acceptance test-driven development) o BDD (behaviour-driven development), pero os puedo asegurar que practicar el “red-green-refactor” termina dando como resultado diseños y código de mucha mejor calidad, con el beneficio añadido de que tenemos una estupenda red de seguridad formada por las pruebas que hemos ido escribiendo para explicar qué queríamos que hiciera el software y no para explicar lo que ya hacía el software. Además, reducimos el número de defectos y, yo no sé a vosotros, pero a mi no me gusta nada estar resolviendo defectos… a mis jefes tampoco. :-)

Proceso de descubrimiento

Otra afirmación de Shalloway con la que estoy muy de acuerdo es que:

El proceso de desarrollo de software es más un proceso de descubrimiento que de construcción.

Podría dedicar un artículo entero a esta afirmación pero sólo quiero señalar que parte de lo que se va
descubriendo durante este proceso es justamente el Diseño Emergente.

Viendo el desarrollo de software dentro del proceso mayor que lo engloba, el desarrollo del producto, podemos decir (simplificando mucho) que hay 3 fases para desarrollar un producto:

  • descubrir las necesidades del cliente
  • imaginar cómo construir los artefactos que cubrirán esas necesidades
  • construir los artefactos

Shalloway explica muy bien en su artículo cómo empleamos un gran esfuerzo en las dos primeras fases a pesar de que normalmente no somos casi ni conscientes (¿inconscientes?) de ello. Si de repente tuvieramos la oportunidad de reconstruir nuestro sistema tardaríamos digamos un 50%-80% menos del tiempo empleado la primera vez. Ese tiempo “perdido” es el correspondiente a las dos primeras fases: descubrir necesidades y diseñar los artefactos.

El artículo de Shalloway del que he extraído las principales ideas que os he comentado es mucho más rico porque recorre los principios fundamentales de “Lean” y va mostrando qué prácticas ágiles surgen a partir de ellos. Esta muy bien porque así es posible tener un fundamento teórico para unas prácticas y, cuando en ocasiones no es posible aplicarlas, podemos sustituirlas por otras pero respetando los principios, es decir, buscando los mismos beneficios. También compara los procesos de producción JIT (just-in-time) con los procesos ágiles de desarrollo de software, pero esto casi merece otro artículo sólo para él.

Estaría encantado de conocer vuestras opiniones.

08 JanMétodos estáticos y pruebas unitarias

El año pasado :-) he comenzado el desarrollo de un plug-in para Concordion sin pruebas unitarias. “¡Vaya tío chungo!”, estaréis pensando ahora mismo. Bueno, en cierto modo tenéis razón. Pero tengo una buena excusa. :-)

El caso es que he copipegado código del ejemplo de editor multipáginas que viene con Eclipse y también del WicketBench (un plugin para trabajar con Wicket del que pretendo plagiar más de una idea). Y resulta que este código “heredado” hace un uso bastante prolijo de métodos estáticos para obtener información de contexto y, sobre todo, de la plataforma. Y me viene al pelo el reciente artículo de Misko Hevery donde explica por qué los métodos estáticos son tan malos para las pruebas y delatan diseños deficientes.

En resumen: no tengo pruebas unitarias de mi código porque no puedo sustituir las llamadas a métodos estáticos por ningún tipo de doble. Cualquier colaborador puedo sustituirlo más o menos fácilmente con un doble (p.ej. un mock), pero un método estático está pegado “a fuego” a una clase, y no puedo sustituir una clase por otra… :-(

Claro está que estoy cambiando el código para encapsular las llamadas a métodos estáticos en clases de colaboración que pueda sustituir en mis pruebas. Así acoto el problema, tal y como Eric Evans aconseja al explicar el “anticorruption layer” (capa anticorrupción), y mejoro la facilidad para escribir pruebas para mi diseño y, por tanto, mejoro también mi diseño.