Files
pgr/docs/rules/520-JAVA_MAVEN_GRADLE.md

13 KiB

Profil Java / Maven / Gradle

Rôle

Ce document possède les règles réutilisables propres au langage Java et à ses deux spécialisations de build principales retenues ici : Maven et Gradle.

Il complète 500-LANGUAGES.md. Les règles de gouvernance, documentation et validation restent possédées par leurs familles générales.

Android n'est pas défini ici. Une contrainte AGP, SDK Android, minSdk, targetSdk, versionCode, signing ou packaging APK/AAB appartient au profil plateforme Android et peut surcharger localement les règles Gradle ou JDK de ce document.

Politique JDK et compatibilité Java

Pour un projet Java général suivant le profil PGR :

  • le JDK de développement SHOULD être une version LTS ;
  • la dernière LTS compatible disponible dans l'environnement SHOULD être utilisée par défaut ;
  • une LTS plus ancienne MAY être sélectionnée lorsqu'un outil, framework, serveur, CI ou environnement d'exécution l'exige ;
  • une version Java non-LTS SHOULD NOT être introduite sans besoin technique explicite.

PGR MUST distinguer :

JDK utilisé pour construire
≠
niveau Java du code source
≠
niveau de bytecode/runtime minimal supporté

Le niveau Java ciblé MUST être déclaré explicitement par le build lorsqu'il affecte la compatibilité. Il ne doit pas dépendre implicitement du JDK actif sur la machine.

Une hausse de la version Java minimale supportée constitue un changement de compatibilité et MUST être justifiée comme telle.

PGR MUST NOT imposer une version exacte de JDK uniquement parce qu'un corpus historique ou un autre projet utilise cette version.

Structure source Java

Un module Java classique SHOULD conserver la structure reconnue par l'écosystème :

src/
├── main/
│   ├── java/
│   └── resources/
└── test/
    ├── java/
    └── resources/

PGR SHOULD NOT remplacer cette convention par une arborescence propriétaire telle que sources/, java-code/ ou tests-java/ sans contrainte réelle.

Les chemins canoniques correspondants sont donc notamment src/main/java/, src/main/resources/, src/test/java/ et src/test/resources/.

Lorsqu'un projet distingue des tests d'intégration, environnementaux ou live, il SHOULD utiliser un source set ou un module explicitement déclaré par le build plutôt que détourner src/test/.

Packages et ownership

Un package Java représente une responsabilité architecturale, pas seulement un dossier.

La racine de package SHOULD être stable et appartenir au projet ou à l'organisation. Les sous-packages SHOULD refléter des responsabilités telles que config, transport, store, logging ou protocol.

Les packages génériques tels que misc, stuff, helpers, common ou util SHOULD NOT devenir des dépotoirs. Lorsqu'un élément est partagé, son propriétaire architectural doit d'abord être identifié.

Un package utilitaire petit et cohérent MAY exister lorsque sa responsabilité est claire.

Nommage des modules

Lorsqu'un dépôt multi-langage ou multi-module utilise déjà une nomenclature de rôles commune, les modules Java SHOULD conserver les mêmes suffixes conceptuels afin de rester lisibles à l'échelle du dépôt.

Exemples usuels :

foo-api
foo-lib
foo-app
foo-cli
foo-server
foo-service
foo-worker
foo-tool
foo-demo
foo-smoke
foo-poc

Ce vocabulaire est une convention de rôle et non une obligation de créer artificiellement des modules séparés.

Imports

Les imports wildcard SHOULD NOT être utilisés :

import foo.*;
import static foo.Bar.*;

Les imports explicites sont préférés afin de conserver l'origine des symboles visible.

Les imports statiques SHOULD être évités par défaut dans le code produit lorsqu'une forme qualifiée reste lisible. Une règle de test ou de framework plus spécifique MAY autoriser une convention différente lorsqu'elle est réellement idiomatique et bornée.

Visibilité et API

La visibilité minimale appropriée est la règle par défaut :

private
→ package-private
→ protected
→ public

Une méthode ou un type MUST NOT devenir public uniquement pour faciliter un test.

Une interface Java SHOULD exister lorsqu'elle représente une vraie frontière : plusieurs implémentations, contrat consommé indépendamment, adaptation de plateforme, API publique ou autre séparation architecturale réelle.

