Utiliser des GITHUB Actions pour déployer dans Google Kubernetes Engine

A mes heures perdues, je travaille sur un « POC/side project qui n’aboutira pas et je m’en fiche » basé sur Quarkus. J’ ai choisi d’utiliser les langages et composants suivants :

Oui, tant qu’à faire, autant aller dans la hype …

Mon projet est sur GITHUB. Pour automatiser certaines actions et, disons-le, par fierté personnelle, j’ai choisi d’automatiser certaines actions par la mise en œuvre de pipelines CI/CD.
Depuis peu, GITHUB a intégré un mécanisme de pipeline : GITHUB Actions.

Ça permet, entre autres, de lancer des processus automatisé sur un push ou sur une action pour un commit GIT.

La force de l’outil est, selon moi, de facilement s’intégrer avec beaucoup de services du cloud ( sonarcloud, google cloud, heroku,…). On aime ou on n’aime pas, mais chez Microsoft, l’intégration ils savent faire.

Par exemple, si on veut lancer une compilation lors d’un push, on peut placer un fichier .github/workflows/build.xml avec le contenu :

name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Build with Gradle without testing
        run: ./gradlew build -x test

Coté GITHUB, vous verrez l’exécution sur un écran dédié

Vous pouvez créer autant de workflows que vous souhaitez (si votre projet est en libre accès).
Pour chaque workflow, on peut définir et utiliser des jobs. Les logs d’exécution sont disponibles dans ce même écran:

Worflows implémentés

J’ai choisi d’implémenter les workflows suivants:

  • CI: Build sur la feature branch
  • CD: Build sur master branch et déploiement

On obtient donc dans mon cas:

Ce n’est pas parfait. Loin de là. Dans la « vraie vie », pour une équipe de dev, je l’améliorerai sans doute par un build docker dans les features branches, une validation formelle et bloquante de l’analyse sonar, etc.
Pour un dev perso ça suffit largement. Le contenu de la branche master est compilé et une image docker est crée pour être déployée automatiquement dans GKE.

Analyse SONAR

J’ai choisi d’utiliser sonarcloud pour analyser mon code. C’est gratuit pour les projets opensource. L’analyse se fait simplement:

  sonarCloudTrigger:
    name: SonarCloud Trigger
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: SonarCloud Scan
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        run: ./gradlew jacocoTestReport sonarqube

Dans ce job j’utilise deux secrets. Ce sont des tokens qui permettent de ne pas stocker en dur les données dans les repos GITHUB.

Création d’une image Docker et déploiement dans le registry GITHUB

