Publica tu how-to

Dinos como hacer lo que sabes hacer, mándanos un email a wdonet@gmail.com y lo publicamos (dos días máximo) o si te interesa unirte al equipo de redactores, también háznoslo saber por correo.

Repositorios en Maven

Maven se coordina mediante cuatro elementos, los cuales definen una dirección para un punto específico desde lo general a lo específico.
  1. groupId, se refiere al grupo, compañía, equipo u organización, considerando la convención para identificadores de grupo, el cual dicta que estos empiecen con el nombre de dominio de la organización en reversa, esto es com.santander para banco Santander por ejemplo.
  2. artifactId, un identificador único para el grupo que permita ubicar al proyecto. Generalmente es el nombre del proyecto
  3. version, un número específico para cada liberación del proyecto y se recomienda un identificador especial para proyectos en desarrollo (SNAPSHOT), y
  4. packaging, define el tipo de proyecto que al final es la salida producida, por defecto es 'jar', el cual produce un paquete .jar.
Una vez que se instala el proyecto en el repositorio local de maven, éste queda disponible localmente para su uso en cualquier otro proyecto local. Por ejemplo, así se define la ruta que maven utiliza para almacenar un artefacto:
/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>
Maven además de instalar el paquete en el repositorio seleccionado, también copia el pom.xml del proyecto en la misma ruta con el mismo nombre del paquete pero con extensión .pom y crea un archivo en la ruta hasta el artifactId llamado maven-metadata.xml con la identificación de grupo, artefacto y versiones disponibles.  Esto ese algo útil para maven puesto que permite la inclusión recursiva de paquetes dependientes (dependencies).  Por ejemplo, si defines una dependencia en el pom de tu proyecto hacia el paquete commons-email-1.1.jar y éste a su vez depende del paquete subethasmtp-smtp-1.2.jar (dependencia transitoria), ambos paquetes se descargan automáticamente a tu repositorio local cuando compilas tu proyecto.  De esta manera maven resuelve las dependencias de forma recursiva y con base a archivos checksum (archivos con mismo nombre pero extensión .md5) descarga lo que no se encuentre localmente.  Así también si varios proyectos locales requieren de las mismas dependencias, estas se copian al paquete del proyecto (en el caso de un war o ear por ejemplo) cuando se instalan en el repositorio.

Así mismo, una dependencia se puede incluir en cierto alcance (scope), por ejemplo pruebas (test), de manera que cuando se ejecute una prueba o todo el conjunto de pruebas del proyecto, se utilice dicha dependencia, pero no al momento de compilar. ejemplo JUnit:
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
            </dependency>
        <dependency>

solo se utilizaría la dependencia al ejecutar una prueba: mvn test -Dtest=MiPruebaTest o el conjunto de ellas: mvn test

Esto obligaría a que cuando se construya el paquete war o ear no se incluya la dependencia.  Otra forma de eviar que se incluya la dependencia en el paquete del proyecto es asignándole un alcance provided scope, el cual le dice a maven que es necesario para compilar, pero no debe se incluido en la construcción final del proyecto. Es útil por ejemplo cuando desarrollas una aplicación web y necesitas el jar de la API de Servlet para compilar, pero no par incluirla en el paquete final.

Servidor Linux desde tu hogar en tres pasos

Una de las ventajas que tiene Linux como sistema operativo es su facilidad y estabilidad al momento de utilizarlo como servidor. Actualmente en el mundo Linux es uno de los sistemas operativos a la cabeza en lo que a elección de sistema se refiere para tener un servidor de múltiples plataformas en Internet (web, ftp, correo electronico, etc.)

Pero lo que es menos conocido es que, en la práctica, cualquier máquina con un sistema Linux puede ser configurada (tanto en S.O. como en la red local) para funcionar como un servidor visible al amplio mundo externo de Internet.

En lo particular, yo lo utilizo tanto como un juguete para hacer experimentos y aprender sobre servidores, como de repente para algunas cosas útiles como tomar un archivo que tengo en mi casa a la hora de navegar por internet desde mi oficina o cualquier otro lugar, para iniciar sesión remota y trabajar en mis pendientes desde fuera de mi hogar, para versionar algunos proyectos que mantengo, entre otras cosas.