PGR SHOULD NOT généraliser le pattern Foo / FooImpl lorsqu'une seule implémentation existe sans frontière utile.

Annotations et génération implicite

PGR n'interdit pas les annotations en tant que mécanisme Java.

Les annotations fonctionnelles faisant partie du contrat officiel d'un framework ou d'une API sont légitimes, par exemple pour la persistance, la validation, l'injection, le routage ou d'autres mécanismes officiellement documentés.

En revanche, Lombok et les outils équivalents de convenience/codegen implicite SHOULD NOT être utilisés par défaut lorsqu'ils servent principalement à masquer du boilerplate, générer des constructeurs/getters/setters ou modifier implicitement l'API visible dans la source.

Une exception exige une justification explicite et reste attachée au projet ou framework concerné.

Nullabilité

null SHOULD apparaître uniquement lorsqu'il appartient explicitement au contrat.

Une API ne devrait pas laisser le caller deviner si l'absence est possible. Selon le cas, le contrat peut employer :

  • Optional<T> ;
  • une collection vide ;
  • une exception appropriée ;
  • un type résultat plus explicite ;
  • une annotation de nullabilité reconnue par le projet.

PGR MUST NOT imposer Optional partout. L'objectif est l'explicitation du contrat, pas une cérémonie syntaxique.

Exceptions

Java possède un mécanisme natif d'exceptions ; PGR ne recrée pas automatiquement un modèle Result autour de toutes les opérations.

La distinction checked/unchecked appartient au contrat de la couche concernée.

Un catch SHOULD exister uniquement lorsque la couche sait réellement traiter, traduire ou enrichir l'erreur. Les captures silencieuses de Exception ou Throwable sont interdites hors mécanisme de frontière explicitement spécialisé.

Lorsqu'une erreur est traduite, sa cause SHOULD être préservée lorsque cette information reste pertinente.

Une couche SHOULD exposer ses propres erreurs de contrat plutôt que propager sans contrôle les détails techniques d'une dépendance interne.

Tests Java

Les tests comportementaux et structurels gardent des responsabilités distinctes.

Les tests unitaires résident normalement sous src/test/java/. Les tests d'intégration, environnementaux ou live SHOULD être séparés par source set, module ou tâche lorsque leur exécution possède des préconditions différentes.

Les tests MUST NOT :

  • rendre publique une API uniquement pour l'atteindre ;
  • rechercher des chaînes dans les sources pour simuler un audit d'architecture ;
  • vérifier une prerelease en codant en dur la version courante ;
  • ouvrir VERSION, pom.xml ou build.gradle uniquement pour confirmer leur synchronisation.

Les contraintes structurelles appartiennent au build system, au compilateur, à un linter adapté ou à un audit read-only.

Maven — ownership du build

Dans un projet Maven multi-module, le POM parent/root SHOULD centraliser ce qui est réellement commun :

  • version du projet lorsqu'elle doit être reflétée par Maven ;
  • niveau Java cible ;
  • dependencyManagement ;
  • pluginManagement ;
  • configuration commune de compilation et de tests.

Les modules SHOULD hériter de cette politique lorsque Maven le permet et ne pas recopier les mêmes versions/configurations sans nécessité.

Le fichier PGR VERSION reste la version canonique de l'unité de release. Le pom.xml racine porte un miroir technique lorsque Maven exige cette valeur. Les enfants SHOULD hériter de la version parent afin d'éviter les modifications mécaniques répétées de nombreux POM.

dependencyManagement centralise les contraintes de version communes ; il ne signifie pas qu'une dépendance doit être effectivement ajoutée à tous les modules. Chaque module déclare uniquement ce qu'il utilise.

Maven Wrapper

Deux politiques sont légitimes :

Maven système
→ environnement contrôlé
→ contrainte de version documentée

Maven Wrapper
→ distribution / CI / onboarding reproductible
→ wrapper versionné

PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.

Lorsqu'un wrapper est retenu, ses fichiers requis sont versionnés et constituent une exception explicite à la politique générale qui ignore les outputs générés.

Validation Maven

Le développement SHOULD privilégier les gates ciblées avant le reactor complet.

Exemple avec wrapper :

./mvnw -pl <module> -am test

Exemple avec Maven système :

mvn -pl <module> -am test