Ici aussi, ça se fait simplement. La preuve :

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Build in JVM Mode with Gradle without testing
        run: ./gradlew quarkusBuild  [1]
      - name: Branch name
        run: echo running on branch ${GITHUB_REF##*/}
      - name: Build the Docker image Quarkus JVM
        run: docker build -f src/main/docker/Dockerfile.jvm -t docker.pkg.github.com/${GITHUB_REPOSITORY}/music-quote-jvm:latest .  [2]
      - name: Login against github docker repository
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: docker login -u ${GITHUB_ACTOR} -p ${GITHUB_TOKEN}  docker.pkg.github.com   [3]
      - name: Publish the Docker image Quarkus JVM
        run: docker push docker.pkg.github.com/${GITHUB_REPOSITORY}/music-quote-jvm:latest  [4]
  1. Création du binaire
  2. Création de l’image docker en utilisant la commande docker et le Dockerfile fourni par Quarkus
  3. Identification sur la registry Docker de GITHUB
  4. Déploiement de l’image

Pour plus de détails sur la variable GITHUB_TOKEN, vous pouvez lire cet article de la documentation.

Déploiement dans Google Kubernetes Engine

Mon application est pour l’instant architecturée comme suit (attention c’est compliqué):

Pour la déployer dans Google Kubernetes Engine, j’ai besoin d’ implémenter cette « architecture » par les objets Kubernetes suivants:

J’utilise les objets suivants:

  • Des services pour exposer la base de données ainsi que l’application
  • Un deployment pour l’application
  • Des pods car à un moment, il en faut…
  • Un statefulset pour la base de données

Vous pourrez trouver la définition de tous ces objets au format yaml via ce lien. J’ai fait très simple. Logiquement j’aurai du créer un volume pour les bases de données ou utiliser une base de données en mode PAAS.

Pour lancer le déploiement, il faut au préalable créer un secret ( fait manuellement pour ne pas stocker d’objet yaml dans le repository GITHUB) pour se connecter au repo GITHUB via la commande suivante:

kubectl create secret docker-registry github-registry --docker-server=docker.pkg.github.com --docker-username=USER--docker-password=PASSWORD --docker-email=EMAIL

On peut faire pareil pour les connexions base de données. J’ai mis dans un configmap pour ne pas trop me prendre la tête…

Après le déploiement via le pipeline se fait assez simplement:

      [...]
      - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
        with:
          version: '286.0.0'
          service_account_email: ${{ secrets.GKE_SA_EMAIL }}
          service_account_key: ${{ secrets.GKE_SA_KEY }}
          project_id: ${{ secrets.GKE_PROJECT }}
      # Get the GKE credentials so we can deploy to the cluster
      - run: |-
          gcloud container clusters get-credentials "${{ secrets.GKE_CLUSTER }}" --zone "${{ secrets.GKE_ZONE }}"
      # Deploy the Docker image to the GKE cluster
      - name: Deploy
        run: |-
          kubectl apply -f ./k8s     

J’utilise les « actions » fournies par Google.

Conclusion

Pour que ça marche il y a pas mal d’étapes préalables ( des tokens à générer, un utilisateur technique, …).
J’ai essayé de les référencer dans le README du projet.
Si vous voulez tester l’intégration Kubernetes dans le cloud google, sachez que vous pouvez disposer d’un crédit de 300€ valable un an. Attention, avec ce genre d’architecture, ça part vite…

Améliorer le temps de démarrage de Debian 10

Mon PC Lenovo a un SSD. Le temps de démarrage est actuellement de 11 sec. Ça commence à faire pas mal… J’ai eu donc envie de me pencher sur l’optimisation du démarrage ( encore une fois) . Voici comment gagner (facilement) quelques secondes au démarrage.

Tout d’abord, vous devez analyser les services qui prennent du temps au démarrage. Vous pouvez le faire avec cette commande:

systemd-analyze plot > plot.svg

J’ai obtenu le graphique suivant:

Configuration GRUB

La première manipulation à réaliser est de désactiver le timeout de GRUB. Pour celà, vous pouvez modifier la variable GRUB_TIMEOUT dans le fichier /etc/default/grub:

GRUB_TIMEOUT=0

Ensuite, vous devez mettre à jour la configuration GRUB en exécutant cette commande:

sudo update-grub2

Au prochain reboot, vous ne verrez plus le menu GRUB.

Configuration NetworkManager

Dans mon cas, le service NetworkManager-wait-online.service prenait près de 9 secondes. Après avoir lu plusieurs billets et rapports de bug, je me suis aperçu que je pouvais le désactiver au boot. Vous pouvez le faire en lançant la commande suivante

sudo systemctl disable NetworkManager-wait-online.service

Configuration Apt

Un autre service qui prenait pas mal de temps était apt-daily.timer qui vérifiait au boot qu’il y avait des mises à jour de l’OS. Après quelques recherches, j’ ai vu qu’on pouvait soit le désactiver ( ce qui n’est pas recommandé pour les mises à jour de sécurité ) soit décaler la recherche. J’ai choisi cette solution. Vous devez donc exécuter la commande suivante:

sudo systemctl edit apt-daily.timer

Et renseigner le contenu suivant:

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
AccuracySec=1h
RandomizedDelaySec=30min

Ce service sera donc lancé 15 minutes après le boot. Ce qui est largement suffisant.

[EDIT] Vous pouvez appliquer la même configuration pour le service apt-daily-upgrade en exécutant la commande:

sudo systemctl edit apt-daily-upgrade.timer

Ensuite, vous pouvez recharger la configuration en exécutant cette commande:

sudo systemctl daemon-reload

Résultats

Après ces quelques manipulations qui peuvent prendre 5 minutes grand maximum, j’ai réussi à optimiser le boot en réduisant le démarrage à 5 secondes!

Vous pourrez trouver le détail ci-dessous:

Répéter avec JjazzLab tout seul dans son garage

Avec les contraintes liées au confinement, les répétitions se font de plus en plus rares. Pour ne pas perdre la main, il y a quelques logiciels qui permettent de jouer d’un instrument et d’ improviser tout en ayant une bande son en fond musical.

Il y a plusieurs logiciels payants/propriétaires sur différentes plateformes:

J’ai découvert ce dernier récemment en naviguant sur le site Linux Mao. Il a l’avantage d’être gratuit (le moteur est sous licence LGPL 3.0, pas le logiciel en tant que tel), de fonctionner sous GNU/LINUX, d’ offrir un son pas mal du tout et de permettre la configuration de la dynamique au fur et à mesure du morceau.

Je vais expliquer comment l’installer sur Debian.

Configuration Midi

Activation des périphériques virtuels MIDI

Créer un fichier /etc/modules.load.d/midi.conf avec le contenu suivant:

snd-virmidi

Ensuite créer le fichier /etc/modprobe.d/midi.conf avec le contenu suivant:

options snd-virmidi midi_devs=1

Logiquement à ce stade, lors du prochain reboot, vous aurez un périphérique virtuel MIDI activé. En attendant vous pouvez lancer la commande suivante

$ sudo modprobe snd-virmidi midi_devs=1

Synthétiser du MIDI

Pour faire fonctionner ce logiciel, il faut installer une banque de son ( au format SF2) et un logiciel permettant de l’utiliser pour synthétiser du MIDI.
La banque de son recommandée est disponible via ce lien. Téléchargez là et copiez la dans un répertoire accessible.

Pour le second, il vous faudra installer fluidsynth. Voic les quelques commandes à lancer:

$ sudo apt install fluid-synth qsynth

Petite vérification…

Avant d’ aller plus loin dans la configuration de fluidsynth, vous pouvez vous assurer que tout est OK en récupérant un fichier MIDI et en lançant la commande suivante:

$ fluidsynth -a pulseaudio -m alsa_seq -l -i /opt/JJazzLab-2.0-Linux/JJazzLab-SoundFont.sf2  MIDI_sample.mid

Normalement vous devriez avoir du son.

Configurer fluidsynth

Lancez qsynth et cliquez sur le bouton « configuration »

Vous trouverez ci-dessous la configuration que j’ai appliqué. Elle diffère légèrement de celle présentée dans la documentation.

Pensez à redémarrer fluidsynth après application de ces nouveaux paramètres.

Configurer aconnect

Disclaimer: La c’est la partie la plus obscure…

Il faut maintenant « brancher » la sortie du synthétiseur virtuel MIDI à fluidsynth pour que le son MIDI soit interprété par ce dernier à travers sa banque de son. Ce n’est pas intuitif, je vous avais prévenu …
Je ne vous parle pas de la pseudo interface graphique à aconnect. La ligne de console est plus parlante ( c’est pour dire ) .

Exécutez la commande suivante:

$ aconnect -lo                                            
client 14: 'Midi Through' [type=noyau]
    0 'Midi Through Port-0'
client 24: 'Virtual Raw MIDI 2-0' [type=noyau,card=2]
    0 'VirMIDI 2-0     '
client 128: 'FLUID Synth (JJLAB)' [type=utilisateur,pid=17838]
    0 'Synth input port (JJLAB:0)'

Dans mon cas, je vais avoir à connecter le client 24:0 au synthétiseur 128:0 grâce à la commande :

$ aconnect 24:0 128:0

Maintenant, si on relance la commande aconnect -lo on obtient le résultat suivant:

client 14: 'Midi Through' [type=noyau]
    0 'Midi Through Port-0'
client 24: 'Virtual Raw MIDI 2-0' [type=noyau,card=2]
    0 'VirMIDI 2-0     '
	Connexion À: 128:0
client 128: 'FLUID Synth (JJLAB)' [type=utilisateur,pid=17838]
    0 'Synth input port (JJLAB:0)'
	Connecté Depuis: 24:0

Attention, cette commande devra être lancée ( ainsi que fluidsynth) avant chaque démarrage de jjazzlab.

Installation de Jjazzlab

Téléchargez les binaires sur ce site, puis décompressez l’archive dans le répertoire /opt par ex.

Vous devez également installer java

$ sudo apt install openjdk-11-jdk

Ensuite, vous devez créer le fichier ~/.local/share/applications/jjazzlab.desktop avec le contenu suivant:

[Desktop Entry]
Type=Application
Name=JJazzLab
GenericName=JJazzLab
Icon=
Exec="/opt/JJazzLab-2.0-Linux/bin/jjazzlab"
Terminal=false
Categories=Audio;Music;Player;AudioVideo;

Maintenant vous pouvez directement démarrer JJazzlab via le menu.

Configuration

Une fois jjazzlab démarré, vous devez aller dans le menu « Tools>Options » et sélectionnez les valeurs suivantes:

Ouvrez un fichier example (ex. sunny )

Cliquez sur le menu décrit par un clavier

Puis configurez comme suit:

Maintenant vous pouvez télécharger les standards fournis sur le site et improviser dessus 🙂

Erreur 139 à l’exécution d’un container docker

Voici un rapide article sur un problème rencontré récemment. Lors de l’exécution d’un container docker, j’ai eu une erreur SIGSEGV 139. Un crash avec aucune log.

Bref que du bonheur 🙂



Avant d’aller plus loin voici mon environnement:

Après quelques recherches, je me suis rendu compte qu’on pouvait reproduire ce comportement en exécutant cette commande:

docker run -it gcc:4.8.5

Une des raisons trouvées serait un problème de compatibilité avec le noyau 4.8.5 (oui ça remonte…).
Une solution est d’activer l’émulation vsyscall.


Voici la configuration à effectuer:
Dans le fichier /etc/default/grub, ajouter la ligne suivante:

GRUB_CMDLINE_LINUX_DEFAULT="quiet vsyscall=emulate"

Puis lancer les commandes suivantes:

$ sudo update-grub 
$ sudo reboot

Maintenant le container devrait pouvoir s’exécuter correctement.

Installer Ubuntu 18.04 LTS sur un Dell Inspiron 14-3493

Suite aux premières annonces de distanciation sociale ( avant que le confinement soit effectif ) j’ai acheté en catastrophe un PC portable. Les critères étaient : 8Go de RAM, un disque SSD … et la compatibilité GNU/LINUX :).

N’ayant pas trop de temps pour chercher la bonne affaire ( technologique et financière ), j’ ai acheté un Dell Inspiron 14-3493.



Je n’ai pas pris trop de risques. Bien que livré avec Windows 10, ce modèle est déjà certifié compatible Ubuntu.
L’installation d’Ubuntu se passe très bien. C’est plié en moins de 30mn. Du coup, je ne la détaillerai pas dans cet article – si vous êtes intéressé, vous pouvez consulter cet article. Pour les pré-requis, c’est une autre paire de manches …

Voilà les différentes actions que j’ai réalisé au préalable

Redémarrer l’ordinateur et accéder au BIOS

Là, j’ai un peu galéré pour accéder au BIOS. La seule manipulation que j’ai trouvé et de lancer le menu « Démarrage avancé » puis sélectionner « Utiliser un périphérique ».

Vous pouvez donc sélectionner le disque dur. Au boot en appuyant sur la touche F12 et/ou F2, vous pouvez accéder au BIOS.

Configuration du BIOS

Voila les paramètres que j’ai appliqué:

Dans le menu "SATA Operation": vous devez sélectionner AHCI au lieu de RAID.
Dans le menu "Change boot mode settings >UEFI Boot Mode" , vous devez désactiver le Secure Boot.

Une fois réalisé, vous pouvez redémarrer en appuyant sur la touche F2 et/ou F12. Si vous n’arrivez pas à revenir sur le BIOS pour indiquer de booter sur votre clé USB, vous obtiendrez un écran d’erreur Windows dû à la configuration AHCI. Personnellement, en redémarrant une ou deux fois, j’ai obtenu un écran de démarrage avancé qui m’a permis de sélectionner le périphérique (ma clé USB) sur lequel démarrer.

