Le meilleur du langage SCALA à la SCALA.io 2018 : Programmation fonctionnelle

CBTW
L’Actualité Tech — Blog CBTW
11 min readNov 8, 2018
Programmation fonctionnelle — Scala IO et langage Scala
Programmation fonctionnelle — Scala IO et langage Scala — “computer keyboard” by Hello I’m Nik

Après 3 jours passés dans l’univers du langage Scala du 29 au 31 octobre 2018, nous vous partageons le meilleur des conférences ayant trait à la programmation fonctionnelle.

Keynote d’ouverture — Martin Odersky

Martin Odersky est ni plus ni moins que le créateur du langage Scala.
Il ouvre la journée par une présentation de la roadmap de Scala contenant une information majeure : la sortie de Scala 3.0 est prévue pour 2020 !

Il prend le temps d’expliquer le Scala Improvment Process et surtout de revenir sur l’intégration de “TASTy” (Typed Abstract Syntax Trees) dans la méta description du langage. Ceci permettra par exemple d’ajouter une logique réflexive (macros/staging) à Scala et de maximiser l’interopérabilité avec d’autres langages.

Enfin, M. Odersky rassure également l’assemblée : le passage de Scala 2 à Scala 3 ne sera insurmontable. Les paradigmes du langage restent les mêmes et l’intégration des macros aidera grandement à migrer vers la nouvelle version.

Tout ce que vous avez toujours voulus savoir sur la programmation fonctionnelle sans jamais oser le demander — Xavier Detant

Première surprise, la présentation parle de javascript. Et après une introduction fédératrice demandant “Qui n’aime pas javascript ?”, Xavier Detant nous présente avec intelligence un cas d’usage pratique.

Au travers de son exemple, il refactor son projet personnel de manipulation de vidéothèque et nous montre successivement des exemples de programmation impérative et procédurale. Clou du spectacle : un vilain effet de bord dans ses tests unitaires.
En effet, les différents tests partagent une même source de données et lorsqu’un test manipule cette source, le test suivant ne fonctionne plus car la source a été modifiée.

Attention toutefois, les “effets de bord” sont des effets souhaitables. Sans effet de bord, notre application serait une boîte noire sans intérêt. N’importe quel affichage, n’importe quel formulaire est une source d’effets de bord.

L’objectif majeur de la programmation fonctionnelle est donc de repousser les effets de bord aux limites du système, c’est-à-dire là où on en a besoin (en gros, du point de vue de notre application, cela équivaut au niveau de notre lien avec l’univers).

Ce talk illustration également les mots pompeux qui représentent souvent des idées simples mais très puissantes lorsqu’elles sont manipulées avec intelligence.

  • [fonction first class citizen] : propriété d’un langage qui permet de passer une fonction en variable et donc en paramètre d’une autre fonction.
  • [closure] : fonction accompagnée de son contexte d’exécution.
  • [fonction lambda] : fonction qui n’est pas nommée explicitement. Lorsque définie dans une variable, la fonction n’a pas nécessairement besoin d’un nom pour être exécutée.
  • [fonction d’ordre supérieur] : des fonctions qui manipulent des fonctions. C’est-à-dire dont les paramètres d’entrée sont des fonctions et dont la sortie est une fonction.
  • [currying] : pratique de design applicatif qui consiste à convertir une fonction à n paramètres en n fonctions à 1 paramètre.

Pour conclure : prenez tout de même garde lors de l’utilisation du langage Scala.
Étant un langage multiparadigme, la tentation sera souvent grande de revenir à ce qu’on sait faire.
Pour sortir de sa zone de confort, un programmeur orienté programmation objet devrait se forcer à tester des langages fonctionnels purs comme [haskell] ou [elm].

Initiation aux effets algébriques Xavier Van de Woestyne

Xavier Van de Woestyne annonce la couleur : il aime utiliser des langages puissants pour coder des applications qui ne servent à rien.
Selon lui, OCaml est le meilleur langage du monde et il cherche des speakers à Lille pour élargir le cercle de sa secte du PHUTUR.

Puis très vite son discours se tourne vers la technique. Les informations pleuvent et il faut suivre, pour le plus grand plaisir de ceux qui veulent apprendre.

