Gestión del versionado en proyectos multimódulo

Publicado por Jaime Martínez el

Arquitectura de SolucionesMavenVersionado

En este artículo vamos a ver como actualizar el versionado en proyectos multimódulo gestionados por maven.

cabecera - Enmilocalfunciona - Maven - 1400x400px.jpg

Este tipo de proyectos es bastante útil trabajando en el desarrollo de arquitecturas, frameworks o cuando se está realizando un aplicativo que se compone de distintos componentes y se quieren gestionar de una manera conjunta,
bien sea por un manejo de dependencias común o por tener unas características comunes que se quieren compartir de manera centralizada.

Inicialmente daremos un repaso (o iniciación para quien no lo conozca) por los aspectos básicos necesarios para cubrir este caso, como es hablar sobre maven y qué es un proyecto multimódulo en sí.

Posteriormente veremos un ejemplo de proyecto de estas características y cómo se podría actualizar tanto manualmente (ejemplo de lo que se quiere evitar, sobre todo en proyectos con muchos componentetes) o mediante el uso de comandos de maven o de plugins.

Por último, incluiremos las referencias a la documentación oficial.

Breve introducción a maven

Maven es una herramienta que nos facilita el desarrollo de software. A la hora de construir un aplicativo es normal hacer uso de librerías, éstas pueden ser tanto propias como de terceros y formarán parte de nuestro software.

Esta gestión de dependencias, es facilitada por maven, ya que mediante la definición de un fichero xml (pom.xml) podremos hacer referencia a todas ellas y será maven el encargado de incluirlas en nuestro proyecto.

Así mismo junto con otras herramientas no solo se realiza la gestión de dependencias a nivel de proyecto, sino que mediante el uso de repositorios se centraliza la distribución de las mismas en sus distintas versiones.

Por otro lado, junto a este manejo de dependencias, maven también se encarga de las distintas fases del ciclo de vida del software, como es la construcción del proyecto, la ejecución de tests o la publicación del mismo en los repositorios centrales que comentábamos anteriormente.

Como maven se encarga de la construcción de nuestro software, es necesario decirle qué estamos construyendo, para ello dentro de la definición del mismo en el fichero pom.xml tenemos una sección denominada packaging que sirve para esta función. Sin entrar en excesivo detalle y centrándonos en el caso actual comentar que existen, entre otros, los siguientes tipos:

  • pom: sirve como módulo principal y se compone de uno o más submódulos.
  • jar: es un módulo que acabará generando un artefacto de tipo jar, el cual podrá ser utilizado como librería o aplicativo dependiendo de su funcionalidad.

Para finalizar diremos que maven se basa en la ejecución de distintos plugins cada uno de ellos con un propósito definido, como puede ser la ejecución de tests o la compilación del proyecto.

¿Qué es un proyecto multimódulo?

Cuando uno piensa en una aplicación pensamos en un todo, pero realmente ésta se compone de varias partes que la forman como módulos. Incluso anteriormente cuando los aplicativos eran monolitos, interiormente se construían a partir de distintas piezas que eran gestionadas desde el principal.

Esto trasladado a Maven da lugar a la creación de un proyecto padre, en el cual se referencian el resto de módulos. A su vez, cada uno de estos módulos pueden contener a otros dando una estructura jerárquica y permitiendo una gestión común de todos ellos.

A modo de ejemplo, y para el caso que nos aplica, se va a utilizar de base el siguiente caso:

  • El módulo principal multimodule, que se compone a su vez del group-modules-1 y group-modules-2.
  • Los módulos anteriormente mencionados que a su vez se componen de module-1 y module-2 respectivamente.
  • Los módulos finales module-1 y module-2.

Todo ello se explica en detalle en el siguiente punto.

Ejemplo de proyecto multimódulo

El caso que nos aplica (definido brevemente en el punto anterior) daría lugar a un proyecto con la siguiente estructura. Para simplificar, se va a incluir en cada módulo o submódulo unicamente el fichero pom.xml.

estructura.png

Como se observa en la imagen cada módulo que contiene a otros submódulos va conformando la jerarquía del proyecto mediante la anidación en distintas carpetas. Esto mismo se puede observar en los distintos pom.xml

A continuación, pasamos a ver la estructura de los ficheros pom.xml de cada componente.

multimodule

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>multimodule</artifactId>
    <version>1.0-SNAPSHOT</version>
	<packaging>pom</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <modules>
		<module>group-modules-1</module>
		<module>group-modules-2</module>
	</modules>
</project>

