REX : entamer une migration Kotlin dans une DSI Java
Tags: kotlin, java, migration, rex
Published: 2019-10-29 12:07:21


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](https://docs.google.com/presentation/d/1X7nhim9r0tU90c5UF5U-G6fwKW5hkcNQdV6N3xF-5Jg)

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](http://jeanphi-baconnais.gitlab.io/img/pe.png "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](http://jeanphi-baconnais.gitlab.io/img/archi_pe-fmk.png "Contete 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](https://devklaus.files.wordpress.com/2016/03/kotlinadoption.gif?w=700 "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](https://images.unsplash.com/photo-1506704810770-7e9bbab1094b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80 "Refus de passer à une solution full Kotlin")

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](http://jeanphi-baconnais.gitlab.io/img/archi_composant.png "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](http://jeanphi-baconnais.gitlab.io/img/classe_java.png "Classe Java")

en une classe Kotlin d'une seule ligne. Séduisant. 

![Classe Kotlin](http://jeanphi-baconnais.gitlab.io/img/classe_kotlin.png "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](http://jeanphi-baconnais.gitlab.io/img/clic_droit_migration.png "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](http://jeanphi-baconnais.gitlab.io/img/yes.png "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](http://jeanphi-baconnais.gitlab.io/img/la_suite.png "La suite de la migration")


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](http://jeanphi-baconnais.gitlab.io/img/mocck.png "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](http://jeanphi-baconnais.gitlab.io/img/jump.jpeg "Le saut en production")

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.