Usos de comando grep

El comando grep te ayuda a buscar un archivo, grupo de archivos, directorios o contenido de archivos mediante un patrón que puede ser una palabra, letra o una expresión regular.
La forma básica de este comando es como abajo se indica, donde lo encerrado entre comillas es la cadena a buscar y archivo.txt es el archivo dentro del cual se desea buscar.

grep "cadena a buscar" archivo.txt

Sin embargo, el comando grep tiene muchas más formas de ser mejor aprovechado y aquí listo algunas de ellas:
  • Para una búsqueda insensible a mayúsculas / minúsculas
grep -i "cadena a buscar" archivo.txt
  • La cadena a buscar puede ser también una expresión regular donde se pueden aprovechar los siguientes caracteres para significados especiales
    • ? - indica que el elemento anterior es opcional y puede aparecer al menos 1 vez
    • * - indica que el elemento anterior puede aparecer 0 o más veces
    • + - indica que el elemento anterior puede aparecer 1 o más veces
    • {n} - indica que el elemento anterior debe aparecer exactamente n veces
    • {n,} - indica que el elemento anterior puede aparecer n o más veces
    • {,m} - indica que el elemento anterior debe aparecer al menos m veces
    • {n,m} - indica que el elemento anterior debe aparecer al menos n veces, pero no más de m.

Patrón de Diseño Command

El patrón comando permite que solicitudes del cliente sean encapsuladas como objetos, indicar parámetros a diferentes solicitudes, encolarlas, registrarlas y hasta dar soporte para operaciones des-hacer.
Participantes:

Uso de mount para montar dispositivos de almacenamiento en Linux

El comando mount nos permite cargar un sistema de archivos, de cualquier dispositivo periférico o carpeta compartida en la red, en nuestro sistema linux y visualizarlo desde una carpeta de nuestro sistema. Esto, muchas veces los ambientes gráficos permiten hacerlo de manera automática, pero es importante conocer que se hace debajo o por lo menos como está trabajando.

Para empezar, debemos conocer como se clasifican los dispositivos. Te recomiendo esta presentación en PDF como introducción. Los canales más conocidos y casi de salida son los IDE, de los cuales hay dos por lo general en cada tarjeta madre, y de estos dos clasificaciones maestro y esclavo, por tanto:
  • /dev/hda - corresponde al canal primario configurado como maestro, si existen particiones, solo pueden existir hasta cuatro primarias y se enumeran hda1 .. hda4, de las cuales una puede ser extendida y dentro de ésta máximo 16 unidades lógicas, de las cuales siguen la numeración desde 5, esto es hda5 .. hda21. Lo mismo se hace para los otros canales IDE si fueran discos duros (hdb, hdc y hdd).
  • /dev/hdb - corresponde al canal primario configurado como esclavo
  • /dev/hdc - corresponde al canal secundario configurado como maestro
  • /dev/hdd - corresponde al canal secundario configurado como esclavo

Usos de comando find en linux

Para ejecutar el comando find, debes conocer lo siguiente:
  • Por defecto, el comando find, busca en la ruta actual y todos sus subdirectorios. No obstante se pueden modificar estas características y otras más según la tabla abajo descrita.
  • Se pueden encadenar los resultados de find con pipe '|' para manipular los resultados. Ejemplo, mostrar los 3 archivos mas grandes del sistema
    • find / -type f -exec ls -s {} \; | grep sort -n -r | head 3
  • Cada archivo, carpeta, enlace simbólico o duro, etc., es guardado en el sistema de archivos con un numero irrepetible conocido como 'inode', de esta manera podemos tener dos o mas archivos con nombres similares pero inodes distintos.
Ejemplo: "archivo1.txt", "archivo1 .txt" y "archivo1.txt " [Noten los espacios]. No obstante, al mostrarlos como 'ls -i1 archivo*' se mostraría algo como esto:
16187429 archivo1.txt
16187430 archivo1 .txt
16187431 archivo1.txt

Configurando log4j

Log4j tiene los siguientes niveles de traza que se definen con el tag <priority>:
  • OFF: no se muestra en ningún mensaje (se encuentra apagado)
  • FATAL: para mostrar mensajes de situaciones que probablemente harán abortar la aplicación
  • ERROR: para mostrar mensajes de errores que no son deseados pero que no interrumpirán la aplicación.
  • WARN: para mostrar mensajes de contextos peligrosos para la aplicación, o ciertas operaciones de uso no recomendado
  • INFO: para mostrar mensajes de información sobre la ejecución de la aplicación, o eventos importantes dentro de la misma
  • DEBUG: para mostrar mensajes interesantes para depurar la aplicación. Para la etapa de desarrollo.
  • ALL: se muestra en todos los casos
Se puede configurar en tres formas, con código Java, con archivo .properties o un archivo .xml, En esta ocasión veremos un xml debido que es más fácil para algunos desarrolladores, aunque yo me acomodo mejor con un .properties.

Uso de APT en Linux Debian, Ubuntu o Mint

APT es el acrónimo de Advanced Packaging Tool, el sistema de gestión de paquetes utilizado en Debian y sus derivados, como Ubuntu. Tanto aptitude como Synaptic o Adept se basan en este sistema.

dpkg es el programa base en el cual se apoya la gestión de paquetes Debian y las distribuciones derivadas. Permite instalar/desinstalar programas en forma de paquetes .deb (similar a los .rpm de RedHat o Fedora) y consultar información sobre ellos.

Para instalar un paquete
dpkg -i paquete.deb
Listar el contenido de un paquete
dpkg -L paquete
(usa grep para buscar un archivo o folder)
Para saber a que paquete pertenece un archivo
dpkg -S archivo.cfg
Listar paquetes instalados en el sistema
dpkg -l
Para reconfigurar un paquete (fase en la que se inician/paran servicios, crean archivos log, etc)
dpkg-reconfigure paquete
Buscar paquetes por palabras
aptitude search texto_a_buscar
Impedir que un paquete se actualice
aptitude hold paquete
Actualizar del sistema todos los paquetes a sus nuevas versiones sin involucrar aquellos que requieran nuevos paquetes o eliminarlos
aptitude upgrade ó
apt-get upgrade
Actualizar todos los paquetes del sistema, incluyendo aquellos que si requieren nuevos paquetes o eliminar otros
aptitude dist-upgrade ó
apt-get dist-upgrade
Para solicitar información de un paquete, esté o no instalado
aptitude show paquete

El equipo de Debian recomienda usar aptitude en lugar de apt-get.

Observaciones sobre Pruebas Unitarias

Analizando las constantes e incansables ocasiones que nuestro líder de proyecto habla sobre la necesidad de hacer pruebas unitarias (automatizadas), y que no siempre estuve de acuerdo, dado el tiempo que se requiere para construirlas y que en la mayoría de las veces, las fechas de entrega negociadas con el cliente nos ahorcan en los tiempos que podemos dedicar a esta práctica, me he dado cuenta de lo siguiente.

Evidentemente sería mucho más útil tener pruebas unitarias que se construyan desde un principio para que en la vida del proyecto se ejecuten periódicamente y nos aseguremos que las partes de dicho proyecto siguen funcionando como deben, independientemente de la integración de nuevos módulos, refactoring de clases, optimización de código e inclusive corrección de estilo.