Pour résumer, la principale problématique des effets algébriques, est qu’il n’en existe pas d’implémentation stable.
Conceptuellement, ils sont d’une puissance redoutable mais leur implémentation concrète est bien moins accessible.
Les monades, quant à elles, sont les outils qui permettent de représenter ces effets.
Mais attention, la manière dont les monades ont été conçues conceptuellement est très différente de la manière dont elles ont été ensuite implémentées et utilisées.

Pour comprendre les effets algébriques, il est donc intéressant de dissocier les “effets” des “effets de bord”. Et ainsi, on comprend bien que les effets sont quelque chose de nécessaires et que la question repose plus sur la maîtrise et donc la formulation des effets.

Une problématique majeure est donc de réussir à composer des effets qui sont potentiellement incompatibles.
Cette propriété se retrouve ainsi dans les monades qui ne peuvent pas se composer.

La solution pratique réside dans la transformation des monades, mais ceci remet en question le principe d’encapsulation : “program to an interface not to an implementation”

“ Un effet algébrique, ce n’est rien de plus qu’une exception “résumable” ”

Un effet réuni un ensemble d’actions définies par des “constructeurs”.
Une “action” / “fonction” impliquant un effet devrait nécessiter un EffectHandler ce qui permet l’élargissement de la signature pour représenter les “effets de bord”.
Ce système de signature à effets typés permet d’élargir la programmation fonctionnelle. Et ceci a pour avantage :

  • de rendre le code lisible et structuré
  • de simplifier les comportements complexes
  • de dissocier les parties “pures” et “impures” du langage
  • les effets se composent et s’ordonnent
  • gestion native du multi-thread

Voici des exemples de langages implémentant ce comportement :
OCaml + effects / Koka / Eft / Links / Franck

OCaml prévoit d’ailleurs la sortie en 2019 d’une nouvelle version majeure incluant les effets.

Théorie des Catégories : vous la connaissez déjà Emilien Pecoul

Programmation fonctionnelle — Scala IO et langage Scala
Category Theory — Programmation fonctionnelle — Scala IO et langage Scala

Dans ce talk, Émilien veut présenter le côté simple, intuitif et pratique de la théorie des catégories.
Les mathématiques apparaissent souvent opaques, austères pour les néophytes, mais peuvent pourtant aussi être vues comme “une surcouche formelle pour exprimer des choses très simples et accessibles”.

Pourquoi la théorie des catégories ?
Cette question met en relief l’exercice qu’Emilien nous propose d’exécuter ensemble : comprendre l’implémentation concrète de concepts extrêmement abstraits.
La théorie des catégories est tellement abstraite qu’elle peut s’appliquer à énormément de choses.
Et ce qui rend la théorie des catégories si remarquables, c’est qu’elle s’intéresse aux comportements plus qu’aux états.

Qu’est-ce que la théorie des catégories ?
Une catégorie est extrêmement simple par définition : c’est un ensemble de morphismes réunis par des objets (qui servent de points de départ et d’arrivée aux morphismes).
Les morphismes (ou arrow) ne sont ni plus ni moins qu’une association entre un début et une arrivée et les objets ne servent ici qu’à définir les points de départ et d’arrivée.

La manipulation de la théorie des catégories s’articule autour de 3 principes : abstraction, composition et identité.

  • Abstraction : Démarche de simplification de problèmes par suppression d’informations. La démarche classique d’abstraction est le passage de la réalité au modèle puis du modèle au code
  • Composition : La composition est le fait d’avoir une équivalence dans l’ordre d’exécution des morphismes.
    En mathématiques, on appelle ‘relation’ un morphisme qui est non prédictible, non composable. La notion de fonction est réservée à un morphisme composable.
  • Identité : Imaginons deux billets de 10€ posséder par un commerçant d’une part et par un collectionneur d’autre part. Il y a fort à parier qu’ils ne considèrent pas la notion d’équivalence de la même manière.
    L’identité est contextuelle. En théorie des catégories, il est plus commun de comparer deux entités isomorphiques qui sont des objets qui peuvent devenir l’un l’autre par un isomorphisme.

