Compte Rendu du Paris JUG de Janvier 2025

Paris JUG est le meetup de l'écosystème Java pour Paris.

Il se définit comme "un groupe d’utilisateurs Java ayant pour but de réunir les acteurs du langage (professionnels, communautés open source, institutions, étudiants, enseignants…) afin d’échanger des idées et de discuter des avancées technologiques de la plateforme Java."

OCTO sponsorise Paris JUG pour cette année 2025. C’est donc tout naturellement que ce premier Paris JUG de l’année s'est tenu le 14 Janvier dans nos locaux, et auquel plus de 60 personnes ont participé.

Le premier événement de l'année est particulier puisqu'il s'agit de la Paris JUG Academy, appelée auparavant Young Blood. Les présentations sont faites par des personnes n'ayant encore jamais présenté en public auparavant et leur permettent de se faire une première expérience.

Les contraintes sont les suivantes:

  • 15 minutes de présentation montre en main. Une fois le délai écoulé, la présentation s'arrête, finie ou non
  • 5 minutes de questions / réponses

Pour ce faire, chacun a pu bénéficier d'un accompagnement pour la préparation de son talk lors de séances d'entraînement avec les membres du Paris JUG.

A l'issue des présentations, un vote du public détermine le speaker qui ira présenter son sujet à Devoxx France.

Cette session comportait six talks que nous allons résumer ici.

Photo des diplômes décernés aux speakers


Nous avons besoin de vous sur Quarkus Cucumber

Said Boudjelda - Linkedin

Quarkus est un framework Java pour les environnements cloud et serverless et permet le développement d'applications rapides et légères. Il est particulièrement adapté aux architectures basées sur des microservices et aux conteneurs, avec un démarrage rapide et une empreinte mémoire réduite. Quarkus prend en charge les standards Java et est conçu pour fonctionner nativement avec Kubernetes.

Cucumber permet de faire du Behavior driven development (BDD). On écrit des tests en langage naturel via Gherkin, qui sont donc lisibles et compréhensibles par des personnes non-techniques. Comme il n'est pas raisonnable que les développeurs d'un projet deviennent des experts du domaine, et que les experts du domaine ne peuvent pas devenir développeur. La personne non-technique peut comprendre les tests, voire même les écrire. La collaboration entre les équipes développement et métier est facilitée.

Example de test Gherkin

  En tant que bibliothécaire
  Je veux pouvoir ajouter des livres à la bibliothèque
  Afin que les utilisateurs puissent les emprunter

  Scénario: Ajouter un nouveau livre à la bibliothèque
    Étant donné que je suis connecté en tant que bibliothécaire
    Et que je suis sur la page d'ajout de livre
    Quand je saisis le titre "Le Petit Prince"
    Et que je saisis l'auteur "Antoine de Saint-Exupéry"
    Et que je saisis l'année de publication "1943"
    Et que je clique sur le bouton "Ajouter"
    Alors le livre "Le Petit Prince" par "Antoine de Saint-Exupéry" est ajouté à la bibliothèque
    Et un message de confirmation "Le livre a été ajouté avec succès" est affiché


Les tests écrits servent aussi de "Living documentation".

Said est contributeur sur le projet Quarkus Cucumber qui est un plugin permettant d'intégrer Cucumber dans Quarkus. Ce talk est un appel à l'aide, le plugin ayant besoin de contributeurs.

Toute personne est libre de contribuer au projet sur l'une de ces différentes thématiques :

  • Écrire de la documentation
  • Améliorer le code de l'extension
  • Ajouter de nouvelles fonctionnalités
  • Tester l'extension

Pour ceux qui veulent débuter dans l'open source, mettre à jour la documentation est une bonne porte d'entrée.

On peut retrouver les slides sur le repository Github du talk.


De la modélisation à la mise en production : Automatisation des workflows avec Camunda et Spring Boot

Salah Eddine El Mamouni - Linkedin

Derrière chaque process se trouvent des tâches répétitives. Ces tâches peuvent être automatisées avec des solutions de workflow.