Pero para lograrlo y evitar el tedio al realizar las pruebas unitarias considero que hay que pensar en lo siguiente:
  1. Para no hacer esfuerzos sin ganancia, es absolutamente necesario planear los puntos críticos a probar unitariamente en los distintos módulos del proyecto.
  2. Así como los Casos de Uso se desarrollan antes que el diseño y los diagramas UML preceden a la construcción de un proyecto, es vital que las pruebas unitarias se armen antes de la construcción.
  3. No es necesario crear una prueba unitaria por cada Dao, Servicio, Pojo, Controller, ViewHelper o Utilería habido o por haber.
  4. Las pruebas que deberían automatizarse son aquellas que tienen una mayor probabilidad de no cambiar (en concepto) a lo largo del proyecto. Cuando sea necesario integrar ajustes nuevos y provoquen un fallo en las pruebas automatizadas ya existentes, se pueden actualizar dichas pruebas con cambios mínimos para mantenerlas como símbolo de que nuestro sigue funcionando con los requerimientos de un principio.
  5. Es necesaria una comunicación plena en el equipo de desarrollo por cuestiones de conflictos de actualizaciones, sobre todo si se esta trabajando en el mismo repositorio y los cambios de uno afectan a las pruebas unitarias de otro.
  6. Para visualizar el correcto funcionamiento de una prueba unitaria y localizar el error si esta falla (sin hacer debug) es realizar un correcto logging, de manera que éste mismo explique claramente la etapa que transcurre (con datos self-explaining) y compruebe el estado del proceso en ejecución.
  7. Es importante contar con un grupo de herramientas adecuadas que nos permitan conectarnos a base de datos y trabajar con datos, simular comportamientos de servicios no-tan-fácilmente-probables, acceder a archivos y verificar su contenido y un grupo de agregados para comprobar los resultados de cada prueba. Quizá funcionen como adaptadores, servicios, factories o daos dedicados exclusivamente para comprobar cosas. Junit tiene un addons que se ve bastante bien.
  8. El que las pruebas unitarias estén correctamente automatizadas y con un adecuado logging (incluyendo los elementos a probar) implica que ya no es necesario hacer debugging para encontrar los errores (algo que solo se puede hacer manualmente).
Una vez planeado así, podríamos ver los resultados que dice el articulo de jamesgolick en su apartado "Breaking Even" : 'si te cuesta 20min. construir una prueba automatizada y 1min. una prueba manual, llegar al punto critico para compararlas es que probases manualmente 20 veces; después de eso, la prueba automatizada se vuelve mucho mas barata y la manual obviamente mas cara, disparándose ambas en sentido contrarios'.

Ustedes que piensan? alguna otra recomendación?

Buenas prácticas con Spring

  1. No abusar de las inyecciones
  2. Utilizar inyecciones por dependencias (setter) en vez de por constructor
  3. Agregar una descripcion al archivo de configuracion xml y notificar al equipo sobre los cambios realizados
  4. Usar ids como identificadores de beans
  5. Integrar archivos de configuración mediante ApplicationContext y no usar imports de xml
  6. Reutilizar definiciones de beans
  7. Si se usa inyección por constructor, utilizar TYPE en vez de INDEX para los argumentos del constructor
  8. Usar convenciones de nomenclatura para nombrar los beans
  9. Evitar el uso de autowiring
Leer más en dosIdeas

Instalar un artefacto en el repositorio de maven

Para instalar un artefacto en un repositorio local de maven. Por lo general lo copia en el directorio home_del_usuario/.m2/repository/, salvo los ajustes que hagamos en archivo de configuración de maven: settings.xml.

mvn clean install

Para instalar un artefacto de terceros hacer:

mvn install:install-file -Dfile=foo.jar -DgroupId=org.empresa -DartifactId=foo -Dversion=1.2.3 -Dpackaging=jar

Para instalar un artefacto en un repositorio remoto de maven.

mvn deploy:deploy-file -Dfile=foo.jar -DgroupId=org.empresa -DartifactId=foo -Dversion=1.2.3 -Dpackaging=jar -DrepositoryId=focus-repository -Durl=scp://host/home/mvn/public_html/repository

Intro comandos Maven 2.0

Para obtener ayuda del comando de Maven 2:
mvn --help

Sintaxis general:
mvn plugin:target [-Doption1 -Doption2 ...]

Para crear un proyecto JAR:
mvn archetype:create -DgroupId=com.empresa.proyecto -DartifactId=nombreAplicacionJAR
* Si vas a crear un módulo dentro de otro proyecto maven previamente creado, debes ejecutar el mismo comando pero dentro o al nivel raiz del proyecto que va a contener dicho módulo, automáticmante maven, hace que el nuevo proyecto sea módulo del proyecto a nivel raíz en el que te encuentras parado.
Observa el tag en el pom.xml del proyecto padre y el tag del proyecto hijo después de ejecutar el comando.
Para crear un proyecto WAR: