Fin de crise d’ado en vue pour Play Framework

play_full_color J’avais écrit un retour d’expérience à propos de Play Framework il y a un peu plus d’un an. J’y exprimais ma frustration quant au fait qu’il ne manquait pas grand chose à Play Framework pour être un super outil de développement.

J’étais assez peu optimiste sur le fait que ces points puissent s’estomper rapidement parce que c’étaient ceux que Typesafe mettait en avant pour se différencier des autres. Il semblerait cependant que le vent a tourné récemment et il souffle maintenant de mon point de vue dans la bonne direction !

L’esprit de contradiction

J’ai choisi de manière provocatrice d’employer la notion de crise d’adolescence dans le titre de cet article. C’est en effet ce que m’inspirait la stratégie de Typesafe depuis le début du développement de Play Framework.

J’ai l’impression qu’à chaque fois qu’une question se posait ils avaient la volonté de ne surtout pas faire comme les autres. Je ne cherche pas à défendre l’idée qu’il faut faire comme ça parce qu’on a toujours fait comme ça, je sais bien que c’est souvent en faisant différemment qu’on innove. Mais l’exercice a ses limites et n’est pas toujours pertinent.

Typesafe a pendant longtemps revendiqué le fait de ne pas faire comme les autres. C’était sans doute leur façon à eux de se faire remarquer, de se faire une place dans ce monde technologique qui évolue si rapidement. Cette tendance ne concernait pas seulement Play Framework mais plus généralement l’ensemble des produits proposés par Typesafe, et notamment scala.

C’est bien entendu leur droit mais c’était parfois à la limite du ridicule. Je me souviens notamment avoir vu une présentation de Play Framework au Lyon JUG dans laquelle le présentateur nous expliquait qu’avec Play Framework on n’avait pas besoin d’IDE pour coder et il nous invitait à utiliser un simple éditeur de texte. Certes les IDE ne sont pas des outils parfaits, ils sont parfois gourmands en ressources, ils ont plein de défauts, mais ils nous assistent dans notre travail pour nous faire gagner du temps précieux, surtout avec un langage comme Java qu’ils maîtrisent très bien.

Cette page de la documentation montre quelques autres exemples de l’anticonformisme de Play Framework. Le nom des packages ne respecte volontairement pas la convention Java (pas de préfixe com.company). Au début on se dit c’est vrai, finalement autant ne pas s’encombrer avec ça, et puis à force de lire des stack traces, on se dit que finalement le préfixe permet très rapidement d’y voir plus clair. On peut également citer le fait que les sources de l’application sont dans le répertoire app au lieu du src/main/java habituel. Individuellement, ces exemples sont anecdotiques, mais, mis bout-à-bout, ils finissent par créer un environnement sensiblement différent de ce à quoi on est habitués pour un gain qui est bien souvent négligeable quand ce n’est pas contre-productif.

Changement de direction

Mon retour d’expérience concernait Play Framework 2.3. Nous en sommes maintenant à la version 2.5. La version 2.4 annonçait les premiers signes du changement, la version 2.5 récemment sortie confirme très largement ce changement de direction. Voilà les 3 principales améliorations récentes qui font que Play Framework est en train d’arriver à l’âge adulte.

Injection de dépendance

La version 2.4 annonçait la couleur. Elle encourage fortement les développeurs à utiliser l’injection de dépendance. Play gère désormais lui-même toute la partie injection de dépendance via Guice. Il faut noter que les versions précédentes ne fermaient pas complètement la porte à l’injection de dépendance mais c’était à nous, développeurs, de la gérer en prenant la main sur l’instanciation des contrôleurs.

La vraie bonne nouvelle pour moi dans ce changement c’est l’intention clairement annoncée dans les notes de version de la 2.4 de se débarrasser de la notion de contexte global (attaché au thread d’exécution de chaque requête) et par là-même de toutes les méthodes statiques qui permettent d’y accéder.

