Ejemplo de reutilización de código
30 oct 2009
Un ejemplo de reutilización de código e ingeniería de “software” en Disney. Tengo la sensación de que no pasaría los test de duplicación de código…
Visto en Con Código
30 oct 2009
Un ejemplo de reutilización de código e ingeniería de “software” en Disney. Tengo la sensación de que no pasaría los test de duplicación de código…
Visto en Con Código
25 oct 2009
Recientemente se ha liberado la primera versión estable de Weld, la implementación de referencia de Web Beans (Java Context and Dependenty Injection - JSR 299). Y aunque puede parecer una liberación cualquiera, en este caso estamos ante un evento realmente importante para el mundillo Java.
¿Por qué es importante esta liberación?
¿Consecuencias para la industria a medio plazo?
¿Consecuencia para nosotros?
¿Defectos?
En definitiva, todo indica que estamos antes una de las piezas clave del próximo JEE 6.
16 oct 2009
El objetivo de este artículo es servir de guía básica para la migración manual de proyectos Java no Maven a entorno Maven. Pensado y dirigido especialmente a personas con poca experiencia previa en Maven, pero con algún conocimiento previo.
Como es obvio, para migrar un proyecto Java a Maven, deberemos disponer de sus fuentes y todas las librerías dependientes.
Ya que vamos a realizar modificación estructurales importantes en el proyecto, conviene asegurarnos de que los fuentes no están conectados a ningún sistema de control de versiones como Subversion. Para realizar esto, podemos o bien eliminar manualmente todos los directorios .svn de nuestro proyecto o bien desde Eclipse desconectar el proyecto.
Si lo vamos a realizar de forma manual, debemos asegurarnos de eliminar todos los directorios .svn (o .CVS si el proyecto a migrar estuviese conectado a un CVS) A modo de ejemplo, en Linux podemos ejecutar el siguiente comando desde el directorio del proyecto para eliminar todas las referencias a carpetas ‘.svn’:
rm -rf `find . -type d -name .svn`
Será mucho más sencillo hacerlo de forma automática desde Eclipse. Para desconectar el proyecto, teniéndolo seleccionado pulsaremos sobre el botón derecho del ratón: Team -> Disconnect.
Aunque la estructura por defecto Maven puede ser modificada, es muy recomendable adaptar la organización del proyecto a migrar a la estructura por defecto más generalizada:
Para hacer esta modificación de la estructura hay que tener especial cuidado en algunos aspecto o convenciones Maven:
Una vez que la estructura del proyecto se ha adaptado a la filosofía Maven, el siguiente paso es definir el pom.xml del proyecto.
Partiremos de un fichero pom.xml básico. Este fichero de origen no tiene dependencias; durante el proceso lo adaptaremos y posteriormente iremos refinando la configuración hasta alcanzar una “mavenización” completa del proyecto.
Una vez colocado el pom.xml en el raíz de la aplicación, lo modificamos indicando el nombre del proyecto y la información básica relativa a los desarrolladores, organización y repositorio de dependencias utilizado.
Antes de continuar y añadir las dependencias, podemos hacer una comprobación previa y verificar que efectivamente nuestro IDE, en este caso Eclipse, reconoce correctamente la nueva estructura del proyecto.
Para ello nos vamos a la consola y en el directorio en el que se encuentra nuestro proyecto ejecutamos la siguiente orden:
mvn clean eclipse:eclipse
(Requiere disponer de Maven correctamente instalado en la máquina).
Si la configuración del entorno es correcta, obtendremos una salida similar a esta:
[INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'eclipse'. [INFO] ------------------------------------------------------------------------ [INFO] Building ejemplo [INFO] task-segment: [clean, eclipse:eclipse] [INFO] ------------------------------------------------------------------------ [INFO] [clean:clean] [INFO] Deleting file set: /home/felix/workspaces/ejemplo/target (included: [**], excluded: []) [INFO] Preparing eclipse:eclipse [INFO] No goals needed for project - skipping [INFO] [eclipse:eclipse] [INFO] Adding support for WTP version 1.5. [INFO] Using source status cache: /home/felix/workspaces/ejemplo/target/mvn-eclipse-cache.properties [INFO] File /home/felix/workspaces/ejemplo/.project already exists. Additional settings will be preserved, run mvn eclipse:clean if you want old settings to be removed. [INFO] Wrote Eclipse project for "ejemplo" to /home/felix/workspaces/ejemplo. [INFO] Sources for some artifacts are not available. Please run the same goal with the -DdownloadSources=true parameter in order to check remote repositories for sources. List of artifacts without a source archive: o javax.servlet:servlet-api:2.4 o javax.servlet.jsp:jsp-api:2.1 o junit:junit:3.8.1 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Wed Sep 3 11:54:28 CET 2008 [INFO] Final Memory: 10M/80M [INFO] ------------------------------------------------------------------------
Nos vamos a Eclipse, refrescamos el proyecto (F5 teniendo seleccionado el proyecto) y comprobamos que la nueva estructura es correcta.
Ahora que hemos comprobado que eclipse ha reconocido la nueva estructura, el siguiente paso es definir en nuestro pom.xml las dependencias. Para hacer esto eliminamos todos los .jar que se encuentran en el directorio /WEB-INF/lib y nos quedamos con una copia de ellos para posteriormente ir resolviendo las dependencias del proyecto original. Una recomendación es cortar la carpeta /WEB-INF/lib a otra ruta de nuestro disco.
Esta es la fase más delicada del proceso, ya que debemos asegurarnos de que todas las dependencias del proyecto quedan correctamente declaradas en el fichero pom.xml. Para realizar esta tarea es recomendadle utilizar alguna aplicación web que nos ayude a la localización de las librerías, como por ejemplo MvnRepository o MvnBrowser (recomendada), en la que podremos buscar cada uno de nuestros jar y encontrar la definición en el pom.xml que debemos utilizar.
Gracias a esta web, una vez que tengamos localizada la dependencia, solo tendremos que copiar el bloque POM Dependency a nuestro fichero pom.xml.
Iremos repitiendo este proceso de forma iterativa para todos nuestras librerías .jar y añadiendo la definición de la dependencia a nuestra zona de dependencies, con ciertas salvedades y consideraciones que introducimos a continuación.
Hay ocasiones en las que determinar la definición de la dependencia en nuestro pom.xml puede no ser una tarea trivial. Se comentan a continuación los mecanismos de actuación recomendados según diversas casuísticas:
Por ejemplo, podemos encontrarnos una librería llamada axis-ant.jar, por lo que tendremos que averiguar previamente la versión de la librería de cara a definir la dependencia en el fichero pom.xml. Para esto suele ser muy efectivo descomprimir la librería y consultar el fichero /META-INF/MANIFEST.MF. A modo de ejemplo, en dicha librería mencionada observaríamos una linea similar a la siguiente: “Implementation-Version: 1.2.1 2243 June 14 2005″. Una vez que conozcamos la versión podremos realizar la búsqueda de la forma usual. , 1.1.1.1. Sabemos que la librería fue generada por maven, pero no conocemos su definición.
No conocemos el groupId, artifactId, etc. Podemos descomprimir el .jar y acceder al fichero pom.xml que se encuentra en /META-INF/maven para comprobar el groupId, artifactId y versión de la dependencia.
Algunos jars, como por ejemplo servlet.jar, son aportados por el contenedor de aplicaciones, por lo que tendremos que definirlas marcándolas como provided. Esto le indica a Maven que estas librerías pueden ser utilizadas en tiempo de compilación, pero no serán agregadas al empaquetado final. Para declarar una dependencia de esta forma incorporaremos en nuestro pom.xml un código como este:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
Muchas de las dependencias dependen a su vez de otras librerías, por lo que Maven añadirá de forma transitiva nuevas librerías a nuestro proyecto. En estos casos no necesitamos definir estas nuevas dependencias transitivas en nuestro pom.xml. Como ejemplo, supongamos que un proyecto depende de estas librerías:
Al buscar la librería xalan-2-6.0.jar, observamos que la librería depende a su vez de las otras dos librerías. Por ello, para este ejemplo bastaría con declarar la dependencia a xalan-2-6.0.jar en nuestro pom.xml. 
En ocasiones nos podemos encontrar con que dos librerías tengan en sus dependencias a una misma tercera librería, pero de distinta versión. Ello haría que maven incluyese en nuestro Classpath 2 versiones de una misma librería, originando conflictos por duplicado de clases. En ese caso debe declararse en la dependencia de una de ellas una directiva para excluir la descarga de la librería conflictiva.
Por ejemplo, en un proyecto deseamos utilizar la librería siguiente:
<artifactId>jaxws-api</artifactId> <groupId>javax.xml.ws</groupId> <version>2.1-1</version>
Y tenemos dependencia a com.sun.xml.ws / jaxws-rt, esta librería se trae como dependencia transitiva otra versión de la librería mencionada anteriormente. Declaramos una exclusión para evitarlo:
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.4</version>
<exclusions>
<exclusion>
<artifactId>jaxws-api</artifactId>
<groupId>javax.xml.ws</groupId>
</exclusion>
</exclusions>
</dependency>
En esta situación, si la librería no parece problemática, podríamos optar por elegir la última versión de la dependencia. En el caso de que consideremos que la versión que utiliza el proyecto puede originar problemas, lo mejor es añadir esta librería manualmente a nuestro repositorio (como si fuese una librería específica del proyecto), según se explica en el próximo punto.
En estos casos tendremos que subir la dependencia a nuestro repositorio de librerías y, para evitar conflictos posteriores, se recomienda que sea subida con el mismo groupId de nuestro proyecto. Supongamos que migrando un proyecto nos topamos con librería example1.jar que no se encuentra en ningún repositorio público. En este caso la subimos a nuestro repositorio por ejemplo con la siguiente definición:
<dependency>
<groupId>com.viavansi.examples</groupId>
<artifactId>example1</artifactId>
<version>0.0.1</version>
</dependency>
En la siguiente figura vemos cómo desplegamos una librería a Artifactory:
Una vez que hayamos finalizado este proceso de definición de todas las dependencias en nuestro pom.xml, ejecutaremos en consola mvn dependency:tree (situados en el directorio donde se encuentre el fichero pom.xml del proyecto) para comprobar que las dependencias que se han incorporado al proyecto son las correctas. Este paso de verificación es muy importante en las migraciones de este tipo de proyectos, ya que es muy posible que alguna dependencia transitiva genere problemas. Como ejemplo, podemos observar la siguiente salida en la que comprobamos que no hay dependencias transitivas que entren en conflicto con alguna de nuestras librerías:
[INFO] [dependency:tree]
[INFO] com.viavansi.examples.examples1:war:0.0.1
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- javax.servlet.jsp:jsp-api:jar:2.1:provided
[INFO] +- javax.servlet:servlet-api:jar:2.4:provided (scope not updated to compile)
[INFO] +- javax.activation:activation:jar:1.1:compile
[INFO] +- avalon-framework:avalon-framework-impl:jar:4.1.5:compile
[INFO] +- axis:axis-ant:jar:1.2.1:compile
[INFO] +- axis:axis:jar:1.2.1:compile
[INFO] +- javax.mail:mail:jar:1.3.1:compile
[INFO] +- commons-beanutils:commons-beanutils:jar:1.6:compile
[INFO] +- commons-codec:commons-codec:jar:1.3:compile
[INFO] +- commons-collections:commons-collections:jar:3.2:compile
[INFO] +- commons-dbcp:commons-dbcp:jar:1.2.2:compile
[INFO] +- commons-digester:commons-digester:jar:1.6:compile
[INFO] | - xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] +- commons-discovery:commons-discovery:jar:0.2:compile
[INFO] +- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] +- commons-io:commons-io:jar:1.3.1:compile
[INFO] +- commons-lang:commons-lang:jar:2.2:compile
[INFO] +- commons-logging:commons-logging:jar:1.1:compile
[INFO] | +- logkit:logkit:jar:1.0.1:compile
[INFO] | - avalon-framework:avalon-framework:jar:4.1.3:compile
[INFO] +- commons-pool:commons-pool:jar:1.3:compile
[INFO] +- displaytag:displaytag:jar:1.1:compile
[INFO] +- displaytag:displaytag-export-poi:jar:1.1:compile
[INFO] +- dom4j:dom4j:jar:1.6.1:compile
[INFO] +- org.extremecomponents:extremecomponents:jar:1.0.1:compile
[INFO] +- com.lowagie:itext:jar:1.4.8:compile
[INFO] +- oro:oro:jar:2.0.7:compile
[INFO] +- javax.xml:jaxrpc-api:jar:1.1:compile
[INFO] +- javax.servlet:jstl:jar:1.1.2:compile
[INFO] +- log4j:log4j:jar:1.2.8:compile
[INFO] +- com.oracle:ojdbc14:jar:9.0.2.0.0:compile
[INFO] +- poi:poi:jar:2.5.1-final-20040804:compile
[INFO] +- javax.xml.soap:saaj-api:jar:1.2:compile
[INFO] +- org.springframework:spring:jar:2.0.5:compile
[INFO] +- taglibs:standard:jar:1.1.2:compile
[INFO] +- struts:struts:jar:1.2.9:compile
[INFO] | +- commons-fileupload:commons-fileupload:jar:1.0:compile
[INFO] | +- commons-validator:commons-validator:jar:1.1.4:compile
[INFO] | - antlr:antlr:jar:2.7.2:compile
[INFO] +- wsdl4j:wsdl4j:jar:1.5.1:compile
[INFO] +- wss4j:wss4j:jar:1.5.0:compile
[INFO] +- xalan:xalan:jar:2.6.0:compile
[INFO] +- org.apache.xmlgraphics:xmlgraphics-commons:jar:1.2:compile
[INFO] +- xml-security:xmlsec:jar:1.2.1:compile
[INFO] +- org.directwebremoting:dwr:jar:2.0.3:compile
[INFO] +- com.viavansi:plantilla-client:jar:0.0.13:compile
[INFO] +- net.sourceforge.barbecue:barbecue:jar:1.5-beta1:compile
En caso de detectar librerías duplicadas a causa de las dependencias transitivas, deberemos proceder a definir las exclusiones necesarias en las dependencias afectadas, según se indicó anteriormente.
11 oct 2009
Durante el proceso de análisis de un determinado software, y en el caso concreto de aplicaciones web, resulta muy útil elaborar un prototipo de la aplicación (también llamado wireframe) que plasme la idea que el cliente intenta transmitir, para así validarla antes de pasar al desarrollo de la misma.
Prototipo como parte del contrato
Este prototipo debería ser un documento más del análisis que al ser aprobado por el cliente supondrá un compromiso tanto por parte de la empresa desarrolladora de ofrecer una solución software que refleje lo que en el prototipo se especificaba, como por parte del cliente que no debería modificar lo allí reflejado una vez comenzado el desarrollo.
Un arma de doble filo
Las ventajas son innumerables pero hay que tener cuidado; el prototipo es un arma de doble filo que se puede volver en tu contra, ya que un mal prototipo puede ser peor que la ausencia total de él en el análisis. Un prototipo debe ser muy claro en la funcionalidad, preciso, detallado y fiel a la realidad en todos los sentidos. Debe quedar recogido el comportamiento de la aplicación en todos los casos, complementando las pantallas con notas y anexos explicativos de cada funcionalidad de la aplicación.
El riesgo que tiene no dejar cerrados todos los puntos es muy alto para el proveedor de aplicaciones, ya que el cliente podría pedir cierta funcionalidad de la aplicación que “parecía que iba a ser incluida” viendo el prototipo. Este tipo de malentendidos son evitables, como he dicho antes, con el suficiente esmero en la elaboración del prototipo. El tiempo invertido, como todo el que se invierte en fase de análisis, suele ser amortizado con un desarrollo más corto, menos problemático y con menos cambios por parte del cliente.
Herramientas de prototipado
Existe numerosas aplicaciones que nos ayudarán a la hora de crear un prototipo, de pago o gratuitas, multiplataformas o no, herramientas web o de escritorio; el abanico es muy extenso, ya que lo podemos realizar con aplicaciones cuyo propósito principal no fuesen los prototipos de aplicaciones informáticas.
A veces, lo más cómodo es utilizar una herramienta con la que ya estemos familiarizados, como podría ser un editor de presentaciones de alguna suite ofimática (PowerPoint por ejemplo) o algún software de gráficos vectoriales (FreeHand, FireWorks, Visio, etc). Pero también existe un amplio mercado de aplicaciones específicas. Algunas de las más conocidas son:
Vía web: Pencil (plugin para Firefox con licencia GPL), iPlotz (con varios planes de pago).
Escritorio: WireframeSketcher (plugin para Eclipse, económico), JumpChart (con herramientas colaborativas), Axure (muy interesante, pero caro y sólo para Windows), Justinmind Prototyper (para Windows y Mac, bastante caro), Gliffy (además de wireframe, permite otros diagramas como MS Visio).