Bonjour

Au sein de mon département nous sommes amenés à développer de nombreuses petites applications pour des besoins très spécifiques de niche.
Nous avons (c'est mon rôle dans l'équipe) choisi JEE. Nous avons délibérément écarté des framwork plus populaires ou plus complets sur certains points pour nous en tenir à la "norme". Notre but étant de rester le plus indépendant possible d'un constructeur ou d'une librairie.
Nos applications étant déployées ici ou là par des personnes que nous ne connaissons pas. Nous voulions que ce soit "facile" et adaptable à l'environnement de chacun. Le choix de JEE permet à chacun de choisir son conteneur même si nous avons ciblé JBOSS/Wildfly (nous n'avons pas utilisé les spécificités de ce conteneur) Tomcat n'est pas un conteneur JEE même s'il est un peu plus qu'un conteneur de WAR.

Autre choix déterminant une application un livrable.
Quant à l'architecture logicielle nous avons choisi Angular pour le front, et java pour le back, le tout, front et back embarqué dans un seul livrable à déployer. JEE n'est peut être pas le meilleur serveur pour les ressources statiques mais entre avoir un gain marginal dans notre contexte de perf et complexifier le déploiement par des personnes dont ce n'est pas le métier et avoir un livrable à déposer dans un serveur d'appli nous avons choisi le second.

Nous avons tout de même bien structuré notre livrable en couches.

Les choses évoluant, ayant à disposition une plateforme kubernetes/docker disponible pour tous et des "clients" plus aguerris (pour certains)

Nous avons cherché à revoir ces choix sans tout remettre en cause.
Et c'est dans ce cadre que j'ai évalué diverses solutions dont celle que nous avons retenue: Quarkus.

Un point à noter est que nous avons au fil du temps développé des modules réutilisables tant côté front, que back afin d'accélérer les développements de nos applications.

Nous avons donc cherché à voir comment passer de JEE à Docker sans avoir à tout refaire ni en embarquant un serveur JEE complet dans une image Docker. (une seule application dans un conteneur d'applications dans un conteneur docker n'a pas beaucoup de sens)

Nous avons donc lancé sur un nouveau projet le développement avec Quarkus. 1ere phase faire une application exécutable d'un seul bloc. Une partie de nos clients reste peu expérimentés et lancer un seul exécutable est bien plus sûr que de devoir déployer toute une architecture faite de plusieurs éléments.

