2021-01-03 11:09:51 +00:00
|
|
|
#+TITLE: voeux 2021 alexandre
|
|
|
|
#+Author: Yann Esposito
|
|
|
|
#+Date: [2021-01-03]
|
|
|
|
|
|
|
|
- tags ::
|
|
|
|
- source ::
|
|
|
|
|
|
|
|
|
|
|
|
Bonjour Alexandre, je te souhaite à toi et toute ta famille une très bonne
|
|
|
|
année 2021 !
|
2021-01-03 11:10:51 +00:00
|
|
|
|
2021-01-03 15:32:18 +00:00
|
|
|
Je vous souhaite à tous et à votre famille une très bonne santé surtout
|
|
|
|
dans le climat actuel.
|
2021-01-03 15:30:39 +00:00
|
|
|
De trouver un bon équilibre entre la vie familiale, les passions et le
|
2021-01-03 11:13:21 +00:00
|
|
|
travail.
|
2021-01-03 11:18:29 +00:00
|
|
|
|
2021-01-03 15:32:18 +00:00
|
|
|
Et je me permet d'ajouter à ce mail une réflexion technique entre Haskell
|
|
|
|
et Clojure qui je l'espère t'inspirera.
|
|
|
|
|
|
|
|
Bien que je n'écrive plus vraiment de nouvel article sur
|
|
|
|
Haskell/Purescript, j'ai passé pas mal de temps à réfléchir à comment
|
|
|
|
architecturer du code dans ces langages et Clojure.
|
|
|
|
J'ai l'impression qu'une solution qu'on utilise actuellement en Clojure
|
2021-01-03 11:18:29 +00:00
|
|
|
bien qu'à première vue très inférieure aux solutions proposées par
|
|
|
|
Haskell/Purescript sont en fait supérieure lorsqu'on les regardes selon le
|
|
|
|
bon angle.
|
|
|
|
|
|
|
|
L'idée de fond c'est que les systèmes d'effets/Free Monad (et les
|
2021-01-03 15:34:04 +00:00
|
|
|
sous-systèmes, style MTL, handler pattern) sont des cas particuliers
|
|
|
|
restreints de ce que l'on peut obtenir avec un système de "Services".
|
2021-01-03 11:44:52 +00:00
|
|
|
|
2021-01-03 15:34:04 +00:00
|
|
|
Si on regarde l'intérêt de ces systèmes d'organisation de code --
|
2021-01-03 11:44:52 +00:00
|
|
|
le plus évolué étant les Free Monads et les systèmes d'effets --
|
|
|
|
leur objectif est toujours plus ou moins le même.
|
|
|
|
|
|
|
|
Changer le comportement du même bloc de code en fonction du contexte
|
|
|
|
d'exécution.
|
2021-01-03 11:48:36 +00:00
|
|
|
En gros si on prend une function qui ressemble à:
|
|
|
|
|
|
|
|
#+begin_src haskell
|
|
|
|
my_function arg1 ... argn = do
|
|
|
|
x1 <- action1 arg1 .. argn
|
|
|
|
x2 <- action2 arg1 .. argn x1
|
|
|
|
...
|
|
|
|
z <- actionK arg1 .. argn x1 .. x<K-1>
|
|
|
|
return z
|
|
|
|
#+end_src
|
|
|
|
|
2021-01-03 11:51:04 +00:00
|
|
|
les =action1= à =actionK= auront des comportement différents en fonction du
|
|
|
|
contexte dans lequel il va être initialisé.
|
|
|
|
Dans le cas de Haskell, on fait au mieux pour déterminer le contexte à
|
|
|
|
compile time en utilisant les types.
|
|
|
|
Du genre:
|
|
|
|
|
|
|
|
#+begin_src haskell
|
|
|
|
main = do
|
|
|
|
effect1 <- initEffect1
|
|
|
|
effect2 <- initEffect2 effect1
|
|
|
|
...
|
|
|
|
effectM <- initEffectM effect1 ... effect<M-1>
|
|
|
|
runWithEffects [effect1,effect2,...,effectM] my_function
|
|
|
|
#+end_src
|
|
|
|
|
2021-01-03 11:54:34 +00:00
|
|
|
Ce système présente ainsi beaucoup d'avantanges:
|
2021-01-03 11:53:10 +00:00
|
|
|
|
2021-01-03 15:34:04 +00:00
|
|
|
1. mettre toute la "business logic" dans la fonction =my_function= en se
|
2021-01-03 11:54:34 +00:00
|
|
|
débarrassant des détails techniques au mieu en les envoyant dans les
|
|
|
|
"Effets".
|
2021-01-03 11:55:54 +00:00
|
|
|
2. Pouvoir facilement changer les Effects par des Effects purs et pouvoir
|
|
|
|
ainsi écrire des tests déterministes et reproductibles aisément.
|
|
|
|
3. Controller "par le haut" les sous-effets disponibles dans certaines
|
|
|
|
branches du code. On peut du coups facilement contraindre et voir que
|
|
|
|
certaines fonction ne pourront jamais accéder à la DB par exemple.
|
2021-01-03 11:57:08 +00:00
|
|
|
|
|
|
|
Par contre ce système à un coût sur les performances.
|
|
|
|
Je pense que le coût est négligeable dans la majorité des cas et qu'il
|
|
|
|
s'agit d'"Haskell circle jerking" lorsque les gens refusent d'utiliser
|
|
|
|
des systèmes d'effects pour cette raison.
|
2021-01-03 12:00:19 +00:00
|
|
|
|
|
|
|
Si on va au bout de l'utilisation de tel système en réalité on voit qu'il
|
2021-01-03 15:35:44 +00:00
|
|
|
faut, plutôt qu'utiliser des systèmes tout prêt à l'emploi, se créer
|
|
|
|
beaucoup d'effects maison pour en tirer le meilleur parti.
|
2021-01-03 12:00:19 +00:00
|
|
|
|
|
|
|
Typiquement on va avoir des effects avec leur pendant pur qui devraient
|
|
|
|
probablement être standards comme un effect de Log, d'accès complet à une
|
|
|
|
DB peut-être ?
|
2021-01-03 12:03:26 +00:00
|
|
|
Mais assez vite, on a envie de se fabriquer des Effets spécialisé au
|
|
|
|
domaine de son application.
|
|
|
|
Typiquement, si on fait de la gestion d'utilisateur on va créer un effet
|
2021-01-03 15:35:44 +00:00
|
|
|
pour la gestion d'utilisateurs plutôt que filer un Effet complet d'accès à
|
2021-01-03 12:03:26 +00:00
|
|
|
la DB.
|
|
|
|
Ce qui permet de s'assurer que des fonctions n'auront accès qu'aux tables
|
|
|
|
de la DB utilisées pour les utilisateurs et pas pour les tables destinées à
|
|
|
|
d'autres buts etc...
|
|
|
|
|
|
|
|
Et c'est là qu'apparaît la première limitation des systèmes d'Effets.
|
|
|
|
Les effets ont des dépendances entre eux.
|
|
|
|
L'effet =UserEffect= doit dépendre de l'effect =DBEffect=.
|
|
|
|
Mais probablement aussi de l'effet qui permet d'écrire des logs, et de pas
|
|
|
|
mal d'autres.
|
2021-01-03 15:37:03 +00:00
|
|
|
Et c'est à la lumière de voir ces effects comme des outils d'applications
|
2021-01-03 12:04:45 +00:00
|
|
|
pragmatiques et pas juste des "Effect algébriques" que l'on voit apparaître
|
|
|
|
un besoin de gestion de ces dépendances.
|
|
|
|
Un aspect important devient donc la gestion de l'ordre d'init et de stop de
|
|
|
|
tous ces effets.
|
|
|
|
En effet, pour faire =initUserEffect= il faudra lui passer en paramètre des
|
|
|
|
effets dejè instanciés (et donc initialisés) pour les logs et la DB.
|
2021-01-03 12:06:15 +00:00
|
|
|
|
|
|
|
Un premier problème est donc que changer/modifier des dépendances entre
|
|
|
|
effet dans un point du système revient à imposer une modification manuelle
|
|
|
|
du code dans tous les effets dépendants.
|
|
|
|
Mais aussi en particulier le code de l'init du système devient lourd à
|
2021-01-03 12:44:09 +00:00
|
|
|
gerrer alors qu'il existe une solution simple.
|
|
|
|
Je pense que Tardis pourrait être utile dans ce cas, mais, ça ne me semble
|
|
|
|
pas encore assez facile.
|
|
|
|
Même avec tardis, il me semble qu'il faut savoir si un effet doit arriver
|
|
|
|
avant ou après.
|
|
|
|
Là on souhaiterai pouvoir utiliser la lazyness pour une gestion
|
|
|
|
automatique des dépendances.
|
2021-01-03 15:23:48 +00:00
|
|
|
|
|
|
|
En réalité l'API la plus souhaitable serait de laisser la gestion de
|
|
|
|
l'ordre des dépendance et leur appel laissé à un système automatique.
|
|
|
|
Ainsi au lieu d'avoir
|
|
|
|
|
|
|
|
#+begin_src haskell
|
|
|
|
main = do
|
|
|
|
confEffect <- initConfEffect "config.dhall"
|
|
|
|
dbEffect <- initDBEffect confEffect
|
|
|
|
userEffect <- initUserEffect dbEffect confEffect
|
|
|
|
runWithEffects [confEffect,dbEffect,userEffect] myFunction
|
|
|
|
#+end_src
|
|
|
|
|
|
|
|
Il semble préférable d'écrire:
|
|
|
|
|
|
|
|
#+begin_src haskell
|
|
|
|
main = do
|
|
|
|
let effects = [ ConfEff, DBEff, UserEff ]
|
|
|
|
runWithEffects effects myFunction
|
|
|
|
#+end_src
|
2021-01-03 15:25:17 +00:00
|
|
|
|
|
|
|
Sans avoir à se poser la question de quel effet doit utiliser quel autre.
|
|
|
|
Ce sont des détails qui doivent être dans les Effets eux-même et pas donné
|
|
|
|
à une gestion manuelle par l'utilisateur.
|
|
|
|
|
|
|
|
Et c'est exactement ce que les systèmes de services font en clojure.
|
|
|
|
Il en existe plusieurs.
|
2021-01-03 15:26:18 +00:00
|
|
|
Component [fn:1] et Trapperkeeper [fn:2].
|
2021-01-03 15:28:09 +00:00
|
|
|
Je travaille avec le second.
|
|
|
|
|
|
|
|
Evidement en Clojure tout se gère en runtime.
|
|
|
|
Mais si j'ai bien lu et compris la présentation sur les différents systèmes
|
|
|
|
d'Effets il semble difficile de faire beaucoup mieux en Haskell.
|
|
|
|
Il est en effet très difficile de faire descendre dans le code le détail
|
|
|
|
qui permet de savoir dans quel contexte il sera exécuté et changer le code
|
|
|
|
pour utiliser seulement le bon contexte et l'optimiser en conséquence.
|
2021-01-03 15:26:18 +00:00
|
|
|
|
2021-01-03 15:30:39 +00:00
|
|
|
Finalement, j'ai vu des essais pour exploiter ces idées en Haskell.
|
|
|
|
Mais elles sont toutes faiblardes et échouent.
|
|
|
|
J'ai moi-même essayé.
|
|
|
|
Le probléme de fond vient du fait qu'il est quasi impossible de trouver un
|
|
|
|
type qui soit à la fois assez generique pour matcher ce que doit faire un
|
|
|
|
Service et assez précis pour être utile lors du typage du code.
|
|
|
|
|
2021-01-03 15:26:18 +00:00
|
|
|
[fn:1] https://github.com/stuartsierra/component
|
|
|
|
[fn:2] https://github.com/puppetlabs/trapperkeeper
|