Maintenant vous pouvez accéder à l’installeur Ubuntu et profiter 🙂

Après l’installation

Je n’ai rien fait de particulier si ce n’est configurer le trackpad. Pour cela, j’ai installé gnome-tweaks. Mis à part ça, tout fonctionne très bien!

Passer votre application Java8 en Java11

Java 8 est encore largement utilisé dans les entreprises aujourd’hui. Il y a même certains frameworks qui n’ont pas encore sauté le pas.
Je vais essayer d’exposer dans cette article les étapes à réaliser pour migrer (simplement) votre application JAVA8 en JAVA 11.

Dans cet article, je prendrai comme postulat que l’application se construit avec Maven.

Pré-requis

Tout d’abord vérifiez votre environnement d’exécution cible! Faites un tour du coté de la documentation et regardez le support de JAVA.

Si vous utilisez des FRAMEWORKS qui utilisent des FAT JARS, faites de même (ex. pour spring boot, utilisez au moins la version 2.1.X).

Ensuite, vous aurez sans doute à mettre à jour maven ou gradle. Préférez les dernières versions.

Configuration maven

Les trois plugins à mettre à jour obligatoirement sont :

Maven compiler plugin

<plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>11</release>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

maven surefire / failsafe plugin

Pour ces deux plugins, ajouter la configuration suivante:

 <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
        <configuration>
        [...]
          <argLine>--illegal-access=permit</argLine>
          [...]
        </configuration>
      </plugin>

Mise à jour des librairies

Bon,la il n’y a pas de magie. Vous devez mettre à jour toutes vos librairies. Mis à part si vous utilisez des librairies exotiques, la plupart supportent JAVA 11 maintenant.

C’est une bonne opportunité de faire le ménage dans vos fichiers pom.xml 🙂

APIS supprimées du JDK

Si vous faites du XML, SOAP ou que vous utilisiez l’API activation, vous devez désormais embarquer ces librairies. Le JDK ne les inclut plus par défaut.

Par exemple:

 <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>

Modularisation avec JIGSAW

Bon là … je vous déconseille de partir directement sur la modularisation, surtout si vous migrez une application existante. Bien que la modularité puisse aider à réduire vos images docker en construisant vos propres JRE et d’améliorer la sécurité, elle apporte son lot de complexité.
Bref pour la majorité des applications, je vous déconseille de l’intégrer.

Conclusion

Avec toutes ces manipulations, vous devriez pouvoir porter vos applications sur JAVA11. Il y aura sans doute quelques bugs. Personnellement, j’en ai eu avec CGLIB vs Spring AOP sur une classe instrumentée avec un constructeur privé. Sur ce coup j’ai contourné ce problème ( je vous laisse deviner comment 🙂 ).

Premiers pas avec Gradle

Depuis quelques temps je me mets à Gradle. Après de (trop?) nombreuses années à utiliser Maven (depuis la version 0.9…), je me risque à modifier mon environnement de build. Du moins sur des projets démo.

Quand on a fait pas mal de Maven, on est un peu dérouté au début. On a d’un coté, la plupart des actions qui sont configurées de manière implicite et de l’autre on peut tout coder/étendre ou presque.

Je ne vais pas me risquer à faire un comparatif des deux outils. Gradle ( donc fortement orienté ) en a fait un.

Je vais plutôt décrire avec cet article comment on peut démarrer rapidement en configurant son environnement pour être utilisé en entreprise.

Installation

Le plus simple est d’utiliser SDKMAN.

Voici la manipulation pour l’installer:

$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"
$ sdk install gradle 6.0.1

Configuration d’un proxy

Et oui comment souvent, passer le proxy d’entreprise est la moitié du boulot :).
Pour le configurer de manière globale (c.-à-d. pour tous vos projets) sur votre poste de travail, vous devez créer un fichier gradle.properties dans le répertoire $HOME/.gradle :

systemProp.http.proxyHost=proxy
systemProp.http.proxyPort=8888
systemProp.http.nonProxyHosts=localhost|127.0.0.1
systemProp.https.proxyHost=proxy
systemProp.https.proxyPort=8888
systemProp.https.nonProxyHosts=localhost|127.0.0.1

Configuration d’un miroir Nexus ou Artifactory

A l’instar du proxy, on va essayer de mettre en place une configuration globale. Pour ce faire, on va utiliser les init scripts. Cette fonctionnalité est très intéressante. Elle permet de centraliser des actions et configurations.
Pour créer un script, il faut tout d’abord créer un fichier .gradle dans le répertoire $HOME/.gradle/init.d.

Voici un exemple pour Nexus:

allprojects { 
  buildscript { 
    repositories {
      mavenLocal() 
      maven {url "https://url-nexus"} 
    }
  }
  repositories { 
    mavenLocal()
    maven { url "https://url-nexus"}
  }
}

Configuration du déploiement dans Nexus / Artifactory

