Ce mois-ci, nous nous intéressons à un code smell : l’usage de Lombok dans un projet. Entre code smell et antipattern, Lombok finit par apporter plus de problèmes que de solutions.
#1. Kézako ?
Lombok est une bibliothèque Java (et un plugin) qui simplifie la création de code fastidieux à l’aide d’annotations qui seront plus tard transformées en code Java. Si sur le papier, l’offre est alléchante, de nombreuses voix de développeur·euse·s s’élèvent pour nous inviter à arrêter d’utiliser ce plugin.
Une liste complète des annotations est disponible sur le site du projet. Mais comme nous allons le voir, elles ne sont pas toutes bien nommées voir incohérentes.
#2. Opacité du code
Toutes les annotations offertes par Lombok n’ont pas un comportement cohérent. Prenons par exemple l’annotation @ToString
. Appliquée à une énumération, vous obtiendrez…. le nom de l’énumération et pas de sa valeur.
Plutôt surprenant ! Pourquoi ce comportement ? Parce que l’annotation est faite pour générer un toString reprenant le nom de la classe et tous ses champs. Une classe plus classique donnera donc :
Et ce n’est qu’un exemple parmi tant d’autres. Sans rentrer dans autant de détails, avant son utilisation posez vous toujours la question de ce que fait l’annotation :
@AllArgsConstructor
: Construit un constructeur dans l’ordre de déclaration des attributs. Rajouter un attribut entre les autres casse tout le code existant.@Builder
: Construit un Builder technique qui ignore les cas métiers : tous les champs sont indépendants et optionnels.@Data
: Sert à pallier le manque de DataClass en java, mais que fait-il vraiment ? Il génère les getters et les setters de chaque attributs, ce qui ne reflète pas toujours les cas métiers une fois encore, et ajoute une méthode toString, laquelle peut-être dangereuse comme nous l’avons vu. En fait, @Data correspond à@ToString
et@Getter
@Setter
@NonNull
et@Cleanup
ne sont plus utiles à partir de Java 7 et
@var
depuis Java 10- …
#3. Opacité du build
De plus, Lombok va nécessiter une passe de précompilation pour générer le code « caché » par les annotations. Ce qui signifie… que le développeur n’a pas accès à ce code, ne peut pas placer de breakpoints et peut difficilement tracer les piles d’appels, que ce code n’est ni modifiable, ni testable, ni documenté (commenté). Des outils d’analyse statiques comme SonarQube seront donc toujours mécontents, entre coverage insuffisant et appel à des méthodes « qui n’existent pas ». De plus, cette passe de précompilation nécessite un plugin extérieur au code, qui soit installé soit dans l’IDE soit dans la configuration maven / gradle. Ce qui signifie qu’une personne sans cette dépendance (extérieure au code!) ne peut pas compiler le projet. Un projet sous Lombok impose l’utilisation de toute la grappe Lombok. Ce qui implique que si l’IDE nécessite une mise à jour et que le plugin n’est plus / pas encore compatible, bye bye le projet.
Et le code généré par Lombok repose sur une utilisation un peu douteuse de l’API java. Premièrement, l’API interne utilisée repose sur des méthodes disponibles dans seulement 2 compilateurs. Personne ne sait si il fonctionnera sur une autre version de JDK, ou si le projet utilise un compilateur différent. De plus, cette API interne utilise une API non publique, donc non supportée et sans assurance de maintien. De l’aveu même de l’auteur de Lombok : « It’s a total hack. Using non-public API. »
De plus, une bonne pratique est toujours de limiter le nombre de dépendances. Ajouter Lombok est donc une contre-performance dans beaucoup de domaines !
#4. Nos solutions conseils
Utiliser son IDE
La plupart des IDE modernes proposent des actions et des raccourcis clavier qui couvrent les cas les plus utilisés de Lombok: génération de getters, setters, constructeurs,….
Se poser la question du langage
Nous l’avons vu, changer la version de Java offre déjà une solution. Mais si le projet le permet, demandez vous si Java est la bonne solution. Les enfants spirituels de Java, Kotlin et Scala, proposent pas mal de sucre syntaxique (entre autre) palliant aux manques de Java. Comme ils compilent sur la JVM, on peut même faire cohabiter Java et l’un ou l’autre des langages (ou les deux !) dans un même projet, pour une migration en douceur.
Coder le métier et pas la technique
Le code généré par Lombok est principalement du code technique, sans intelligence métier. Pour reprendre l’exemple des getters et des setters, préférez une API interne à des dummy setters. Une API interne permet en effet de coder le métier dans l’objet concerné et de ne pas déplacer cette logique dans des couches externes. Prenons un exemple, un élève possède une liste de notes et sa moyenne :
Sans intelligence, on doit déporter le calcul de la moyenne ailleurs, probablement à un endroit qui n’a pas la responsabilité de connaitre l’implémentation du calcul.