Cette propriété permet des simplifications comparables à ce que les développeurs du monde de la POO réalisent habituellement par héritage. __Un functor__ est alors défini comme la transformation d’une catégorie en une autre. {objets; morphismes} => {objets’; morphismes’}
Par exemple : List + map qui peut transformer par exemple {Int; isEven} en {List[Int]; List[Int].map(isEven)}
__Une transformation naturelle__ est une transformation entre 2 functors
Par exemple : List + Maybe […]

La programmation fonctionnelle et la théorie des catégories peuvent être abordées de manière plus ‘naturelle’.
Par exemple, envisager le Monoïde comme une catégorie contenant seulement un objet. Ainsi, tous ses morphismes partent de et reviennent vers cet objet.

Nous mettons à disposition quelques liens utiles pour explorer plus avant la théorie des catégories :

Par ailleurs ne soyons pas complexés d’avoir des difficultés à appréhender cette théorie. La théorie est apparue en mathématiques en 1940 et il lui a fallu 50 ans pour se concrétiser sous forme exploitable en informatique !

Functional Programming: The Enterprise EditionNarek Asadorian

Programmation fonctionnelle — Scala IO et langage Scala
The enterprise edition — Programmation fonctionnelle — Scala IO et langage Scala

Le retour au premier plan de la programmation fonctionnelle a amené ces dernières années quelques guerres de clocher opposant programmation fonctionnelle et programmation orientée objet / impérative.
Les seconds reprochent en effet souvent aux premiers l’invocation de concepts purement mathématiques et la complexification de la code base dans la quête de suppression de mutation et d’éloignement de sides-effects.

On ne compte plus les threads twitter commençant par quelques mots innocents sur les bienfaits de la monade et finissant dans un magma d’incompréhension entre partisans des 2 approches.

Enterprise VS Theory
Conférence scala oblige, c’est la défense de la programmation fonctionnelle qui est en jeu dans “Functional Programming: The Enterprise Edition”, dans une approche pragmatique.

Narek Asadorian commence par se référer à Martin Fowler et nous rappelle que le développement d’application d’entreprise consiste en la manipulation et le stockage de large volume de données.
L’exercice se révèle bien souvent fastidieux dans le monde réel, si bien qu’on préfère dans un souci de pragmatisme appliquer des patterns purement objets aux élégants concepts théoriques de programmation fonctionnelle.

Programmation fonctionnelle — Scala IO et langage Scala
Programmation fonctionnelle — Scala IO et langage Scala

Mais à y regarder de plus près, quels sont nos besoins réels ?

Le speaker en identifie 3 :

  • correct : Les données doivent bien entendu être correctes et valides,
  • reliability : On doit pouvoir accéder à nos données et les manipuler sans entrave,
  • changing : Les données changent, il faut donc pouvoir faire évoluer l’état de l’application.

Or que proposent les concepts de programmation fonctionnelle ?

  • appliquer des fonctions totales
  • éloigner / supprimer les sides-effects
  • composer nos fonctions
  • une transparence référentielle
  • privilégier les abstractions

Rien dans cette liste ne semble à priori rendre incompatible la programmation fonctionnelle et la programmation d’application d’entreprise ! Quelles sont donc les causes à cette frilosité apparente de certains développeurs ?

Une première cause est à chercher du côté de la syntaxe en elle-même. Alors que des langages comme Java, Php, Python sont à classer dans la catégorie des C-like, passer à un langage fonctionnel implique souvent une gymnastique mentale et demande de désapprendre quelques principes pris pour acquis.

Notre interlocuteur poursuit en pointant le rôle des différentes formations qui diversifient peu les apprentissages en se restreignant aux langages C-like, si bien que des armées de développeurs sont chaque année formées aux styles impératifs au détriment d’autres approches.

Une seconde cause tient en la nature même des applications d’entreprise qui sont typiquement des programmes interagissant avec le monde extérieur, donc produisant des effets en réaction à d’autres effets. Le développeur se retrouve ainsi à gérer les effets suivants :

  • données partielles (un formulaire incomplet par exemple)
  • gestion d’erreur (comme une base de données inaccessible)
  • side-effects (logging, base de données, etc.)

