REX : Entamer Une Migration Kotlin Dans Une DSI Java

Cet article est issu d’une prĂ©sentation que j’ai rĂ©alisĂ©e en interne Ă  la DSI de PĂ´le emploi, mais aussi Ă  l’extĂ©rieur, que ce soit au NantesJug en juin et au JugSummerCamp en Septembre. Les slides sont disponibles ici

Cette prĂ©sentation est un retour d’expĂ©rience sur la manière dont j’ai intĂ©grĂ© Kotlin dans la DSI de PĂ´le emploi, historiquement en Java. Je ne vais pas vous montrer comment rĂ©volutionner une DSI Java mais plutĂ´t la manière dont j’ai intĂ©grĂ© Kotlin Ă  cĂ´tĂ© du Java pour dĂ©velopper nos applications.

Contexte de la DSI de PĂ´le emploi

Le langage historique Ă  la DSI est comme beaucoup d’entreprise Ă  cette Ă©poque pour du back end, le Cobol. Java a fait son apparition dans l’Ă©cosystème PĂ´le emploi Ă  partir des annĂ©es 2000. Au dĂ©part un framework dĂ©veloppĂ© en interne permettait de rĂ©aliser les applications pour les agents. Ce framework permettait de cadrer le dĂ©veloppement en proposant de gĂ©nĂ©rer le code Ă  partir de diagramme.

En 2007 une importante Ă©tape de modernisation a eu lieu, afin de basculer vers du microservices avec des API REST. Le framework interne est prĂ©sent mais est rĂ©duit pour contenir uniquement des briques techniques. J’en parlerai d’avantages par la suite. Et c’est Ă  partir de 2018 que j’ai commencĂ© mes tests pour intĂ©grer du Kotlin dans ces API REST Java.

Contexte PĂ´le emploi

Notre framework interne

Comme je le disais précédemment, notre framework interne est toujours présent, et a deux objectifs principaux : harmoniser toutes nos API REST et faciliter le développement fonctionnel.

Contexte PĂ´le emploi FMK

L’harmonisation permet d’avoir les mĂŞmes services techniques de supervision, mĂ©trologie, logging, etc sur toutes les API REST dĂ©veloppĂ©es Ă  PĂ´le emploi. Les OPS peuvent donc intervenir sur les API de la mĂŞme manière quelque chose l’API.

Lors du dĂ©veloppement, certaines briques sont redondantes comme l’accès Ă  un annuaire, la gestion d’exception. Grâce ua framework, les dĂ©veloppeurs ne s’occupent plus de cela.

Et le Kotlin dans tout ça ?

Kotlin est un language qui depuis 2012 n’arrĂŞte pas de voir sa cĂ´te de popularitĂ© augmentĂ©e grâce Ă  ses fonctionnalitĂ©s qui plaisent aux dĂ©veloppeurs.

Popularité Kotlin

Quel dĂ©veloppeur Java n’a pas rencontrĂ© des Null pointer ? Koltin permet d’Ă©viter cela. Les coroutines, extensions de mĂ©thode sont des features qui plaisent. Les dĂ©veloppeurs apprĂ©cient et cela se voit, que ce soit dans les meetups prĂ©sents dans diffĂ©rentes villes de France, et dans les confĂ©rences. Après avoir assistĂ© Ă  une Nigthclass Zenika me permettant d’apprĂ©hender et de dĂ©velopper une application en Kotlin, j’ai Ă©galement Ă©tĂ© sĂ©duit. Pratiquer sur le temps perso pour faire un simple hello world sans avoir de rĂ©el projet au quotidien n’est pas le meilleur moyen de progresser dans un langage.

De ce fait visons le quotidien profressionnel. Dès le lendemain j’en ai parlĂ© avec les urbanistes et les architectes de la DSI de PĂ´le emploi et je leur ai dit “les prochains dĂ©veloppements seront fait en Kotlin” … ils m’ont gentillement refuser.

https://unsplash.com/photos/1k3vsv7iIIc

Et oui, dĂ©velopper dans le contexte de PĂ´le emploi un composant en Kotlin serait complexe de par sa complexitĂ© d’intĂ©gration dans les règles et bonnes pratiques de la DSI. Toutes les briques framework serait Ă  recoder en Kotlin et vu le nombre, un simple test prendrait un temps fou ! La suite logique serait de dire qu’on va y aller doucement.

L’intĂ©gration de Kotlin dans notre Ă©co-système

Kotlin utilisant la JVM, il Ă©tait donc logique de se dire qu’un composant dĂ©veloppĂ© en Java peut contenir des classes Java appelant des classes Kotlin et vice-versa. C’est donc l’option utilisĂ©e.

Mais tout d’abord voyons l’architecture fonctionnel de nos composants Ă  PĂ´le emploi.

Architecture de composant

Le choix de migration s’est portĂ© sur les “entrĂ©es / sorties”, ces beans Java qui ne contiennent qu’en fait des attributs avec getters et setters, des mĂ©thodes equals, hascode, un bean très classique et ressemblant Ă  l’exemple mentionnĂ© sur le site de Kotlin. Et leur exemple convertit une classe constituĂ©e de 2 attributs, produisant un fichier d’une trentaine de ligne,

Classe Java

en une classe Kotlin d’une seule ligne. SĂ©duisant.

Classe Kotlin

Les Ă©tapes de modification de notre composant

Pour effectuer cette intégration de Kotlin dans un composant Pôle emploi, il y a plusieurs étapes :

1/ installer le plugin Kotlin dans l’IDE.

2/ cela permet d’avoir une fonctionnalitĂ© de conversion de classe Java en classe Kotlin, que ce soit sur un fichier ou un package, pratique.

Migration avec un clic droit

3/ j’ai pris le choix de dĂ©placer les classes Kotlin dans un rĂ©pertoire “kotlin” au mĂŞme niveau que le rĂ©pertoire “java”. Rien de rĂ©volutionnaire mais une bonne pratique.

4/ ajouter la dépendance Kotlin au projet

<dependency>
  <groupId>org.jetbrains.kotlin</groupId>
  <artifactId>kotlin-stdlib-jdk8</artifactId>
  <version>${kotlin.version}</version>
</dependency>

5/ déclarer les ressources java et kotlin

<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
    [...]
<configuration>
    <sourceDirs>
        <source>src/main/java</source>
        <source>src/main/kotlin</source>
        <source>src/main/resources</source>
    </sourceDirs>
</configuration>

6/ A ce stade différentes erreurs de compilation sont présentes, comme par exemple :

Erreur de compilation : Property must be initialized or be abstract : cette erreur Ă©tait due au fait d’avoir des classes sans setter. La conversion Kotlin a donc produit des classes avec des attributs typĂ©s val et donc non modifiable. Or il y avait un peu de rĂ©flexion qui modifiait les beans. Un passage en var rĂ©solvait ce problème.

Des classes Ă©taient converties en companion pour stocker des constantes. Cela provoquait des erreurs et l’annotation @kotlin.jvm.JvmField permet de corriger ce problème.

7/ Le dernier point et le plus impactant, que ce soit en terme de temps passĂ© et de fichier impactĂ©s : les tests unitaires. L’intĂ©gration de Koltin implique un passage de la version de Mockito 1.9 en 2.x (2.23 au moment du test). La librairie whitebox de Mockito Ă©tait utilisĂ©e pour faire de la rĂ©flexion … Personnellement je ne suis pas fan de rĂ©flexion dans les tests, en tout cas dans ce composant. Mais pour corriger les erreurs de compilation et ne pas refaire tous les tests unitaires du projet, j’ai remplacĂ© l’utilisation de cette librairie supprimĂ©e dans la version 2.23 de Mockito par de la rĂ©flexion Java standard.

et un dernier point c’est cette erreur :

org.mockito.exceptions.base.MockitoException: Cannot mock/spy class data.MiniSite
Mockito cannot mock/spy because :
 - final class

En regardant sur les forums, on trouve rapidement une correction Ă  cette erreur. Il s’agit d’un hack nommĂ© “mock-maker-inline” qui consiste Ă  crĂ©er un fichier vide “mock-maker-inline” et notre erreur est rĂ©solue … Admettons !

Et Ă  ce stade la, notre composant fonctionne !