Les gates globales telles que le reactor complet, verify ou le packaging de tous les modules SHOULD être réservées aux changements transverses et aux phases où elles fournissent une preuve supplémentaire réelle.

clean est une opération de maintenance et MUST NOT précéder automatiquement chaque validation.

Gradle — ownership du build

Un projet Gradle SHOULD centraliser la configuration commune au niveau root lorsqu'elle est réellement partagée.

Selon le DSL retenu, les propriétaires typiques sont :

settings.gradle / settings.gradle.kts
build.gradle / build.gradle.kts
gradle.properties

Les sous-projets SHOULD NOT recopier sans nécessité :

  • la compatibilité Java ;
  • les repositories ;
  • les versions de plugins ;
  • les contraintes de dépendances ;
  • les configurations de tests communes.

Un version catalog tel que gradle/libs.versions.toml MAY être utilisé lorsque la taille du projet le justifie. PGR MUST NOT l'imposer pour un projet qui n'en tire aucun bénéfice réel.

Gradle Wrapper et version de Gradle

La contrainte Gradle doit refléter la matrice réellement supportée par le projet :

minimum seulement
range min..max
version exacte/pinnée
latest compatible

Le projet MUST choisir la forme la moins restrictive qui prouve réellement sa compatibilité.

Un Gradle Wrapper SHOULD être versionné lorsqu'il apporte une reproductibilité utile pour la distribution, la CI ou l'onboarding. Un projet contrôlé MAY utiliser un Gradle système si sa contrainte de compatibilité est explicitement vérifiée.

Une plateforme ou un framework plus spécifique MAY imposer une contrainte plus étroite. Cette contrainte ne se propage jamais implicitement aux autres projets Gradle.

DSL Gradle

PGR ne transforme pas une préférence de langage applicatif en interdiction du DSL de build.

Groovy DSL et Kotlin DSL sont tous deux reconnus. Un projet SHOULD retenir un DSL canonique et éviter de les mélanger arbitrairement.

Le code applicatif Java reste Java par défaut lorsque rien n'impose Kotlin/Groovy. Les scripts Gradle SHOULD rester aussi déclaratifs et courts que raisonnablement possible.

Une logique de build devenue importante SHOULD être déplacée vers une abstraction ou un plugin clairement possédé plutôt que grossir indéfiniment les scripts root.

Validation Gradle

Les tâches ciblées sont préférées pendant le développement :

./gradlew :<module>:test

ou, lorsqu'un Gradle système est explicitement retenu :

gradle :<module>:test

Les tâches globales check, build, assemble ou de packaging complet SHOULD être sélectionnées lorsqu'elles correspondent réellement au scope, typiquement lors d'un changement transverse ou dans les phases de stabilisation/release.

gradle clean est une opération de maintenance et MUST NOT être utilisé comme précondition automatique à chaque build.

Outputs, état local et Git

Les sorties de build et caches usuels ne sont pas versionnés :

Maven: target/
Gradle: .gradle/, build/

Les métadonnées IDE spécifiques à une machine restent ignorées sauf exception explicitement partagée selon les règles générales du projet.

Les wrappers retenus sont une exception volontaire : ils peuvent être générés par l'outil, mais leurs fichiers nécessaires au bootstrap reproductible sont versionnés.

Les fichiers de configuration locale contenant chemins machine, credentials ou overrides développeur restent hors Git. Un template est ajouté uniquement lorsqu'un utilisateur doit réellement préparer une valeur non régénérée automatiquement.

Validation et futurs audits PGR

Les catégories et l'autorité du gate restent possédées par 400-VALIDATION.md.

Ce profil définit des commandes et politiques Java/Maven/Gradle, mais PGR lui-même ne possède actuellement aucun projet Java, Maven ou Gradle à compiler. Aucune commande Maven/Gradle n'est donc ajoutée à la gate documentaire de cette tranche.

De même, aucun audit Java/Maven/Gradle n'est créé uniquement pour matérialiser un outil.

Lorsqu'un skeleton ou projet réel fournira un sujet stable, des audits monotâches MAY vérifier séparément des propriétés objectivement structurelles, par exemple la cohérence VERSION/POM, l'héritage d'une politique Maven ou la contrainte Gradle déclarée. Ils resteront read-only et ne lanceront jamais Maven ou Gradle à la place de leurs gates propres.