Lab 02

Maven Multi Module

Aus einem unsauberen Monolith-POM wird ein nachvollziehbarer Multi-Module-Build.

MavenModuleDependency ManagementBuild Governance
SchwierigkeitEinsteiger+
Dauer45–75 Min
LernstufeStufe 6 – Praxislabor und Capstone
Arbeitsweise: Erst den Vorher-Code öffnen, dann Analyse lesen, anschließend die Nachher-Lösung und den Test vergleichen. Alle Abschnitte sind standardmäßig geschlossen.

Workshop-Slice

Dieses Lab zeigt einen konkreten Enterprise-Fehler mit Vorher/Nachher-Code. Die Beispiele sind bewusst fachlich benannt, damit du Architekturentscheidungen und nicht nur Syntax übst.

Lernziel

Du strukturierst ein Enterprise-Projekt so, dass Domain, Application, Adapter und Architekturtests als getrennte Maven-Module sichtbar werden.

Ausgangslage

Ein einzelnes POM enthält Spring Boot, JPA, Web, Testcontainers, SOAP und OpenShift-Plugins in einem Modul. Dadurch ziehen Domain-Klassen unnötige Framework-Abhängigkeiten und Architekturgrenzen sind nicht sichtbar.

Vorher: problematischer Code

Das Monolith-POM macht alles in einem Modul. Es ist bequem, aber für Enterprise-Lernen und spätere Migration schlecht.

pom.xmlXML
<project>
  <artifactId>order-platform</artifactId>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>postgresql</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
Analyse: Was ist daran schlecht?
  • Domain-Code kann versehentlich Spring/JPA importieren.
  • Build-Zeiten und Testarten sind nicht getrennt.
  • Adapter-Abhängigkeiten sind nicht erkennbar.
  • Spätere Migration zu Quarkus/Jakarta EE wird unnötig schwer.

Der wichtige Punkt ist nicht nur Maven-Technik, sondern Architektur-Sichtbarkeit: Was nicht voneinander abhängen darf, bekommt eigene Module.

Nachher: bessere Lösung

Der Parent steuert Versionen und Module. Domain bleibt frameworkfrei, Adapter hängen bewusst von der Application-Schicht ab.

pom.xmlXML
<project>
  <packaging>pom</packaging>
  <modules>
    <module>shared-kernel</module>
    <module>order-domain</module>
    <module>order-application</module>
    <module>order-adapter-rest</module>
    <module>order-adapter-jpa</module>
    <module>architecture-tests</module>
  </modules>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>
order-domain/pom.xmlXML
<project>
  <artifactId>order-domain</artifactId>
  <dependencies>
    <!-- bewusst keine Spring-, JPA- oder Web-Abhängigkeit -->
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>shared-kernel</artifactId>
    </dependency>
  </dependencies>
</project>
architecture-tests/pom.xmlXML
<dependency>
  <groupId>com.tngtech.archunit</groupId>
  <artifactId>archunit-junit5</artifactId>
  <scope>test</scope>
</dependency>
Test / Prüfnachweis

Dieser Abschnitt zeigt, wie du die Verbesserung nachweist. Es ist bewusst kein reiner Happy-Path-Test, sondern prüft ein Risiko aus dem Vorher-Teil.

LayerRulesTest.javaJAVA
@AnalyzeClasses(packages = "com.acme.order")
class LayerRulesTest {
    @ArchTest
    static final ArchRule domain_must_not_depend_on_spring =
        noClasses().that().resideInAPackage("..domain..")
            .should().dependOnClassesThat().resideInAnyPackage("org.springframework..", "jakarta.persistence..");
}
Typische Fehler
  • Jedes Modul importiert wieder alle Starter.
  • Parent-POM enthält Buildlogik, die nur für ein einzelnes Adaptermodul gilt.
  • Tests liegen nur im Webmodul und prüfen Domainregeln indirekt.
Deep-Learning-Bezug

Die Links führen zum ausführlichen Inhalt; die Deep-Learning-Seite bleibt nur die Lernlandkarte und kopiert den Inhalt nicht doppelt.

Prüfcheckliste
  • Domain-POM hat keine Spring/JPA/Web-Abhängigkeit.
  • Parent-POM enthält dependencyManagement.
  • Module bilden Architekturgrenzen ab.
  • ArchUnit-Regel verhindert Rückfall in Framework-Kopplung.
⌂ Cockpit