Je vois en ce changement une grosse amélioration au point de vue de la testabilité. L’injection de dépendances est en effet un élément à part entière des 5 principes de base SOLID de la programmation orientée objet. Une API définie via des méthodes statiques implique en effet un couplage fort vis-à-vis de son implémentation. Pour contourner ce problème, Play proposait des outils permettant de faire tourner son code de test au sein d’un faux contexte global, mais c’est encore bien plus simple si on peut se découpler complètement de ce contexte sans avoir à tout abstraire manuellement.

Le contexte global accessible de n’importe où présentait à mon sens un deuxième problème qui est également en train de disparaître. Il était tellement facile d’accéder au contexte (à la requête courante par exemple), qu’on a tendance à l’utiliser n’importe où, y-compris dans du code métier où ça n’a pourtant aucun sens. De base, nous avons tendance à nous coupler trop fortement aux outils que nous utilisons et ce mécanisme augmente largement la tentation de le faire.

Pour limiter l’impact lors des migrations il a été décidé de se séparer du contexte global version après version. La version 2.5 enfonce un peu plus le clou sur ce sujet-là en poursuivant le remplaçant du tout statique par l’injection de dépendance.

API Java enrichie

Je me demandais dans mon premier retour d’expérience si l’API Java de Play Framework (qui permet d’interagir avec Play en Java) n’était pas en sursis. En effet, Play Framework est écrit en scala et un module écrit en Java se charge de faire la passerelle avec l’API scala pour présenter une API exploitable en Java.

L’API Java était en effet largement incomplète et en retard par rapport à celle qui existe en scala. Certaines fonctionnalités n’étaient accessibles que depuis du code scala. On voyait bien que les développeurs Java n’étaient clairement pas la cible de Typesafe à l’époque et que cette API ne représentait donc pas une priorité.

La version 2.5 rattrape tout ce retard et met à niveau l’API Java par rapport à l’API scala.

Du code plus interopérable

Play Framework suit les principes du Reactive Manifesto. Il repose sur Akka et encourage à écrire du code non-bloquant (et donc asynchrone).

Java était assez mal outillé dans les versions précédentes dans ce domaine et ne proposait pas les structures nécessaires pour représenter une promesse. L’API de Play Framework amenait donc ses propres promesses pour compenser cette absence.

Or, si on veut jouer le jeu du code réactif, il faut que tout le code soit réactif (asynchrone), y-compris les accès à la base de données par exemple. Concrètement, cela signifie que l’intégralité du code devait être couplé à l’API de Play Framework pour utiliser les bonnes promesses. Il s’agit là encore d’une augmentation de couplage plutôt indésirable puisqu’elle est très néfaste pour la réutilisabilité du code.

Dans sa version 8, Java apporte le concept de CompletableFuture et propose ainsi une solution alternative aux promesses de Play Framework. La version 2.5 abandonne ainsi ses propres promesses pour utiliser ce qui est maintenant natif en Java. Il est désormais possible d’écrire du code Java standard asynchrone et compatible avec Play.

La migration vers la 2.5 est cependant très lourde pour ceux qui utilisent intensivement les promesses de Play Framework puisque, comme à leur habitude, les développeurs du framework ne s’embarrassent pas à maintenir la compatibilité entre les API des versions successives.

Conclusion

Ce changement de cap est très intéressant pour tous ceux qui travaillent avec Play Framework en Java. Il vient renforcer la crédibilité du framework pour répondre aux problématiques d’aujourd’hui et de demain.

Il semble s’inscrire dans un changement de stratégie bien plus vaste au sein de Typesafe dans lequel même le nom de l’entreprise a changé. Typesafe s’appelle désormais Lightbend. Ce changement a pour objectif de rendre leurs technologies plus agnostiques du langage de développement et donc s’éloigner un peu de scala. Ils justifient ce changement par le fait que la majorité de leurs clients utilisent leurs produits directement en Java.

SBT reste cependant toujours un problème pour moi. Je ne serais pas malheureux de pouvoir m’en passer. Après plusieurs années d’utilisation de Play Framework je ne suis toujours pas capable d’écrire ou de modifier tout seul mon fichier de build sans copier / coller des extraits de code trouvés sur internet. Notons quand même que les améliorations successives du support de Play dans les différentes versions d’IntelliJ IDEA sont très appréciables et permettent de masquer une partie de ce problème.

