ScalaIO 2018 - Le retour de l'équipe Univalence

ScalaIO est une conférence tournant autour du langage Scala, de son écosystème (Akka, Spark, Play...) et aussi autour de tout ce qui touche de près ou de loin à la programmation fonctionnelle, quelque soit le langage (Haskell, OCaml, JavaScript, TypeScript...). La session ScalaIO 2018 a eu lieu entre le 29 et 31 octobre au CPE à Lyon.

Pour l'occasion, l'équipe d'Univalence ont fait le déplacement. Ils reportent ici leurs impressions.

Les keynotes

Nous avons eu droit à trois keynotes :

  • Towards Scala 3 - A Status Report par Martin Odersky, le deuxième jour en ouverture.
  • ZIO: Next Generation Effects in Scala par John De Goes, le troisième jour en ouverture.
  • Future of Scala par Jon Pretty, le troisième jour en fermeture.

Towards Scala 3 - A Status Report par Martin Odersky

Le talk d'Odersky fut en partie une redite de son talk présenté lors de ScalaDays Berlin en mai dernier (disponible sur Youtube) et lors de ScalaDays New York en juin dernier (disponible aussi sur Youtube). Si vous avez loupé ces sessions, sachez qu'avant l'arrivée de Scala 3 prévue pour 2020, il y aura une version 2.13 prévue pour février 2019. L'objectif sera d'orienter le langage vers plus de simplicité et de réduire les puzzlers (comprenez des expressions Scala valides dont le résultat est contrintuitif).

Dans ce qui va arriver :

  • Une notation pour les types union A | B (par exemple String | Null) et une nouvelle notation pour les types intersection A & B (le mot-clé with disparaîtra progressivement).
  • Les types de fonction implicite implicit A => B, ce qui va permettre de créer des contextes de traitement.
  • Une syntaxe pour les enums avec la possibilité de les paramétrer. Par exemple ci-dessous, nous voyons une autre façon d'écrire le type Option.
    enum Option[+T] {
      case Some(x: T)
      case None
    
      def isDefined: Boolean = this match {
        case None => false
        case some => true
      }
    }
  • Nous pourrons mettre des paramètres dans les traits trait MyTrait(x: String).
  • La fin de la limite à 22 paramètres pour les fonctions et les tuples : nous pourrons mettre autant de paramètres que nécessaire. Les tuples seront réimplémentés afin d'avoir une vision plus proche des HList de Shapeless ((a, b, c) == (a, (b, (c, ())))).
  • L'égalité multiversale, c'est-à-dire la possibilité de comparer deux types différents que dans le cas où un implicite basé sur Eq a été déclaré.
  • Une notation pour les types lambda type T = [X] => F[X] (qui équivaut à type T[X] = F[X]).

Une volonté est marquée de séparer un peu plus Scala de Java. Dans ce cadre, Odersky propose TASTY. TASTY est un format de sérialisation d'AST (Abstract Syntax Tree) typé. Il faut le voir comme un format intermédiaire généré juste après les premières phases de compilation et de type checking. Libre ensuite aux phases suivantes de transcrire le format TASTY vers d'autres formats : Java byte code, Javascript, code machine natif, etc. Le format TASTY peut aussi être utilisé à destination des IDE pour une meilleure intégration du langage.

Si TASTY sera pleinement fonctionnel pour Scala 3 (il est développé dans le cadre de Dotty, qui représente en quelque sorte le futur de Scala), sa mise en place pour Scala 2.x est encore en cours d'étude. La plus grosse difficulté concerne actuellement les macros. Il y a deux types de macros :

  • Blackbox : ce sont des macros qui interviennent après la phase de type checking. Les informations sur les types sont complètement résolus.
  • Whitebox : ce sont des macros qui interviennent avant la phase de type checking. Les informations sur les types dans les signatures sont imprécises.