Los puntos más relevantes son:

  • groupId, artifactId, version y packaging: esto define a nuestro módulo, mediante el groupId y artifactId tenemos la referencia a él (debe ser única), con la opción de packaging indicaremos de que tipo es y por último con la versión gestionaremos la evolución del mismo.
  • properties: permite definir una serie de propiedades, en este caso la codificación y la versión de java, que pueden ser reutilizadas por sus submódulos.
  • modules: aquí se referencia que módulos lo componen.

group-modules-1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example</groupId>
		<artifactId>multimodule</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules</groupId>
    <artifactId>group-modules-1</artifactId>
	<packaging>pom</packaging>

    <modules>
		<module>module-1</module>
	</modules>
</project>

En este caso aparte de lo mencionado anteriormente, se observa el siguiente apartado:

  • parent: el cual indica cual de que módulo padre formamos parte, identificándolo con los apartados que lo definen (groupId, artifactId y version).

A continuación, se muestran el resto de módulos, que contienen los puntos anteriores con la información relativa a cada uno de ellos.

module-1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example.modules</groupId>
		<artifactId>group-modules-1</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules.group1</groupId>
    <artifactId>module-1</artifactId>
	<packaging>jar</packaging>
	
</project>

group-modules-2

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example</groupId>
		<artifactId>multimodule</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules</groupId>
    <artifactId>group-modules-2</artifactId>
	<packaging>pom</packaging>

    <modules>
		<module>module-2</module>
	</modules>
</project>

module-2

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example.modules</groupId>
		<artifactId>group-modules-2</artifactId>
		<version>1.0-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules.group1</groupId>
    <artifactId>module-2</artifactId>
	<packaging>jar</packaging>
	
</project>

Con esto tenemos la estructura completa del proyecto, a continuación pasaremos a ver como gestionar un cambio de versión.

Actualización de versión

Manual

Si realizamos el cambio manualmente, lo que habría que hacer es ir a cada uno de estos ficheros pom.xml y modificar el campo versión hasta dejarlos como se muestra a continuación.

multimodule

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>multimodule</artifactId>
    <version>1.1-SNAPSHOT</version>
	<packaging>pom</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <modules>
		<module>group-modules-1</module>
		<module>group-modules-2</module>
	</modules>
</project>

group-modules-1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example</groupId>
		<artifactId>multimodule</artifactId>
		<version>1.1-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules</groupId>
    <artifactId>group-modules-1</artifactId>
	<packaging>pom</packaging>

    <modules>
		<module>module-1</module>
	</modules>
</project>

module-1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example.modules</groupId>
		<artifactId>group-modules-1</artifactId>
		<version>1.1-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules.group1</groupId>
    <artifactId>module-1</artifactId>
	<packaging>jar</packaging>
	
</project>

group-modules-2

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example</groupId>
		<artifactId>multimodule</artifactId>
		<version>1.1-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules</groupId>
    <artifactId>group-modules-2</artifactId>
	<packaging>pom</packaging>

    <modules>
		<module>module-2</module>
	</modules>
</project>

module-2

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.example.modules</groupId>
		<artifactId>group-modules-2</artifactId>
		<version>1.1-SNAPSHOT</version>
	</parent>

    <groupId>org.example.modules.group1</groupId>
    <artifactId>module-2</artifactId>
	<packaging>jar</packaging>
	
</project>

Este cambio llevado a un caso real, donde puede haber 100 módulos distinto, no solo implica un coste en tiempo, sino la posibilidad de cometer algún error manual, cuando todo ello se puede realizar mucho más fácilmente con la opción siguiente.

Maven

Este es el caso más inmediato y cuyo resultado es el mismo que el anteriormente mostrado. Para ello se hará uso del plugin de maven versions:set

mvn versions:set -DnewVersion=1.1-SNAPSHOT -DgenerateBackupPoms=false

La estructura de la instrucción es la siguiente:

  • mvn: para la ejecución de maven
  • versions:set: el plugin que vamos a utilizar
  • -DnewVersion: versión nueva a actualizar
  • -DgenerateBackupPoms: flag que indica si queremos que se guarde una copia de los pom.xml originales

Con esto, con una simple ejecución, hemos obtenido el mismo resultado que en el caso anterior.

Conclusiones

Tras haber dado una breve introducción a maven y a lo que es una estructura multimodular queda reflejado el interés en el uso de esta herramienta y en la creación de este tipo de proyectos para los casos que aplica.

Por supuesto, como ya hemos comentado, de cara a mantener el versionado de los mismos se ha visto cómo se puede realizar de una manera sencilla y rápida con el uso de este plugin.

No dudes en comprobarlo por ti mismo haciendo uso del ejemplo mostrado o en tus propios proyectos!!

Referencias