Explicación básica de Maven

Maven es una herramienta de build, posiblemente la más utilizada en la actualidad en el mundo Java.

Una herramienta de build es un herramienta que permite “buildear” un proyecto. “Buildear” (ejecutar un proceso de build) implica ejecutar un conjunto de tareas las cuales pueden variar dependiendo de cada proyecto. En el caso más básico el proceso de build implica tan solo compilar. En casos más avanzados el build implica ejecucar algunas otras tareas como ser: resolución de dependencias (previo a la compilación), verificación de estándares de codificación, ejecución de pruebas automatizadas, generación de paquetes binarios, etc.

En algunos casos las herramientas de build pueden utilizarse con distintos lenguajes de programación, pero en general cada lenguaje de programación tiene alguna herramienta de build “preferida”. Entre las herramientas de build más populares en la actualidad se encuentran:

  • Maven, Ant y Gradle (Java y derivados)
  • MSBuild y NAnt (C#)
  • Grunt y Gulp (JavaScript)
  • Rake (Ruby)

Algunas herramientas de Build funcionan con un conjunto de tareas predefinidas (que pueden extenderse), mientras que otras dependen completamente de la definición que haga el usuario.

Todas estas herramientas de build toman como entrada un archivo que describe generalidades del proyecto a buildear (cosas como nombre del proyecto, autor, versión, etc) y la lista de tareas a ejecutar.

Maven es una de las herramientas de build que ya trae un conjunto de tareas predeterminadas. Más concretamente Maven define lo que llama un ciclo de vida, el cual incluye diversas fases y tareas asociadas a cada una. Al mismo tiempo Maven define un serie de convenciones respecto de la estructura de carpetas del proyecto. Entonces para usar Maven deberemos:

  1. Crear una estructura de directorios acorde a lo definido por Maven (en realidad la estructura exacta depende del tipo de arquetipo utilizado, pero ello es un tema avanzado)
  2. Incluir en la raíz del directorio un archivo llamado pom.xml que describa nuestro proyecto
  3. Ejecutar Maven indicando la fase deseada. Aquí debemos tener presente que cuando indicamos una fase, Maven ejecutará la fase indicada pero previamente ejecutará todas las fases anteriores. O sea, cuando uno le indica a Maven una fase X, lo que le está diciendo es: quiero ejecutar el ciclo de vida completo hasta la fase X

 

Un caso robusto de integración contínua en Java

En el proyecto en el que he estado trabajando los últimos meses tenemos montado un proceso de integración continua bastante completo en mi opinión, comparto aquí algunos detalles. Se trata de un proyecto Java, basado en Spring, Hibernate, Camel y algunos otros frameworks. A nivel de herramientas tenemos quality checks con PMD, pruebas unitarias y de aceptación con JUnit y pruebas de aceptación y carga con JMeter. Como herramienta de build usamos Maven, como servidor de integración continua usamos Jenkins y el código lo tenemos en Git (gitlab). Al mismo tiempo tenemos un ambiente de tests en la nube donde desplegamos nuestra aplicación periódicamente. También tenemos un ambiente de prueba en las oficinas del cliente, donde desplegamos nuestra aplicación al final de cada iteración. En el jenkins tenemos varios jobs:

  • integración continua: monitorea el branch develop y ante cada cambio compila, ejecuta las pruebas de JUnit (unitarias y de integración)
  • quality-check: se ejecuta a continuación del job de integración continua y caso_java_jenkins_2básicamente ejecuta análisis de código (pmd)
  • integración continua de branches: en algunos casos creamos feature-branches, para lo cual seguimos una convención de nombres y este job se encarga de ejecutar integración continua sobre estos branches. En general procuramos que estos branches no vivan más de 3 días.
  • inicialización: es el job que dispara el build pipeline, y como tal comienza por inicializar el ambiente de test. Se ejecuta periódicamente (varias veces al dia siempre que haya cambios en el repositorio)
  • deploy: son dos jobs que se encargan de desplegar las dos aplicaciones que forman parte de nuestro sistema.
  • pruebas de aceptación: ejecuta las pruebas de aceptación (codeadas con jmeter) luego de cada despliegue
  • pruebas de carga: ejecuta un conjunto de pruebas de carga. Este job lo ejecutamos manualmente al menos una vez por iteración para asegurarnos que los cambios realizados no haya impactado en la performance del sistema
  • generador de release: este job lo ejecutamos manualmente al final de cada iteración para generar un nuevo release lo cual implica: taggear el repo, generar y publicar los artefactos (wars y jars) y actualizar la versión en los archivos del proyecto (pom.xml)
  • generador de instalable: este job toma  los artefactos generados por el job de generación de release y los empaqueta junto con un grupo de scripts que luego se utilizarán para instalar  el sistema en los ambientes del cliente.

caso_java_jenkins