Or les macros whitebox vont disparaître avec Scala 3. Pourtant, plusieurs frameworks Scala dépendent des macros whitebox, comme par exemple SCio (présenté dans l'après-midi même). Odersky recherche actuellement une solution au niveau langage pour pallier la disparition des macros whitebox (😢).

Pour terminer, Odersky nous propose à travers Visual Studio Code une démonstration des nouvelles capacités de Dotty au niveau des types : par exemple la représentation de l'inversion d'un tuple avec de nouvelles fonctionnalités pour transformer les types (pattern matching au niveau du système de type).

type Append[+X <: Tuple, Y] <: Tuple = X match {
  case Unit      => Y *: Unit
  case x1 *: xs1 => x1 *: Append[xs1, Y]
}

type Reverse[+X <: Tuple] <: Tuple = X match {
  case Unit      => Unit
  case x1 *: xs1 => Append[Reverse[xs1], x1]
}

def reverse[T <: Tuple](xs: T): Reverse[T] = ???

def r: (Boolean, String, Int) = reverse((1, "", false))

ZIO: Next Generation Effects in Scala par John De Goes

Pour l'occasion, John De Goes a renommé son talk en "Beautiful Scala". Un talk démarrant par la Genèse revue et corrigée du point de vue du développeur fonctionnel !... Avec quelques trolls au passage :

  • Sur les outils : "Il y a deux types de programmeurs : ceux qui utilisent les éditeurs de texte et ceux qui utilisent les beaux IDE".
  • Et surtout sur la programmation objet : lors d'une discussion entre le serpent et l'homme le développeur : "An apple is a plant which has seeds and is the receiver of being-eaten".

Là dessus, John fait une transition à l'ancien testament (toujours revu et corrigé) en présentant les tables de la loi du développeur et ses 10 commandements, tout en parlant de son framework scalaz-zio (ou ZIO).

  1. Une fonction doit être totale, déterministe et sans effet de bord.
  2. Les effets doivent être réifiés. Il faut donc utiliser la notation IO[E, A] de ZIO. IO représente tout processus impliquant possiblement un effet. C'est-à-dire une étape de calcul dans laquelle la modification du système est observable. Dans IO[E, A], A représente le type de la valeur attendu par le processus et E représente le type retourné en cas de problème.
  3. Il ne faut pas bloquer les threads (pour des raisons de performance). C'est tout l'intérêt des fibres qui peuvent être vues comme un thread léger et se retrouvent à la base de ZIO. Les fibres dans ZIO sont notées Fiber[E, A]. Elles permettent d'éviter le callback hell et peuvent être gérées par le GC, même si la fibre contient une boucle infinie.
  4. Des ressources managées. ZIO propose deux opérations bracket et managed qui permettent de gérer des zones de code à la manière de try with resource en Java dans lesquelles les ressources comme les fichiers ou les connexions à un service sont gérées sans que le développeur n'ait besoin de rentrer dans les détails techniques.
  5. Ne pas avoir peur de la concurrence. L'objectif est de mettre en place une abstraction donnant une perception claire de la concurrence. Pour cela, ZIO propose deux opérations : parAll pour récupérer le résultat de toutes les fibres exécuter en même temps et raceAll pour récupérer le résultat de la fibre ayant répondu en premier parmi plusieurs, sachant que les autres fibres sont automatiquement arrêtées (difficilement réalisable sans une réification des différentes tâches des processus comme dans les fibres de ZIO) .
  6. Reposez-vous autant que possible (la paresse est importante). La création de fibres dans ZIO se fait en utilisant l'opération fork. Il est possible alors soit de se mettre en attente de son terme avec join ou de l'interrompre avec l'opération interrupt. Sachant que interrupt agit immédiatement.
  7. Honorer les transactions. ZIO fournit Ref[A] et RefM[A], qui sont des zones mémoires de type STM (Software Transactional Memory), c'est-à-dire avec des transactions (comme dans une base de données). Ces zones mémoires sont mutables, mais les opérations effectuées sur celles-ci sont atomiques. RefM[A] permet en plus de gérer les effets (par exemple, afficher un message à l'écran).
  8. Respecter les promesses. ZIO fournit Promise[E, A]. Ce type représente des variables qui ne peuvent être assignées qu'une seule fois avec une valeur de type A. Cette valeur sera récupérée par une autre fibre, mise en attente de l'assignation. Il est possible aussi de remonter une erreur E à travers cette variable. Promise[E, A] permet de coordonner plusieurs fibres en échangeant des valeurs entre-elles.
  9. Ne pas abandonner. ZIO propose des ordonnanceurs composables avec Schedule[A, B], c'est-à-dire un outil permettant de spécifier la récurrence d'une tâche (en nombre de répétitions et/ou en intervalle de temps entre deux répétitions). Schedule[A, B] consomme des éléments de type A et produit des éléments de type B. On peut ainsi représenter une nouvelle tentative (retry) avec Scheduler[E, A], où E représente le type d'une erreur : une tâche est répétée jusqu'à ce qu'il n'y ait plus d'erreur.
  10. Soyez productif et multipliez la donnée. John De Goes parle à ce moment là d'un type Queue avec back-pressure et aussi d'un nouveau type pour les flux de données Stream[E, A] incluant là aussi la notion d'erreur avec E.

