Je travaille, sur un side-project. Une application pour une grande conférence française ;).

Lors du bootstrap du projet, je suis parti sur une stack technique assez classique. Pour servir l’api, j’avais choisi Akka-Http, au niveau BDD Postgres et pour la partie front VueJs/webpack/Yarn.

J’ai démarré comme ça et ça fonctionnait bien.

Depuis mes repositories, je remontais une Future[Either[E,V]] qui transitait par mes services avant d’arriver au niveau de mes contrôleurs.
Je pouvais, à chaque étape, appliquer une for-compréhension pour manipuler et transformer mes résultats.

Une approche très classique.

Amélioration continue

En tant que développeur, on cherche à améliorer son code, apprendre et rendre les choses plus pures et plus simples. 🙂

Je me suis intéressé aux IO Monad. Un concept que je ne maitrisais pas bien et que je voulais approfondir.

Après plusieurs lectures, discussions et tests.. tout cela prenait un sens.

Les futures devenaient le mal au profit des IO monads qui simplifiaient conceptuellement et concrètement le code.

La future est un type fourbe et pas déterministe. Je ne vais pas détailler ici, mais dans les lignes le type Future, selon la manière dont on l’utilise n’a pas le même comportement et de plus elle a une mémoire interne, ce qui peut poser des problèmes.

Du coup, on n’a pas la certitude, lorsque l’on exécute deux fois de suite un bout de code utilisant des futures que l’on n’aboutira au même résultat. C’est embêtant..

(Je noirci le tableau volontairement, mais le fond reste absolument vrai)

Maintenant que je maitrise mieux les principes derrières les IO Monads, je me suis jeté dans le grand bain et je me suis lancé dans un refactoring sur ma base de code.
L’intérêt d’utiliser une IO Monad, c’est d’encapsuler de bout en bout tous les effets de bord et de les exécuter au dernier moment.
Pour cela, il me fallait pour chaque couche technique la lib supportant le type IO.

Le couple Http4s et doobie étaient les bons candidats. Doobie s’interface avec postgres et Http4s sait exposer une API et tout ça en encapsulant les résultats et traitement dans une IO monad nativement.

Le type manipulé est devenu dans les couches abstraites : F[_], F étant une IO
Et dans l’implémentation IO[Either[E, V]], ou IO est l’abstraction provenant de la librairie Cats-effect.

La suite a été assez simple à mettre en oeuvre.

Mais alors quel intérêt d’utiliser ce concept ? (dans les grandes lignes)

Dans une IO Monad, on va s’attacher à décrire les effets de bord que le traitement va générer. Ceci tout au long du traitement.

Par exemple, on reçoit une requête Http, on fait une requête en BDD, ensuite on va écrire dans un fichier et enfin on va répondre à la requête. Tout ce traitement va créer des effets de bord. Ils vont alors être consignés au fur et à mesure. Lorsque l’on arrivera au moment de répondre le résultat, on exécutera l’ensemble des effets de bord.

Les avantages sont que l’exécution est complètement maitrisée. Si l’on exécute deux fois le traitements on a la garantie que celui sera exécuté de la même manière.
Aussi, il est possible de gérer de manière plus précise et plus explicite les différents contextes d’exécutions si l’on cherche à tuner notre code.

La réécriture a grandement simplifiée la base de code.

Il y a un effort au démarrage à faire pour adopter une nouvelle façon de voir les choses mais rapidement on en voit les bénéfices.

Cet article ne rentre pas dans le détail, mais fait une introduction générale.

N’hésitez pas à lire, discuter et à tester… 🙂

A disposition si vous avez des questions 🙂