Le déploiement dans Nexus est possible via le plugin maven publish. La configuration fournie dans la documentation est tellement bien faite ( comme le reste d’ailleurs ) que je ne vais que mettre un lien vers celle-là:
Voici le lien.

Conclusion

Après ces quelques actions vous pourrez démarrer des builds avec gradle tout en étant compatible avec un environnement « Maven ».
Enjoy 🙂

Partager des variables entre scénarios gatling

Je suis en train de mettre en œuvre des tests de performance avec Gatling. Un des principaux outils libres de tests de performance.

J’ai eu récemment à résoudre un « petit » soucis : je souhaitai partager des variables entre plusieurs scénarios. Il existe pas mal de solutions sur stackoverflow. J’ai condensé certaines d’entre elles pour les adapter à mon besoin.
Ces variables sont issues de exécution d’une seule requête et sont automatiquement injectées dans les scénarios suivants. Ce mécanisme permet par exemple de récupérer un jeton d’un serveur d’identification et de l’injecter pour le scénario que l’on souhaite tester.

Pour ce faire, il faut ajouter une variable de type LinkedBlockingDeque et injecter le contenu choisi via la session

 val holder = new LinkedBlockingDeque[String]() 
...
val firstScenario = scenario("First Simulation")
		.exec(http("first scenario")
			.post("/base/url1")
			.check(jsonPath("$.my_variable").find.saveAs("variable")))
		.exec(session => {
            holder.offerLast(session("variable").as[String])
            session}       
        );

Maintenant on peut l’utiliser dans un autre scénario comme feeder:

val secondScenario = scenario("Second Simulation")
		.feed(sharedDataFeeder)

Voici l’exemple complet



En espérant que cela puisse aider à certain.e.s d’entre vous 🙂

Programmmation par aspect avec Spring AOP

Une fois n’est pas coutume, voici un article qui reprend des basiques de la programmation. J’aborde une stack JAVA, mais c’est applicable à d’autres langages.

Il existe une fonctionnalité très intéressante dans Spring (et dans J(akarta)EE) que l’on oublie assez souvent : l’AOP ou encore la programmation par aspect. Cette manière de programmer permet notamment de séparer le code fonctionnel et technique.
Si vous faites du JAVA, vous utilisez déjà l’AOP. En effet, quand vous faites une insertion en base via JPA dans un EJB ou un bean annoté @Transactional, une transaction est initiée au début de la méthode et fermée à la fin.

Avec Spring et notamment dans Spring boot, voici comment initier l’AOP.

Configuration maven

Ajouter le starter AOP:

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

Activation des aspects

Dans la configuration ci-dessous, je prendrai comme exemple le logging des méthodes ( un log en début de méthode et un log en fin ). 

La définition des aspects se fait dans des classes annotées par @Configuration.

@Configuration
@Aspect
@ConditionalOnProperty(name = "debug.enabled", havingValue = "true")
public class DebuggingConfiguration {

private static final Logger LOGGER = LoggerFactory.getLogger(DebuggingConfiguration.class);
private static final String WITHIN_MY_PACKAGE = "within(my.package..*)";

/**
* Log before execution
*
* @param joinPoint the current method
*/
@Before(WITHIN_MY_PACKAGE)
public void logBeforeExecution(JoinPoint joinPoint) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Beginning of method : [{}]", joinPoint.getSignature().getName());
}
}

/**
* Log after execution
*
* @param joinPoint the current method
*/
@After(WITHIN_MY_PACKAGE)
public void logAfterExecution(JoinPoint joinPoint) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("End of method : [{}]", joinPoint.getSignature().getName());
}
}
}

L’utilisation de l’ annotation @ConditionalOnProperty me permet d’activer cette classe de configuration seulement si la propriété debug.enabled est initialisée à true.

Les annotations @Before et @After indiquent à Spring AOP quand exécuter ces méthodes ou sur quelles méthodes. Dans mon cas, quand les méthodes appelées sont définies dans les classes d’un package défini.

Pour plus de détails sur la syntaxe et les possibilités, vous pouvez vous référer à la documentation.


Comment coacher des jeunes développeurs – The last blood