Le talk s'est terminé sur un appel à participer à la montée en compétence des développeurs en programmation fonctionnelle et en particulier avec ZIO.

... Puis, avec l'intervention de l'organisation, John a posé quelques questions en demandant à ceux qui répondent par non (en toute sincérité) de venir sur la scène :

  • "Savez-vous ce qu'est un Functor ?" Une dizaine de personnes hésitantes se sont alors déplacées sur la scène.
  • "Connaissez-vous un type de "type" (*, *) -> * ?" Beaucoup de participants se sont regardés. Et petit à petit, les personnes se sont levées pour venir remplir l'estrade. Pendant quelques minutes, un flux continu et pratiquement interminable s'est emparé des escaliers de l'amphi en direction de la scène. Sur un amphi de 500 places bien rempli, il ne restait cette fois qu'une vingtaine de personnes assises. Le reste remplissant comme il le pouvait les rares places restant sur l'estrade. La photo était impressionnante, laissant dans l'embarras un instant l'organisation ! (Si vous vous vous demandez quelle réponse est valide, il faut comprendre que (*, *) -> * (ou aussi * -> * -> *) représente tous les constructeurs de types avec deux paramètres comme Either[A, B], (A, B) ou A => B ; allez voir la notion de higher-kinded type.)
  • "Qui ne comprend pas la programmation fonctionnelle ?" Le flux pris une marche inverse, remplissant à nouveau les sièges de l'amphi et ne laissant qu'une quarantaine de personnes sur l'estrade. Et pour ces personnes restant sur scène un exemplaire de Functional Programming for Mortals with ScalaZ de Sam Halliday leur était offert !

Future of Scala par Jon Pretty

Alors que SBT domine sur l'ensemble des outils de gestion de build dédié à Scala, d'autres outils du même ordre voient le jour. C'est le cas pour CBT ou Mill. Dans ce talk, Jon Pretty nous présente Fury, qui est aussi un outil de build, avec un logo que Jon nous promet de voir plus souvent.

Si le nom représenterait ce que Jon pense de SBT, la particularité de Fury est

  • Qu'il s'utilise en ligne de commande (CLI).
  • Qu'il est rapide. Nous n'avons pas à attendre qu'il se charge comme SBT.
  • Qu'il propose un reporting semi-graphique (vue tabulaire sur les éléments du projet, vue arborescente et régulièrement mise à jour lors de la construction du projet)
  • Qu'il est déjà intégré avec d'autres outils, comme Git.

Fury fournit une vision hiérarchique de vos projets. À la base se trouve le workspace, qui comme son nom l'indique est l'espace de travail de Fury. Le workspace représente aussi un ensemble de repo Git. Dans ce workspace, nous allons avoir différents projets. Un projet représente une lib ou une application entière et correspond à un repo Git. Un projet sera ensuite décomposé en module(s) — typiquement core, macro, bench... Aux différents projets, il est possible d'associer des schema. Un schema est une configuration qui permet de compiler un projet sous différentes versions (scala 2.12, scala 2.11, scalaJS...).

Quelques conférences de ScalaIO

Scala Best Practices I Wish Someone'd Told Me About par Nicolas Rinaudo

Nicolas Rinaudo a présenté un talk intitulé "Scala Best Practices I Wish Someone'd Told Me About" (en français). Cette présentation était une occasion unique à vivre. Ce n'est pas tant le contenu qui était exceptionnel. Celui-ci était de bonne qualité et j'ai eu l'occasion d'apprendre de bonnes et de mauvaises pratiques en Scala. Non, ce qui fut exceptionnel, c'était la présence non avertie de Martin Odersky, le créateur de Scala, dans cette session — mettant en émoi le speaker, qui effectivement ne s'y attendait pas.

Je tiens à rappeler que le talk était en français et en mode puzzler, donc interactif. J'ai donc découvert que Martin Odersky comprend bien le français et le parle aussi ! Et sa présence fait écho à ce qu'il avait annoncé dans sa keynote : réduire autant que possible les puzzlers du langage Scala.