Yes

  • Le composant compile,
  • un mvn clean install nous permet d’avoir un ear de notre composant,
  • il se dĂ©ploie sur notre version de weblogic,
  • aucune rĂ©gression n’est constatĂ©e, que ce soit via un client REST comme postman, ou via les composants graphiques du projet.
  • par contre je suis d’accord pour dire que la plus value n’est pas exceptionnelle et comme argument pour annoncer haut et fort que nous avons dĂ©veloppĂ© un composant en Kotlin Ă  PĂ´le emploi n’est pas le mieux adaptĂ©.

Par contre, on peut acter qu’on a intĂ©grĂ© du Kotlin dans nos composants Java, et cela est transparent sur notre projet !

La suite ?

Il ne faut pas en rester lĂ , la première Ă©tape d’intĂ©gration du Kotlin a Ă©tĂ© faite mais l’objectif est plus loin. Si on reprend notre architecture de notre composant, il est prĂ©fĂ©rable d’utiliser les fonctionnalitĂ©s de Kotlin pour dĂ©velopper le coeur de mĂ©tier de notre composant.

La suite

Et je pense dans un premier temps aux coroutines, ces Ă©lements d’asynchrone, facilement utilisable et gĂ©rable lors des dĂ©veloppements, qui pourraient nous permettre d’exĂ©cuter plusieurs traitements en parallèle comme des rĂ©fĂ©rentiels. Actuellement, mĂŞme si on peut gĂ©rer des threads en Java, ces rĂ©fĂ©rentiels sont appelĂ©s en synchrone. Avec les coroutines, on pourrait lancer en parallèle les rĂ©cupĂ©rations de rĂ©fĂ©rentiels, et une fois toutes les rĂ©ponses rĂ©cupĂ©rĂ©es, continuer notre traitement mĂ©tier. Cela pourrait nous faire gagner du temps d’exĂ©cution de notre API Rest.

println("Start")

// Start a coroutine
GlobalScope.launch {
    delay(1000)
    println("Hello")
}

Thread.sleep(2000) // wait for 2 seconds
println("Stop")

Ensuite on pourrait imaginer revoir les tests, pour remplacer les tests (et bricolages) java par une librairie de test Kotlin comme Mockk.

Mockk

Cela permettrait de faire des tests dans une structure given / when / then Kotlin pour tester nos claseses et traitements codés dans ce même langage.

val car = mockk<Car>()
every { car.drive(Direction.NORTH) } returns Outcome.OK
car.drive(Direction.NORTH) // returns OK
verify { car.drive(Direction.NORTH) }
confirmVerified(car)

Et la dernière Ă©tape serait de bencher ce composant. A la DSI de PĂ´le emploi, plusieurs Ă©tapes de validation sont nĂ©cessaires pour informer des modifications et livraisons faites dans nos composants en production. Leur annoncer que le composant contient du Kotlin pourrait faire grincer les dents. Alors leur fournir cette information avec comme “preuvre” des rĂ©sultats de bench pourrait permettre de montrer Ă  la direction que oui il y a du kotlin dans nos composants, mais que cela a des rĂ©sultats positifs sur les temps de rĂ©ponse du composant.

Crédit https://unsplash.com/photos/gdAuwo-qj5k

Et bien sur, la dernière Ă©tape serait d’aller en production, et cela n’est pas encore le cas, mĂŞme si seulement les “entrĂ©es / sorties” ont Ă©tĂ© migrĂ©es en Kotlin, il y a un contretemps qui n’a rien Ă  voir avec Kotlin. Des attaques nous sont tombĂ©es dessus, faisant tomber le site pole-emploi.fr. Le composant a donc Ă©tĂ© surveillĂ© de près, et je ne me voyais pas leur prĂ©senter mes arguments de migration Kotlin tant que ce n’Ă©tait pas rĂ©solu. Depuis plusieurs mois, les problèmes ont Ă©tĂ© rĂ©solus, des benchs ont Ă©tĂ© faites sur la partie full Java, me permettant d’envisager de livrer mon composant avec du Kotlin et de comparer que les temps de rĂ©ponses sont identiques (ou mieux) qu’avec le composant Java. Cela me laisse voir une installation en production de ce composant avec du Kotlin dans l’annĂ©e.

Cela permet de valider le test et d’offrir la possibilitĂ© aux dĂ©veloppeurs Kotlin ou voulant se mettre Ă  ce langage qu’ils peuvent dĂ©velopper des composants Ă  la DSI de PĂ´le emploi avec ce langage.

Merci de votre lecture.