Est-ce si compliqué de traiter ces 3 effets en mode fonctionnel ?

Données partielles
Dans un programme impératif, l’absence de données est le plus souvent gérée par la valeur `null`, ce qui amène dans bien des cas au trop bien connu NullPointerException.
Scala (entre autres) utilise un type particulier pour indiquer l’absence possible de valeur, `Option`, ce qui permet de proposer des traitements qui ne seront appliqués que si l’Option n’est pas vide. On y perd le risque de NullPointerException tout en y gagnant une meilleure lisibilité et un code plus concis.

Gestion d’erreur
Un programme impératif va gérer ses erreurs en déclenchant des exceptions, ce qui rend le programme imprédictible, et donc plus complexe à débuger et à tester.
On ne sait en effet pas forcément quelle fonction est susceptible de lever quelle exception et l’accumulation d’appels nous expose à un nombre conséquent d’exceptions pouvant survenir. Le code appelant finit par être entouré d’instructions `try / catch` ce qui alourdit la lisibilité et la developer experience.

La librairie standard Scala propose 2 types dédiés à la gestion d’erreurs :

  • `Either` qui permet de stocker soit une erreur, soit la valeur attendue
  • `Try` qui permet d’encapsuler une exception si une exception est levée, et la valeur attendue si tout se passe bien

Comme pour l’Option, il est possible d’associer des fonctions à ces types, fonctions qui ne seront appliquées qui si le type contient la donnée attendue.
Il est ainsi possible de composer ses programmes en appliquant une série de fonctions sur le modèle `Option[A] -> Option[B]`. Tant que tout se passe bien et que la valeur attendue est présente, les fonctions sont appliquées, et dès qu’une erreur intervient, notre type contiendra l’erreur, à traiter le moment voulu.

Side effects
La toolbox fonctionnelle à destination du développement d’entreprise est presque complète, il nous reste maintenant à gérer les side-effects. Alors que le code impératif ne s’embarrasse pas de telles subtilités, Scala propose plusieurs librairies (cats-effet, scalaz) à cet usage.
L’idée n’est pas de supprimer le side-effect mais de l’abstraire en séparant la définition, donc le code à exécuter autour, de son exécution.
La testabilité du programme n’en est que meilleure.

Correcte, prédictible, testable et concise, notre application développée à base de patterns fonctionnels valide toutes les cases du cahier des charges de l’application d’entreprise en apportant des garanties supplémentaires à une application développée sur un mode impératif.

Le speaker rappelle alors qu’il serait dommage de passer à côté de tous ces bénéfices et nous invite à nous faire avocat, voire activiste, de la programmation fonctionnelle en :

  • Partageant autour de nous,
  • Présentant les avantages en termes de valeur ajoutée et non en évoquant la théorie des catégories,
  • Refactorisant sur un mode fonctionnel lorsque l’occasion se présente,
  • N’étant pas élitiste !
  • Gardant la théorie pour plus tard.

À suivre

Suivez la suite de nos aventures à la SCALA.io grâce aux deux articles suivants :

De plus, nos collaborateurs participent régulièrement à des événements phares du monde de la Tech. N’hésitez donc pas à vous abonner à notre compte Medium pour suivre nos prochains retours de conférences et réaliser votre veille professionnelle.

Retrouvez aussi nos publications et notre actualité via notre newsletter, ainsi que nos différents réseaux sociaux : LinkedIn, Twitter, Youtube, Twitch et Instagram

Vous souhaitez en savoir plus ? Consultez notre site web et nos offres d’emploi.

Les auteurs

Raphaël Bacconnier
Web fullstack developer
Functional programming enthusiast & happy dad
Pierre-Yves akka MeKeyCool
Developer
Pirate et adepte du RTFS (Read The Fucking Sources)
Guillaume Bogard
Web fullstack developer
Amateur de programmation fonctionnelle et de parcs d’attractions

--

--

CBTW
L’Actualité Tech — Blog CBTW

Nos experts partagent leur vision et leur veille en développement web et mobile, data et analytics, sécurité, cloud, hyperautomation et digital workplace.