Et alors que Nicolas se permettait (tant qu'il pouvait) quelques critiques du langage Scala, l'auditoire a pu assister à des échanges entre le speaker et Martin. Dans les sujets des échanges, les type class, leurs avantages et le fait d'avoir une syntaxe simplifiée dans les futures versions de Scala. Et aussi :

  • Nicolas : Désolé Martin de faire cette critique 😬, mais je conseille d'éviter d'utiliser le type Try. Préférez le type Either, d'autant qu'avec ce type, il est possible de choisir le type pour les erreurs.
  • Martin : Je comprends, mais le type Either est une abomination hérité d'Haskell ! Try est un bon type et les exceptions sont une bonne représentation.
  • Nicolas : 😅
  • Quelqu'un dans l'auditoire : Oui mais les exceptions pose un problème de performance. Lancer une exception nécessite de réifier toute la pile d'appel !

Les puzzles vus ont été parcourus avec plus de temps que prévu par le speaker, si bien que seule la moitié des slides ont été présentées. Néanmoins, le déplacement valait le coup ! Pour terminer, afin de faire un happy end, Martin a demandé à Nicolas hors séance de refaire le talk en anglais à ScalaDays !

Better, faster, stronger Coder. Improving data processing @Spotify par Julien Tournay

En dehors de ça, nous avons eu aussi des talks assez avancés. Ce fut le cas de l'excellent talk de Greg Pfeil intitulé "Category-parametric Programming", sur la capacité à représenter la théorie des catégories à travers Scala. Ce fut le cas aussi de l'intervention de Julien Tournay de Spotify qui présentait SCio, une API en Scala et programmation fonctionnelle pour Apache Beam et Google Cloud Dataflow. Le talk s'intitulait "Better, faster, stronger Coder. Improving data processing @Spotify". Il présentait les difficultés que posent la sérialisation en Java et le fait que ce soit... pire avec Scala.

Julien nous a alors présenté Magnolia, une solution développée par Jon Pretty pour générer automatiquement des typeclass pour datatype décrits à partir de case class et sealed trait. Magnolia se base sur les macros Scala pour cette génération. Autrement dit, tout se passe à la compilation ! Ce qui permet de décharger la partie runtime, contrairement à la réflexion. Julien utilise donc Magnolia pour enlever de la charge lors des phases de (dé)sérialisation. Il réussi à obtenir ainsi de meilleures performances au niveau de SCio. En aparté, une discussion s'est engagée entre Julien et Martin Odersky : Magnolia se base sur des macros whitebox. Mais les versions futures de Scala verront leur disparition. Les versions futures de Scala représentent donc un risque pour SCio. Ce à quoi Martin promet de réfléchir.

High performance Privacy By Design using Matryoshka and Spark par Olivier Girardot et Wiem Zine Elabidine

Du côté Data, il y avait un certain nombre de talks sur Spark et ainsi que les problématiques du streaming. Notamment Frameless, présenté par Brian Clapper, un framework s'installant au-dessus de Spark et qui utilise Shapeless pour apporter plus de type checking dans le code Spark. Il y avait aussi "7 conseils pour démarrer avec Spark" de Nastasia Saby et quelques retours d'expérience d'Ebiznext sur Spark et Kafka.

Il y avait enfin le talk d'Olivier Girardot et Wiem Zine Elabidine, intitulé "High performance Privacy By Design using Matryoshka and Spark" (sous la bienveillance de John De Goes). Si matryoshka fait référence à ces poupées russes qui s'emboitent les unes dans les autres, il était question ici du framework Scala implémentant les schémas de récursion (recursion schemes), introduit par Erik Meijer et al. dans un article intitulé "Generalized bananas, lenses and barbed wire".

Le contexte présenté par Olivier concerne la mise en place d'une approche privacy by design, inscrit dans la réglementation européenne RGPD sur la protection des données privées et en application depuis le mois de mai de cette année. Dans un cadre BigData / Spark, il est nécessaire d'appliquer cette réglementation, en veillant à ce qu'une stratégie de privacy soit appliquée aux colonnes qui le nécessitent, ce qui inclut l'anonymisation ou la pseudonymisation des données. Pour se faire, Olivier propose tout d'abord d'associer à chaque catégorie de colonnes représentée par un Seq[String] une stratégie spécifique. Il représente alors ça à travers ce type : Map[Seq[String], PrivacyStrategy].

C'est pour mettre en pratique cette structure de données que l'équipe dans laquelle étaient Olivier et Wiem se sont intéressés à Matryoshka. Wiem nous a alors expliqué le principe derrière cette librairie et comment et dans quel cadre elle a été mise en place : la transformation des données intégrant la transformation de schéma en passant par un format pivot SchemaF.

Et Univalence ?

Tout d'abord toute l'équipe Univalence était présente lors de ScalaIO. Un signe nous distinguait à ce moment : des t-shirts et des stickers avec les symboles suivants :

𝜆❤.
(𝜆🐇.❤(🐇🐇))
(𝜆🐇.❤(🐇🐇))

Nous vous laissons avec le mystère que cache ces symboles, mais comprenez qu'ils sont en rapport avec la programmation fonctionnelle et... les lapins !

Notre ressenti sur la conférence était globalement positif. Deux de nos data engineers ont d'ailleurs gagnés le livre de Sam Halliday Functional Programming for Mortals with ScalaZ. Et notre CEO a aussi gagné grâce à Lunatech un mug Star Wars ^^. Néanmoins, pour la plupart d'entre-nous, il y avait à ScalaIO de la matière à discuter certes, mais aussi beaucoup de concepts et de pratiques à découvrir.

Et en tant que speaker, nous avons animé deux sessions :

  • Le workshop "Dans s'cas là mettons les mains dans le code" avec Jean Helou (de Codamens) et @Jonathan Winandy .
  • Le short talk "Back to school : des exercices pour monter en compétence en FP" avec @François Sarradin

Ces deux sessions sont destinées aux débutants en Scala et en programmation fonctionnelle. Elles tournent autour de la montée en compétence des novices et du mentoring pour ces sujets.

Car, même si nous avons une expertise en Scala, Spark et en programmation fonctionnelle, la montée en compétence dans ce domaine est un sujet qui nous anime, sachant que devons régulièrement y faire face aussi bien en interne, en particulier pour nos profils juniors, qu'auprès des équipes auprès desquelles nous intervenons ou de la communauté en général.

Autres points

N'oublions pas que ScalaIO est avant tout une conférence basée sur le bénévolat, dont une bonne partie des frais sont principalement payés par les billets achetés et les sponsors. De plus, les membres de l'organisation sont avant tout des développeurs.

Le lieu est assez simple d'accès, situé sur un campus avec le tramway pas trop loin. Néanmoins il faut prévoir un peu de marche sorti du tramway. En ce qui concerne le CPE, pas de problème particulier non plus. Les salles sont biens. Il y a juste eu quelques surprises avec le matériel de projections. Par contre, le réseau mobile Free y est capricieux et il ne fallait pas trop compter sur le Wifi (apparemment, c'était plus un problème d'infra au CPE et indépendant de l'organisation).