Ce talk nous apprend comment déployer, exécuter et superviser des workflows.

Un workflow est un ensemble de tâches séquentielles réalisées pour atteindre un objectif spécifique. Ces tâches peuvent être automatisées ou être lancées manuellement.

Pour décrire le workflow, on va utiliser un standard de modélisation graphique qui permet de le représenter visuellement. Ce standard offre une notation compréhensible à la fois par les développeurs et les analystes du métier.

Ce standard s'appelle BPMN.

Une fois le workflow défini, il faut pouvoir l'exécuter. Il existe différents acteurs tels que Activiti, jBPM, Kogito et Camunda. Salah Eddine nous recommande Camunda qui est aujourd'hui le leader du marché. Il s'agit d'une plateforme de gestion des processus métier (BPM - business process management) permettant d'exécuter et de monitorer les workflows.

Ses principales fonctionnalités sont:

  • Modeler : une interface graphique permettant de modéliser le workflow BPMN
  • Tasklist : permet de gérer et suivre les tâches assignées aux utilisateurs
  • Cockpit : metrics, surveillance et analyse des processus en cours d'exécution, incidents, etc
  • Admin : instances de processus, des utilisateurs et des configurations de l'environnement BPM. Il supporte les systèmes de gestion d'identités externes tels que LDAP, OAuth / OIDC.

Il est possible de réaliser des workflows qui vont discuter avec différentes APIs et est donc adapté à un environnement en microservices.


How to test asynchronous code

Yifang Dong - Linkedin

Yifang commence par rappeler que "les tests servent de documentation vivante sur le fonctionnement de chaque composant. Tester les composants individuellement garantit que tous les aspects de chaque module sont pris en compte. Lorsqu'un composant est testé indépendamment, il est plus facile d'identifier l'origine des problèmes"

Comment bien tester lorsque le code que nous voulons tester contient de l'asynchrone ? Prenons l'exemple d'une notification qui est envoyée en asynchrone. Nous voulons vérifier que cette notification est bien arrivée.

Un test basique ne fonctionne pas car son exécution se termine avant que la notification ne soit reçue. Une implémentation naïve pourrait d’ajouter un temps d’attente via une instruction sleep afin de laisser le temps à la notification d'arriver. Mais cela rend le test instable: il peut échouer si la notification arrive après la fin du sleep. Cela rend également le test inefficace car on doit attendre la fin du sleep alors que la notification est peut être arrivée depuis un moment.

Deux solutions existent : le CompletableFuture et le CountDownLatch

CompletableFuture

Le CompletableFuture est une classe Java du package java.util.concurrent introduite en Java 8 pour faciliter la programmation asynchrone en permettant des opérations futures et la composition de tâches.

On peut utiliser la méthode bloquante get. Lorsqu’elle est utilisée, le Thread qui l'appelle suspend son exécution jusqu'à ce que la tâche représentée par le CompletableFuture soit terminée et que son résultat soit disponible. Dans notre exemple, on attend jusqu’à la réception de la notification.

Ici le Thread n'attend que le temps nécessaire pour que la tâche s'exécute et se termine. Le blocage dépend donc de la durée d'exécution de la tâche. Si la tâche est rapide, le blocage sera de courte durée. Si la tâche est longue, le thread sera bloqué plus longtemps.

 public Future<String> calculateAsync() throws InterruptedException {
    CompletableFuture<String> completableFuture = new CompletableFuture<>();

    Executors.newCachedThreadPool().submit(() -> {
        Thread.sleep(100);
        completableFuture.complete("Completed !");
        return null;
    });

    return completableFuture;
}
Future<String> completableFuture = calculateAsync();
String result = completableFuture.get();
assertEquals("Completed !", result);


Il existe des alternatives non bloquantes. CompletableFuture permet de chaîner plusieurs étapes de traitement avec thenApplythenAcceptthenCompose et whenComplete. Cela facilite la composition de plusieurs opérations mais peut également rendre le code plus complexe et difficile à lire, voir à des “callback hells”.