J'avoue ne pas avoir fait beaucoup de chose personnellement si ce n'est que déblayer le terrain et orienter le développeur (vu qu'il est seul)
Nous utilisons RBAC dans nos dev et là rien n'a changé
question découpage pas de changement
Une contrainte forte mais non bloquante pour ce premier projet Quarkus accepte plusieurs connexions JDBC mais UNE SEULE datasource JPA.
Là encore tous nos modules JPA ont été portés sans changements.
Pour ce qui est du lien entre le front et le back nous utilisions REST et ça n'a pas changé.

Je pourrais continuer car finalement même le développeur qui est plutôt moins expérimenté JEE s'en est sorti sans aucune difficulté. Je serais tenté de dire que c'est un développement JEE comme les autres.

Il y a tout de même quelques bémols.
CDI: nous n'avons là encore pas rencontré de difficulté mais nous avons dû réviser notre code existant.
L'injection de dépendance est réalisée par les implémentations CDI en mettant à jour un membre de la classe depuis l'extérieur de la classe. Or l'habitude veut que le membre soit privé. Pour faire cette mise à jour CDI va par introspection récupérer une référence au membre, outre passer la restriction "private" et faire l'affectation. Il se trouve que pour compiler en mode natif Quarkus utilise les capacités de GraalVM. Et GraalVM par mesure d'optimisation n'autorise pas par défaut l'introspection. Il faut pour cela déclarer toutes les classes pour lesquelles on veut pouvoir faire de l'introspection. Une contradiction totale avec le fonctionnement de CDI qui à priori le fait sur toutes les classes. Une autre particularité de Quarkus est que cette injection ne sera pas faite au runtime mais si possible à la compilation. Pour résoudre le problème Quarkus propose de passer les membres "injectables" avec la visibilité "package" (ou de déclare la classe pour l'inspection) nous avons donc revu la visibilité de tous nos membres. (Quarkus explique comment on peut le garder privé tout en évitant l'introspection mais ça demande un peu plus de taf)

Et enfin l'autre point sur lequel nous avons eu des difficultés est l'usage des BlockingIO JPA se base sur JDBC qui utilise des accès aux bases avec des BlockingIO. Ce n'est pas directement lié à Quarkus mais au fait que Quarkus par défaut utilise Vert.X et autres librairie asynchrone.
Nous avions donc au départ des Warnning fréquents sur l'usage de BlockingIO et de temps en temps une stackException dans les logs.
Il nous a fallu chercher comment avec Vert.X ou une autre des librairies disponibles dans Quarkus encapsuler les appels à JPA dans un contexte non bloquant. Au final la solution la plus simple est venue de Mutiny https://smallrye.io/smallrye-mutiny/ qui est fournie avec Quarkus.

Un petit passage dans nos ressources REST et elles sont toutes devenues réactives et non bloquantes.

Côté code donc très peu de changements, juste quelques adaptations mineures.
Sans changer notre environnement de travail la compilation par défaut nous permet de fournir un Jar autonome
le client peut le lancer par
Code : Sélectionner tout - Visualiser dans une fenêtre à part
>java -jar monApplcation-runner.jar
Après installation de GraalVM et des outils associés. La compilation native c'est faite sans difficulté et l'application se lance simplement par Dans les deux cas il faut fournir un fichier conf/application.yaml ou conf/application.properties pour la paramétrer. On y retrouve les paramètres qu'on déclarait dans le serveur JEE.

Un point il faut prévoir à la compilation la façon dont se fait la sécurité alors que dans JEE cela était délégué au serveur d'application.

La dernière étape et à partir du fichier de conf et de l'exécutable faire une image docker et là encore c'est prévu nativement dans Quarkus.

On pourrait dire à ce stade que finalement Quarkus nous a apporté clef en main les processus de build qui vont jusqu'à généré l'image là ou nous nous arrêtions à la production de WAR ou un EAR.
Mais si vous avez bien lu j'ai dit à un moment que les injections étaient faites si possible à la compilation.
Ce n'est pas la seule chose qui le soit. Quarkus vise à faire le maximum de chose à la compilation quand c'est possible. Instancier des objets en fait partie.
La compilation va donc produire un code qui dispose déjà des objets et qui pourra les exploiter la où le fonctionnement de la JVM va chercher la classe, vérifier qu'elle est utilisable (sécurité), charger la classe, instancier ses membres statiques, instancier un objet, initialiser ses membres, exécuter son constructeur. Là seulement elle pourra l'exploiter.
résulta sur ma machine le temps de démarrage
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
>java -jar monApplcation-runner.jar //0,305s
>monApplcation-runner           //0,003s
Au final à ce jour nous n'avons quasiment pas changé nos habitudes pour produire une petite application sous forme d'un seul livrable. C'est même plus simple pour nos clients inexpérimentés. Unzip, Edit application.yaml, Run.

Reste un point qui a dû en faire bondir plus d'un. UNE SEULE datasource. Nous avons tous des applications qui se branchent sur plusieurs datasources.
La contrainte parait forte. Mais en fait elle ne l'est pas tant que ça. Bien qu'elle ne soit pas sans impact.
Quarkus est très orienté microprofile et donc si on se met dans cet état d'esprit notre application qui aujourd'hui compile sous la forme d'un seul exécutable est en fait un assemblage d'un jar qui contient le front, et autant de jar que de sous domaines fonctionnels dans le back. Chacun contenant toutes les couches de l'exposition du service Rest jusqu'à la persistance.

En compilant avec Quarkus chaque sous-domaine dans un exécutable on obtient un sous domaine un exécutable un service.
En déployant tout ça derrière un reverse proxy notre application fonctionne.

Et nous nous retrouvons avec la contrainte un sous domaine fonctionnel -> un service -> un exécutable -> une datasource.
Donc autant de datasources que de sous domaines fonctionnels.

Cette façon (éclatée) de déployer des applications est courante et maitrisée dans le SI. Beaucoup moins chez nos clients dont le métier n'est pas l'informatique. Nous allons continuer à produire de petites applications sous forme d'exécutable et d'autres plus complexes en environnement docker sous forme modulaire.

Voilà pour ce premier retour sur notre approche de Quarkus.
A+JYT