Niveau intendance, rien à dire, avec la présence d'un traiteur (proposant des plats frais et la présence de plats végétariens) et d'un stand crêpe. Un effort était fait pour proposer des gobelets solides (du genre qui ne s'écrase pas lorsqu'on appuie dessus) et réutilisables.

Du point de vue stand, les sponsors étaient principalement des sponsors français, mais représentant assez bien la communauté Scala (eBizNext, NeoLynk, Teads, Criteo...). Le sponsor principal, Lunatech, a assuré une bonne animation avec des prix à gagner et une décoration spéciale pour "Helloween".

Enfin, la community party dans un ancien pétrolier réaménagé en lieu de réception fut très appréciable.

Enfin, pour la première fois de son existence, l'organisation a ajouté un jour dédié aux workshops. Nous insistons sur l'aspect première fois, car il y a eu quelques couacs autour de l'organisation de ces workshops. En espérant, que l'année prochaine sera plus favorable sur point.

Conclusion

L'un des avantages de ScalaIO, lorsqu'on s'intéresse à l'écosystème Scala et/ou à la programmation fonctionnelle, c'est de se sentir d'autant moins reclus. Pas de jugement, pas de réelles mauvaises critiques, la communauté a plus envie de faire avancer les sujets et est prête à accompagner et guider ceux qui souhaitent aller de l'avant.

De plus, au travers des talks mais aussi au travers des discussions de "couloir" que vous pouvez avoir, l'état d'esprit de toutes les personnes présentes à ScalaIO (dont nous pouvions compter beaucoup de contributeurs à l'écosystème Scala en France et dans le monde) font que cette conférence est une bonne expérience. Et c'est toujours un peu triste de voir ScalaIO se terminer, néanmoins avec une certaine fierté d'être membre de cette communauté.

Merci à tous ceux qui ont fait ScalaIO 2018 et à l'année prochaine !

Merci @Bernarith Men @Anonymous @François Sarradin et @Jonathan Winandy pour les photos. En ajoutant @Anonymous et @Brahim Boukalit pour leur participation.