CompletableFuture
.supplyAsync(() -> "Completed !") 
.thenAccept(result -> System.out.println(result));


CountDownLatch

Le CountDownLatch en Java est une classe du package java.util.concurrent qui permet de synchroniser un ou plusieurs threads en leur permettant d’attendre jusqu'à ce qu'un certain nombre d'événements se produisent.

Il permet de coordonner l'exécution de threads dans des situations où un ou plusieurs threads doivent attendre qu'un autre thread termine son travail avant de pouvoir continuer.

public class Worker implements Runnable {
    private List<String> output;
    private CountDownLatch countDownLatch;

    public Worker(List<String> output, CountDownLatch countDownLatch) {
        this.output = output;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        doSomeWork();
        output.add("Added by Worker");
        countDownLatch.countDown();
    }
}

@Test
public void countDownLatchExample()
  throws InterruptedException {

    List<String> output = Collections.synchronizedList(new ArrayList<>());
    CountDownLatch countDownLatch = new CountDownLatch(3);
    List<Thread> workers = Stream
      .generate(() -> new Thread(new Worker(output, countDownLatch)))
      .limit(3)
      .collect(toList());

      workers.forEach(Thread::start);
      countDownLatch.await(); 
      output.add("Latch released");

      assertThat(output)
        .containsExactly(
          "Added by Worker",
          "Added by Worker",
          "Added by Worker",
          "Latch released"
        );
    }



CountDownLatch nous fournit deux méthodes: await pour attendre la fin des processus asynchrones et countDown qui permet de décrémenter le compte du latch. Le await se termine une fois que le compte est à zéro.

Nous avons ici vu deux méthodes pour gérer notre test en asynchrone. Une autre solution est de se passer de l'asynchrone. On change alors l'implémentation du service pour qu'il n'ai plus la responsabilité de lancer lui-même le thread. Il reçoit un Runnable . Et notre test peut injecter un Runnable qui n'est pas asynchrone, tandis que l'implémentation métier injecte un Runnable qui lancera un Thread.

Attention cependant, car on peut vouloir tester le comportement en asynchrone via un Thread. L'implémentation du test peut donc dépendre de ce que nous voulons réellement tester.


JPMS - Nightmares and Awakening Java Platform Module System

Salathiel Genese Yimga Yimga - Linkedin

Les JPMS - Java platform Module systems - ont été pensés pour introduire une modularité dans Java en 2005 pour répondre au besoin de diviser le JDK en modules pour le rendre plus léger et plus facile à gérer.

Les travaux débutent en 2008 sous le nom de “Projet Jigsaw” avec pour but une sortie sur Java 7. En raison de sa complexité et des autres priorités, le projet ne sera finalisé que sur Java 9 en 2017.

Les JPMS restent une partie méconnue de Java et ne sont donc pas très utilisés. Pourtant, JPMS peut offrir de nombreuses choses aux développeurs Java.

  • Encapsulation forte : les modules permettent de définir quelles parties du code sont accessibles depuis l’extérieur (exports) et quelles parties sont internes, ce qui renforce l’encapsulation et réduit les risques d’accès non intentionnel à des classes ou des méthodes internes.
  • Déclaration de dépendances explicite au sein du code, les dépendances entre modules sont déclarées de manière explicite (requires), ce qui facilite la compréhension et la gestion des relations entre différents composants de l'application.
  • Optimisations : Les modules permettent une amélioration potentielle des performances, notamment en optimisant le temps de démarrage des applications et en réduisant la taille du runtime en excluant les modules inutilisés.
  • Validation à la compilation : aide à détecter les erreurs tôt dans le cycle de développement
  • Validations à l'exécution : la JVM vérifie que les modules sont cohérents avec les dépendances spécifiées, assurant que l'application fonctionne comme prévu.
  • Amélioration de la sécurité : En limitant l’accès aux parties internes des modules, JPMS peut renforcer la sécurité de l’application en réduisant les surfaces d’attaque potentielles.

Le JDK utilise les JPMS et est donc modularisé. Cela permet d'utiliser certaines parties du JDK sans tout importer. Il permet des JRE (Java Runtime Environment) plus petits puisque le JRE lui-même est organisé en modules. Cela permet de n'inclure que les modules nécessaires pour l'application et réduit donc la taille du JRE. C'est utile dans les environnements où les ressources sont limitées, comme les conteneurs Docker ou les déploiements cloud.

JPMS permet une encapsulation forte du code en exposant certains packages uniquement. Pour les ressources, les fichiers assets sont séparés.

Un frein à l'adoption est un manque de compatibilité de JPMS avec certaines bibliothèques tel que JUnit. Enfin, pour beaucoup de projets, les avantages de la modularisation (meilleure encapsulation, réduction des conflits de classes) ne sont pas toujours jugés suffisants pour justifier l'effort de migration.

Retrouvez les slides de ce talk.


Reprenez le contrôle de votre stack back !

Marc Guiot - Linkedin

Marc expose une problématique qu'il a connu il y a quelques années sur un site eCommerce qui recevait de nombreux Webhooks. Pour des besoins d'optimisation, les triggers suite à la réception de Webhooks externes ne devaient se faire que lorsque nécessaire.

Prenons en exemple une Webhook notifiant à intervalle régulier l’état de l’ensemble des stocks d’une boutique.

La mise à jour des informations des stocks sur nos applications se fait toutes les cinq minutes environ. Durant cet intervalle de cinq minutes, plusieurs Webhooks peuvent être reçues.

On souhaite calculer la différence entre la Webhook dernière Webhook prise en compte et l’ensemble des Webhooks reçue depuis. S'il y a une différence, on notifie nos applications.

Comment calculer cette différence ?

  • Écrire du code de diff entre chaque champs : laborieux
  • Faire de l'introspection : pas facile
  • Manipuler les JsonObject directement

La solution retenue est différente. Marc et son équipe ont développé GlobsFramework. C’est un framework metamodel conçu pour utiliser des Generic Lightweight objects (Globs). Un Glob est essentiellement un objet de type Map permettant une modélisation du schéma des données. Les fields du Glob peuvent être visités en utilisant le “visitor pattern”.

public static class ProductType {
   public static GlobType TYPE;
   public static LongField id;
   public static StringField title;
   public static DoubleField price;
   public static BooleanField published;
}



Pourquoi créer ce framework metamodel plutôt que l'introspection ?

  • A l'époque du projet c'était naturel de le formaliser dans un modèle plutôt que de la génération de code
  • L'introspection à un impact sur les performances
  • Avec l'introspection on doit gérer beaucoup de classes et continuellement l'améliorer.

Pour ceux qui auraient des problématiques similaires, un participant met en avant JaVers - "The Leading Framework for Object Audit and Diff in Java".


Apprenez à votre IA à faire du TDD

Manuel Camargo - Linkedin

Manuel est un fan de Test Driven Development (TDD) que nous vous avons présenté dans l’article “Le double cycle TDD : ne sous-estimez plus l'étape de refactoring”.
Il a décidé d'apprendre à GitHub Copilot à en faire. L'IA est pourtant souvent décriée pour produire du code de mauvaise qualité.

Revenons tout d'abord rapidement aux bases du TDD. Ce processus de développement fonctionne en cycle composé de trois phases : Red, Green et Refactor. Écrire un test qui échoue (Red), écrire juste assez de code pour que le test passe (Green), puis re-factoriser le code tout en s'assurant que les tests passent toujours (Refactor). TDD permet d'améliorer la qualité du code et de garantir que chaque fonctionnalité est correctement testée dès sa création.

On s'est rendu compte que les IA répondaient bien mieux si on leur demandait d'écrire les différentes étapes de réflexion, ce qui est exactement un principe du TDD. Cette technique appelée “prompt chaining” découpe un problème complexe et permet d'obtenir de meilleurs résultats, avec moins d'hallucinations de la part de l'IA.

La présentation commence par une demande simple, sans TDD, d'écrire la logique et les tests correspondants. L'organisation du code générée est mauvaise : le code métier est dans la couche repository.

Les tests fournis par Copilot passent tous. Mais aucun test n'a la même forme et ils ne sont pas cohérents. Manuel écrit des tests supplémentaires pour vérifier que le code généré est vraiment correct. Ses tests ne passent pas car Copilot n'a pas géré les cas limites dans le code métier, et n'a pas non plus généré de tests pour les valider.

"À première vue, Copilot est comme un dev avec énormément de connaissances mais aucune intelligence". Est-ce que l'approche TDD peut y changer quelque chose ?

Comme on l'a vu, les tests sont de mauvaise qualité. On doit donc commencer par expliquer à Copilot ce qu'est un bon test. On commence par expliquer le contexte du projet : le métier, l'architecture, les standards utilisés. On insiste particulièrement sur les standards de tests unitaires. On peut également fournir un exemple de test existant qui applique ces standards.

On lui demande de générer un premier test qui échoue (red). Puis on demande l'implémentation du test. Dans le prompt, on fourni le nom du test voulu afin d'orienter son implémentation.

On passe ensuite à l'étape Green. Mais Copilot va avoir tendance à écrire plus de code que ce dont on a besoin. En TDD on a besoin du strict minimum pour faire passer le test. Il faut lui rappeler cette règle.

Enfin vient l'étape du Refactor. Manuel spécifie qu'il vaut mieux demander de refactorer. Si on lui demande d’améliorer le code, Copilot va avoir tendance à rajouter du code non nécessaire tel que du logging. On lui demande également de faire cinq propositions d'améliorations différentes. Le développeur choisit celle qui lui plait le plus. Parmi ces cinq propositions, il peut y en avoir une seule d'intéressante.

Le retour sur cette expérience est que ça fonctionne. "Faire du TDD avec Copilot c'est comme faire du peer programming où Copilot est le driver et on est le navigateur". Attention cependant, les tests réalisés l'ont été sur des cas qui restent assez simples et pas sur des algorithmes complexes.

Le principal problème rencontré par Manuel est l'ergonomie dû à l'outillage utilisé (Copilot sur IntelliJ IDEA), qui n'existe pas avec d'autres solutions.

Par exemple, on peut désormais utiliser les Copilot extensions pour ajouter nos propres standards à Copilot et qu'il les retienne. Certains IDE comme vs code ont une intégration bien plus poussée qui permet par exemple d'avoir des propositions de code directement dans l'éditeur. On parle aussi d'autres IDE spécialisés dans l'IA comme Cursor.

Si vous souhaitez intégrer de l’IA dans votre processus de développement, retrouvez notre article “AI Augmented Developer: Intégrer la GenAI dans la toolbox des développeurs”.


Ce premier Paris JUG de l’année nous a permis de découvrir de nouveaux speakers. Rappelons que la présentation est coupée à l’issue de quinze minutes. L’exercice n’est donc pas évident. Certains n’ont pas pu finir complètement, mais repartent avec une précieuse expérience : ne pas finir sur le plus important.

Cette initiative est importante pour permettre à de nouvelles personnes de se lancer dans les talks.

Photo des speakers à l'issue de la conférence

Les six talks présentés couvrent une gamme variée de sujets. Chaque intervenant a pu apporter sa perspective sur les problématiques rencontrées dans l'écosystème Java.

La soirée s'est terminée par le vote du public pour déterminer le speaker qui participera à Devoxx France. C’est Manuel Camargo qui ira y présenter son talk “Apprenez à votre IA à faire du TDD” du 16 au 18 avril 2025.

Avec le soutien d’OCTO pour l'année 2025, Paris JUG continue de renforcer les liens de la communauté Java.

Nous remercions tous les participants et intervenants pour leur contribution à cet événement réussi, et sommes impatients de voir ce que cette année nous réserve encore.