Après avoir soumis mon article sur le coaching des développeurs, je me suis rendu compte que j’ai oublié pas mal de points qui, à bien y réfléchir, me paraissent essentiels.
Dans mon précédent article ( the first blood pour le coup ) je me suis attardé sur le « quoi » : toutes les actions que j’ai testé dans l’encadrement des jeunes développeurs et des développeurs en général.

Maintenant, je vais essayer de m’attarder sur le « comment » : ma démarche, la posture que l’on doit adopter ( ce n’est que mon ressenti ) etc.

Je vais commencer par ce dernier point. Quand on est architecte, développeur sénior ou bien encore tech lead, on est amené à encadrer techniquement des développeurs.

Vous pouvez adopter plusieurs postures:

A ce stade de lecture de cet article, vous vous dites, quelle est la bonne photo et donc la posture à adopter ?
A mon avis, elles sont à proscrire individuellement. Je pense qu’il faut les panacher.

Tout d’abord, il faut se souvenir de notre début de carrière et se rappeler du code que l’on a réalisé. J’ai par exemple gardé les premiers programmes réalisés en entreprise ( Servlet, JSP, JAVA 1.2, des méthodes de 3km de long, de la duplication de code en veux tu en voila, …) . Ça me permet de relativiser, d’être assez compréhensif et d’éviter de prendre les gens de haut.

Cependant, cette prise de conscience ne doit pas vous empêcher de faire progresser votre entourage et surtout de leur faire éviter les écueils que vous avez vécu. Les ateliers et documentation que vous pourrez leur transmettre sont donc primordiaux. Par exemple, faire lire « Clean Code » ou « Effective Java » aux développeurs – je ne l’oblige pas mais incite fortement – est un moyen de leur faire gagner du temps dans leur apprentissage du code.

Ensuite, même si vos padawans vous voient soit comme Pascal le grand frère ou maître Yoda (pour flatter mon égo), il ne faut pas oublier les exigences que vous avez fixé. L’industrie logicielle a gagnée en maturité en favorisant par exemple l’industrialisation via les outils de CI/CD ou bien encore en facilitant l’application de principes de qualité via des outils d’analyse des dépendances (dependency track) et du code (sonarqube). Vous devez vous adapter, favoriser l’adoption de ces pratiques et imposer quelques étapes qualité de préférence automatisée via de la CI.

Pour favoriser l’adoption de toutes vos exigences, je conseille d’y aller progressivement. Il ne faut pas oublier que votre objectif est de faire « grandir » vos collègues. Pour cela essayez de les adapter et les faire évoluer dans le temps.
Par exemple, pour les tests unitaires, commencez pas mettre en place les différents indicateurs qui vous permettront de mesurer la couverture de code. Ensuite, exigez un niveau de couverture de code (ex. 30%). Suivez le, via les quality gates SonarQube et enfin augmentez le progressivement : 30% , 40%,… Si vous commencez dès le début par un objectif trop haut, ce dernier paraîtra inatteignable et découragera tout le monde. Mieux vaut commencer volontairement très bas pour favoriser l’adoption.

Dans un autre domaine, pour vos workflows GIT, vous pouvez commencer dans un premier temps par le workflow de feature branch. Ce dernier posera les bases des pipelines CI, des merge requests et des bonnes pratiques liées à la gestion de configuration. Une fois tout le cérémonial lié à GIT assimilé par votre équipe, passer à GITFLOW sera beaucoup simple.

Bref, cette démarche revient à parler de conduite du changement. Il faut identifier vos exigences minimales. Celles-ci doivent être acceptées par votre hiérarchie ET par vos collègues. Sans ça vous échouerez!

Si ils vous soumettent quelques idées ou adaptations, n’hésitez pas à les incorporer. Ça peut faciliter l’adoption!

Ensuite, planifiez une progression sur 1 ou 2 ans. Cela donnera à vos collègues dans un premier temps des premiers objectifs atteignables puis une marge de progression leur permettant de s’améliorer.

Enfin, n’hésitez pas à faire un bilan ( par ex. au bout d’un projet ou après la première année ). Ou encore mieux, faites le faire par un de vos collègues pour avoir son ressenti. Cela mettra en exergue le chemin parcouru … et ce qu’il reste à faire 🙂

Conclusion

A mon avis le management et l’encadrement de personnes n’est pas à prendre à la légère. Votre attitude ainsi que la démarche que vous voulez mettre en œuvre feront autant voir plus que toute la documentation et formations que vous mettrez en place.