J’ai hâte de voir ce que nous apporteront les futures versions de Play Framework !

L’image en en-tête provient de Flickr.

6 réflexions au sujet de « Fin de crise d’ado en vue pour Play Framework »

  1. Merci pour cet article très intéressant. Je suis encore en 2.3.x et je n’ai pas passé le pas qui exige JAVA 8 mais les nouveautés de la 2.5 valent le coup de la migration. A voir au cas par cas, j’en ai un en tête truffé de Promises qui sera peut-être long et pénible à migrer 😉

    1. Salut Yax.

      Merci pour ton commentaire.

      Il est clair que la migration reste un point faible de Play. Depuis le début de la version 2, il n’y a pas eu une seule mise à jour qui s’est faite sans rien changer. Mais bon je crois que c’est malheureusement le prix à payer de notre côté pour avoir un outil qui évolue dans le bon sens. Changer de direction (ce qui est leur cas) tout en assurant la rétrocompatibilité, c’est un exercice très difficile. Ils ont fait leur choix, c’est pénalisant pour nous mais si ça leur permet d’investir davantage sur le futur du produit, pourquoi pas.

      D’ailleurs je ne suis pas encore passé à la version 2.5 parce que j’utilise deux outils qui ne sont pas encore compatibles avec cette nouvelle version (les librairies doivent elles aussi faire une version par version de Play…).

      Courage pour la migration, ça en vaut la peine !

  2. Retour intéressant c’est vrai que l’injection de dépendances rend les choses plus faciles à tester. L’intégration avec Akka Streams est le gros point fort de cette version 2.5 pour moi, notamment pour API Java (beaucoup de choses manquantes dans la partie Java venaient des Iteratee qui ont été dépréciés).

    Concernant l’arborescence des fichiers dans app/ ce n’est pas pour faire différemment mais plutôt pour faire comme les frameworks web que l’on trouve dans d’autres stacks comme ruby on rails, dont play s’est inspiré à sa création.

    Petite précision le contexte global des versions précédentes n’était pas attaché au thread de la requête courante, le modèle 1 requête = 1 thread ne s’applique pas pour play (du fait de son approche asynchrone et des IO non bloquantes).

    1. Bonjour Loïc et merci pour ce retour.

      Pour ce qui est des sources dans le répertoire /app, je me souviens que c’est en effet un des arguments qui étaient mis en avant pour montrer que c’était aussi simple avec Play qu’avec symfony ou d’autres outils. J’ai cité cet exemple-là mais c’est pas le plus gênant. C’est simplement qu’à force d’accumuler des petits détails de ce genre ça finit par être un peu déstabilisant pour des développeurs Java.

      Pour le contexte accessible en static, j’avoue que je n’ai pas trop creusé la question pour savoir à quel endroit il est récupéré. J’imaginais qu’il était attaché au thread. Même si l’exécution est asynchrone, ça n’empêche pas de positionner le contexte dans le thread juste avant de commencer l’exécution non ? Mais du coup ça m’intéresse de savoir comment ça fonctionne !

      Et d’ailleurs je crois savoir que ça a changé en Play 2.5 et qu’à partir de maintenant on ne peut plus récupérer ces informations-là en static dès lors qu’on a rendu la main une fois. Est-ce exact et si oui comment ça se fait techniquement ?

      Merci !

  3. Bonjour,

    Article très intéressant !

    Juste un petit commentaire pour dire que le D de SOLID ne correspond pas à « Dependency Injection » mais à « Dependency Inversion », ce qui est un peu différent. J’ai longtemps fait la confusion moi-même. Il existe bon nombre d’articles à ce sujet.

    Damien

    1. Merci Damien pour cette précision !

      Je crois qu’on peut rajouter Inversion of Control dans la liste des concepts proches mais pas tout à fait identiques avec lesquels il y a pas mal de confusion.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.