Maven
Por qué se necesita una herramienta de build
Sección titulada «Por qué se necesita una herramienta de build»En un proyecto de software donde trabaja más de un desarrollador existen: muchos archivos de código fuente, datos de configuración de herramientas y frameworks, y librerías —de terceros y propias— con dependencias entre ellas y entre sus versiones.
Construir un ejecutable es más que compilar: implica empaquetar, probar y —eventualmente— desplegar, con toda la complejidad que trae el servidor de destino, la base de datos, la seguridad. Para que un equipo funcione, ese proceso tiene que ser igual, repetible y automatizado para todos sus integrantes; si no lo es, cada desarrollador puede terminar usando versiones distintas de una librería, empaquetando fuentes distintas, o entregando algo que nunca se probó.
De un build tool esperamos dos servicios:
- Soporte al ciclo de vida del ejecutable: compilar, empaquetar, probar, desplegar, ejecutar.
- Manejo de librerías y dependencias.
En nuestros proyectos usamos Maven para el backend en Java/Spring Boot, y npm para el frontend en Angular — cada lenguaje trae su propia herramienta, y ambas cubren los dos servicios anteriores.
¿Qué es Maven?
Sección titulada «¿Qué es Maven?»Maven nació dentro de Apache: su primer prototipo apareció en 2001, y en 2002 Jason van Zyl reunió esas ideas en la herramienta que se liberó como versión 1.0 en 2004 (ver la historia de Maven). Hoy sigue siendo, junto con Gradle, una de las dos herramientas de build más usadas para proyectos Java.
Maven da soporte a:
- Administrar las librerías y sus versiones, propias y de terceros.
- Definir el proceso de construcción y automatizarlo.
- Manejar las dependencias entre los distintos módulos de un proyecto.
- Reportar y documentar el proceso y sus resultados.
Además, se integra con otras herramientas para que ese proceso de construcción incluya, por ejemplo, ejecutar pruebas, generar código, desplegar la aplicación, o alimentar tableros de calidad como SonarQube. Por eso Maven es una pieza clave de la Integración Continua en proyectos Java: es lo que la herramienta de CI ejecuta automáticamente en cada push.
Módulos y artefactos
Sección titulada «Módulos y artefactos»En Maven, un módulo es un proyecto — y su tipo determina el artefacto que se construye a partir de sus fuentes: el resultado final de la construcción, listo para desplegarse. Un artefacto es un archivo empaquetado según una estructura estándar; los empaquetados más comunes son:
| Empaquetado | Para qué |
|---|---|
.jar |
Una librería Java, o una aplicación Spring Boot ejecutable (con su servidor embebido adentro) |
.war |
Una aplicación web pensada para desplegarse en un application server externo |
.ear |
Un paquete que agrupa varios .war/.jar para desplegarlos juntos en un application server JEE |
Cada módulo tiene un archivo pom.xml (Project Object Model) que declara su tipo, su identificación, sus dependencias y su configuración de build, en el dialecto XML que define Maven (ver la referencia de pom.xml).
Identificación de artefactos: el GAV
Sección titulada «Identificación de artefactos: el GAV»Un artefacto Maven se identifica de forma única con tres datos, su GAV:
- Group Id: agrupa los proyectos relacionados —típicamente el nombre de la organización o de la aplicación—. Debe ser único a nivel mundial.
- Artifact Id: el nombre del componente o proyecto puntual.
- Version: la versión de ese componente.
<project> <modelVersion>4.0.0</modelVersion> <groupId>co.edu.uniandes.dsw.books</groupId> <artifactId>books-api</artifactId> <version>1.0-SNAPSHOT</version></project>A eso se le agregan el empaquetado y el nombre del proyecto:
<project> <modelVersion>4.0.0</modelVersion> <groupId>co.edu.uniandes.dsw.books</groupId> <artifactId>books-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>books-api</name></project>Proyectos multimódulo
Sección titulada «Proyectos multimódulo»Un producto puede estar compuesto por varios módulos. En nuestro proyecto Book, por ejemplo, un pom.xml padre puede agrupar el módulo del API y el módulo web:
<project> <modelVersion>4.0.0</modelVersion> <groupId>co.edu.uniandes.dsw.books</groupId> <artifactId>books</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging>
<modules> <module>books-api</module> <module>books-web</module> </modules></project>Cuando corres una acción de Maven sobre el proyecto padre —como mvn package—, esa acción se ejecuta sobre cada uno de sus módulos.
Herencia entre archivos POM
Sección titulada «Herencia entre archivos POM»Un módulo hijo puede declarar el padre como <parent>, y así heredar sus dependencias, plugins y configuración sin tener que repetirlos en cada módulo:
<project> <modelVersion>4.0.0</modelVersion> <artifactId>books-api</artifactId>
<parent> <groupId>co.edu.uniandes.dsw.books</groupId> <artifactId>books</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> </dependencies></project>El ciclo de vida de Maven
Sección titulada «El ciclo de vida de Maven»Maven ejecuta las tareas de construcción en fases, siempre en el mismo orden. Estas son las principales del ciclo de vida por defecto:
flowchart LR
A[compile] --> B[test] --> C[package] --> D[verify] --> E[install] --> F[deploy]
| Fase | Qué hace |
|---|---|
compile |
Compila el código fuente principal |
test |
Corre las pruebas unitarias |
package |
Empaqueta el artefacto (.jar, .war, …) |
verify |
Corre validaciones sobre el paquete, por ejemplo pruebas de integración |
install |
Copia el artefacto al repositorio local, para que otros proyectos en la misma máquina lo puedan usar |
deploy |
Copia el artefacto a un repositorio remoto, para compartirlo con el equipo |
Manejo de dependencias
Sección titulada «Manejo de dependencias»Repositorios de dependencias
Sección titulada «Repositorios de dependencias»Maven guarda los artefactos —los propios y los de terceros— en repositorios, y los identifica por su GAV. Hay tres niveles:
- Local: en la máquina del desarrollador, en la carpeta
.m2. Es lo primero que Maven consulta cuando necesita una dependencia. - Central (o global): el repositorio público de Maven, con las librerías de uso compartido más comunes. Se puede explorar en Maven Central.
- Empresarial: un repositorio propio de la organización —herramientas como Nexus o Artifactory son las más usadas hoy— para librerías internas, o como caché de Maven Central.
Si una dependencia no está en el repositorio local, Maven la busca en los repositorios remotos configurados —el repositorio empresarial, si el proyecto tiene uno, o directamente Maven Central— y la descarga a .m2 para no tener que volver a pedirla.
Definición de una dependencia
Sección titulada «Definición de una dependencia»Una dependencia se declara con su GAV, su tipo de empaquetado, y un scope: cuándo se necesita.
| Scope | Cuándo se necesita |
|---|---|
compile (por defecto) |
Siempre: en el proyecto y en los proyectos que dependen de él |
provided |
Se espera que el JDK o el servidor ya la provean; no se empaqueta con la aplicación |
runtime |
No hace falta para compilar, pero sí para ejecutar (por ejemplo, un driver JDBC) |
test |
Solo al compilar y correr las pruebas |
system |
Como provided, pero apuntando manualmente a un .jar local en disco |
import |
Importa las dependencias declaradas en el pom.xml de otro proyecto (típico con un BOM, como spring-boot-dependencies) |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency>