Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Pedro Rolo

Min Read

25 février 2024

Présentation du langage de programmation Elm

Ceci est la deuxième partie de mon article sur le langage de programmation Elm. Sur le premier article Je me suis concentré sur les principales fonctionnalités qui font d'Elm une alternative intéressante à JavaScript.

Ici, je me concentrerai sur la perspective historique qui fait qu'Elm vaut le détour, et j'approfondirai les deux caractéristiques principales du langage : la pureté fonctionnelle et le typage statique. Ensuite, je donnerai quelques bons exemples montrant qui utilise Elm en production.

blue arrow to the left
Imaginary Cloud logo

Le succès discret de l'architecture d'Elm

La meilleure façon de prédire l'avenir est de l'inventer.
Alan Kay, concepteur du langage de programmation Smalltalk

Avant 2013, la plupart des programmes frontaux suivaient des approches très impératives. Des frameworks tels que Backbone ou Angular v1 se sont inspirés du modèle modèle-vue-contrôleur (MVC) et ont placé la mutation et l'observation des modèles de vue au cœur de leur logique d'affichage. Gérer autant d'états et d'événements était difficile et inconfortable pour de nombreux développeurs Web, à qui le simple flux de données de leurs frameworks web backend sans partage les faisait soupirer à l'époque où JavaScript et AJAX n'avaient pas encore envahi leur monde.

Le flux de données unidirectionnel

Réagir a été le premier projet à bouleverser cet impératif château de cartes. La caractéristique la plus distinctive de ce projet est le DOM virtuel, qui permet aux programmeurs de considérer leur page Web comme quelque chose qui peut être recalculé et rendu efficacement sans frais importants.

Cette efficacité est ce qui permet à React de modéliser le front-end : une page Web se compose d'une arborescence de composants et chaque fois que l'utilisateur interagit avec eux, l'apparence de la page entière est recalculée en fonction du nouvel état stocké dans ces composants. Vous n'êtes plus obligé de modifier activement le DOM ; React s'en charge pour vous.

Bien que React ait facilité la modélisation des applications Web, il n'a pas prescrit de moyen de séparer la logique métier de la logique de rendu. Facebook a proposé une architecture appelée Flux pour résoudre ce problème, même si la plupart des anciennes implémentations étaient plus complexes que nécessaire et prenaient du temps à gagner du terrain.

Une architecture fonctionnelle pour les applications React

C'est en 2015 que Redux est apparu et est apparu comme une implémentation plus simple de l'architecture Flux. L'idée principale est que l'état de l'application doit être stocké dans un arbre d'états unique et que les modifications apportées à cet arbre doivent être modélisées comme une fonction de réduction. Cela devrait lui-même résulter de la composition de plusieurs fonctions réductrices, chacune étant responsable d'une partie de l'état de l'application, modélisant la logique pour traiter chaque action et obtenir une nouvelle version de l'état.

Redux est une bibliothèque simple avec un très petit noyau (une dizaine de petites fonctions). Il est facile à comprendre, agréable à utiliser et permet d'utiliser des fonctionnalités de développement intéressantes, telles que des débogueurs qui voyagent dans le temps et le rechargement de modules à chaud.

Malgré sa simplicité, son approche n'est pas intuitive et semble étrangère à JavaScript. L'écriture de fonctions réductrices qui ne modifient pas la version précédente de l'état n'est pas triviale et il est même recommandé d'utiliser une bibliothèque pour gérer l'état de manière immuable. C'est donc sans grande surprise que l'auteur de Redux l'a dit très clairement que cette architecture est fortement inspirée d'Elm.

blue arrow to the left
Imaginary Cloud logo

Typage statique

Le courage, c'est savoir ce qu'il ne faut pas craindre.
— Platon

Si l'architecture d'Elm a réussi après avoir été associée à une technologie extraterrestre impérative telle que JavaScript, même au prix d'éloigner les développeurs de leur zone de confort, ne serait-il pas agréable de rester à l'écart de « l'herméneutique » du typage dynamique et de l'insécurité des mutations d'état arbitraires ? Y a-t-il autre chose à retenir de ce filon ? Y a-t-il d'autres secrets sous Elm ?

L'écosystème JavaScript semble avoir besoin d'un typage statique

Lorsqu'un projet logiciel démarre, tout le code est magnifique, rose et brillant. Ensuite, vous commencez à faire face à des délais, à des bogues, à des correctifs, à des changements de périmètre, à des fusions d'entreprises, à des acquisitions et à une horde de développeurs surchargés qui modifient le code alors que l'auteur original est en vacances, malade ou décédé. Après avoir vieilli, chaque ligne de code porte l'apogée de son histoire et, souvent, personne n'est là pour le dire.

Sur les projets mal vieillis, les noms de variables se trouvent, les noms de fonctions, les noms de classes et les noms de types. Cependant, lorsque vous utilisez des langages typés dynamiquement, comme JavaScript, seuls les noms et les tests nous fournissent des informations sur la sémantique d'un programme et sur la manière dont il peut être modifié et amélioré.

Éloge du typage statique

Les langages typés statiquement, quant à eux, vérifient la sémantique du projet et s'assurent de son exactitude. Les noms sont peut-être erronés, mais nous savons quelles opérations correspondent à quels types et le compilateur vérifie automatiquement si nos modifications sont pertinentes.

Les informations fournies aux développeurs par de tels systèmes valent mille noms et ces systèmes sont plus faciles à modifier et nécessitent beaucoup moins de tests car le système de types évite plusieurs erreurs qui devraient autrement être vérifiées par un test automatisé développé par un humain.

Les inconvénients du typage statique

Le problème avec les types est que, dans la plupart des langages, ils gênent le développement d'un nouveau code, le débogage ou l'expérimentation du comportement du code. Habituellement, les types ajoutent beaucoup de bruit inutile à la clarté du discours que les développeurs ont avec la machine des autres développeurs pendant le codage.

En ce qui concerne les types, les développeurs sont également contraints d'écrire davantage - et même si cela n'est pas très mal lorsque vous utilisez la saisie semi-automatique de l'éditeur, c'est une catastrophe lorsqu'il s'agit d'expérimenter dans des environnements interactifs tels que la ligne de commande ou le débogueur. L'encombrement du code rempli d'informations typographiques crée beaucoup d'inertie et implique une énorme perte d'agilité. Choisir entre le typage statique et le typage dynamique finit donc par être un compromis entre Utilisabilité et maintenabilité.

L'écosystème JavaScript évolue vers un typage progressif

Il n'est donc pas surprenant que plusieurs initiatives introduisent le typage statique dans le monde JavaScript. Les plus connus sont Flux (Facebook), Tapuscrit (Microsoft) et fléchette (Google). Bien qu'il ne s'agisse pas de modifications apportées au langage JavaScript lui-même, il s'agit soit de surensembles du langage qui ajoutent de la saisie, soit de langages similaires qui lui font directement concurrence. Cela exerce une forte pression sur les développeurs pour qu'ils adoptent une approche typée statiquement, car les outils et les bibliothèques évoluent également de cette façon.

Il existe toutefois une tendance commune à toutes ces approches : Afin d'éviter l'encombrement statique des caractères, ils ont choisi de rendre les types facultatifs.. Ainsi, selon le contexte, les développeurs sont libres d'ajouter des informations de type à leur code ou de choisir de travailler sans vérification de type, et de choisir la sécurité de type qui l'accompagne.

Les résultats sont meilleurs que ceux obtenus sans les types, mais restent relativement limités. Comme les types sont progressifs, il est souvent impossible de vérifier si les signatures de type ont un sens, et le niveau de vérification dépend fortement de la discipline du développeur et de la question de savoir si les bibliothèques utilisées contiennent des informations de type pour le même système de types.

Elm a une approche différente

Les idées d'Elm proviennent du monde fonctionnel typé, au cours duquel des décennies de développement ont abouti à l'utilisation de l'inférence de type. Contrairement au typage dynamique ou progressif, le compilateur vérifie les types du code. Cependant, contrairement à la plupart des systèmes de types statiques, les informations de type ne doivent pas nécessairement être saisies explicitement par le programmeur et sont déduites par le compilateur.

Le programmeur peut choisir d'ajouter ultérieurement des signatures de type à ses fonctions, bien que ces signatures de type soient distinctes des définitions de fonctions. De cette façon, ils ne deviennent pas source de confusion pour ceux qui liront ou modifieront le code ultérieurement.

Cependant, il convient de noter que, tout en s'inspirant des systèmes de types de langages fonctionnels, Elm n'en respecte pas les caractéristiques les plus complexes. Il adopte ce qui semble utile aux programmeurs frontaux et conserve une approche pragmatique. C'est comme si JavaScript avait été repensé pour son utilisation actuelle.

blue arrow to the left
Imaginary Cloud logo

Programmation fonctionnelle pure

La vraie sagesse vient à chacun de nous lorsque nous réalisons à quel point nous comprenons peu [...] le monde qui nous entoure.
— Socrate

Elm est un langage de programmation purement fonctionnel. Cela signifie que toutes ses expressions bénéficient d'une propriété simple appelée Transparence référentielle d'où découlent plusieurs conséquences intéressantes. Nous procédons en décrivant ce qui est Transparence référentielle puis explorez ses conséquences.

Transparence référentielle

Une expression ou une fonction est dite transparente référentielle lorsque ses résultats se comportent de manière logique. En d'autres termes, lorsqu'elle est fournie avec une certaine entrée, une expression transparente référentielle aboutira toujours au même résultat.

Les fonctions pures sont faciles à raisonner et à tester

Si l'on pense au concept mathématique de fonction on remarquera peut-être qu'elle bénéficie bel et bien de cette propriété. Il est en fait assez difficile d'imaginer comment il pourrait en être autrement. La fonction qui calcule l'aire d'un carré est toujours évaluée à 4 mètres carrés lorsqu'elle est fournie avec une entrée de 2 mètres et se comportera toujours comme telle. Il n'existe aucun moyen d'écrire une fonction qui prendra le côté du carré comme entrée unique et lui fera renvoyer des valeurs différentes à différents moments.

Du moins, dans le domaine des mathématiques auquel la plupart d'entre nous ont pensé, les mathématiciens semblent avoir choisi cette abstraction comme un outil très important, sinon le principal, pour modéliser et raisonner sur le monde. Je dirais que ce n'était pas un hasard.

Si une fonction renvoie toujours les mêmes résultats, nous pouvons l'évaluer et la tester sans rien prendre en compte à part ses entrées et ses sorties. Nous savons exactement ce que nous devons fournir et à quoi nous attendre lorsque nous envisageons de le modéliser et de le tester.

Aucune mutation

Mais la transparence référentielle n'est pas une réalité dans la plupart des langages de programmation. Avec le développement des ordinateurs numériques, la plupart des langages de programmation ont choisi de modéliser le monde d'une manière similaire à la façon dont les machines fonctionnent en interne plutôt qu'à celle utilisée par les mathématiciens pour modéliser le monde.

Des tentatives ont été faites pour suivre la première voie depuis le développement des premiers compilateurs. Cependant, les ordinateurs de l'époque n'étaient pas assez puissants pour gérer un tel modèle informatique et la méthode semblable à une machine pour modéliser le monde est devenue une partie intégrante de notre culture informatique.

Cette méthode semblable à une machine pour modéliser le monde (programmation impérative) est principalement basée sur un état de mutation. Dans celui-ci, les calculs peuvent être modélisés en lisant et en modifiant l'état d'une unité de mémoire jusqu'à ce qu'un état final soit calculé. Lors de l'ajout de fonctions à ce modèle, la plupart des langages ont choisi de partager cet état entre les fonctions, brisant ainsi la transparence référentielle.

Les fonctions ne dépendent pas de leur saisie ; leurs résultats dépendent de la mémoire qu'elles lisent et écrivent, et elles ne renvoient souvent aucune valeur, uniquement dans le but de modifier les valeurs dans l'état partagé.

En revanche, dans la programmation purement fonctionnelle, aucun état n'est partagé entre nos fonctions. Et si aucun état n'est partagé, il n'y a plus de raison de modifier l'état des valeurs utilisées. L'objectif de nos fonctions cesse d'être de modifier des valeurs et commence à les utiliser comme entrées pour calculer d'autres valeurs. Dans la programmation purement fonctionnelle, chaque définition est immuable.

Elm appartient à cette famille de langues et, par conséquent, toutes ses définitions sont immuables et toutes ses fonctions sont transparentes du point de vue référentiel.

Le runtime est responsable des effets secondaires

Les fonctions pures sont inutiles à elles seules. Nous effectuons des calculs parce que nous voulons lire les valeurs d'entrée du monde extérieur et parce que nous voulons les modifier en fonction des valeurs de nos calculs. Le monde extérieur est donc comme un état modifié par notre programme au même titre que la mémoire de nos programmes impératifs.

Certains langages de programmation fonctionnels ont trouvé des moyens mathématiques pour traiter cette question avec élégance, dans un style purement fonctionnel et d'une manière générale, mais en utilisant certains concepts qui se sont révélés assez difficiles à comprendre.

Elm a une approche différente. Son environnement d'exécution et son architecture nous cachent ce problème. Notre programme finit par être un ensemble de fonctions utilisées pour calculer ce qu'il faut afficher à l'utilisateur en fonction d'une certaine séquence d'actions de l'utilisateur ou d'autres entrées environnementales.

Fondamentalement, le runtime et l'architecture d'Elm se chargent d'interagir avec le monde dans ce domaine particulier, en le rendant de manière simple et agréable.

blue arrow to the left
Imaginary Cloud logo

Elm dans le monde réel ?

L'avenir n'est pas tracé sur une piste. C'est quelque chose que nous pouvons décider, et dans la mesure où nous ne violons aucune loi connue de l'univers, nous pouvons probablement le faire fonctionner comme nous le souhaitons.
Alan Kay

L'écosystème d'Elm est assez immature et évolue lentement. Cependant, la qualité de la bibliothèque est souvent très bonne et le compilateur nous donne de nombreuses garanties quant à leur stabilité. Pour l'instant, Elm convient aux petits composants dynamiques de pages Web ou aux pages Web simples qui ne nécessitent pas de rendu côté serveur.

Certaines fonctionnalités importantes ne devraient être fournies qu'avec la version suivante (0.19) :

  • Rendu côté serveur - envoi de code HTML avec la réponse initiale ;
  • Effacement de l'arbre : suppression du code inutilisé (généralement appelé élimination du code mort ou DCE) ;
  • Fractionnement du code : découpage du code en petits morceaux pour une meilleure mise en cache ;
  • Lazy loading : envoi uniquement des morceaux de code nécessaires à une page particulière.

L'objectif principal de cette version sera de fournir un système acceptable pour développer des applications Web complexes d'une seule page.

Utilisation dans le monde réel

Le fait de se déguiser remplace inévitablement les bonnes idées. Ce n'est pas un hasard si les types d'entreprises techniquement incompétents sont appelés « costumes ».
— Paul Graham

Malgré son immaturité, le secteur connaît déjà quelques réussites :

  • Pas d'encre rouge est une entreprise dans le domaine des logiciels éducatifs ;
  • Pivotal Tracker est une entreprise célèbre qui fournit des outils pour le développement agile. Ils ont récemment commencé à utiliser Elm et semblent avoir une très belle expérience avec elle ;
  • Prezi développe des logiciels pour créer des présentations interactives dans le navigateur ;
  • Réseau CBANC - Un réseau de professionnels du secteur bancaire doté d'outils permettant aux banques de collaborer et de gérer leurs activités. Tous les nouveaux développements frontaux sont en cours dans Elm ;
  • CircuitHub (GitHub) - CircuitHub fournit des produits électroniques à la demande avec des devis instantanés ;
  • Laboratoires Yari - Une société portugaise développant des logiciels utilisant des langages fonctionnels ;
  • Autres entreprises: Adrima ; Bendyworks ; Futurice ; Gizra ; Test Double ; Mimo ; SMRxt ; TruQu ; PinMeto ; Hearken ; Day One ; Spottt ; imby.bio ; Wonktonk ; Beautiful Destinations ; AS Tallink Grupp ; CARFAX.
blue arrow to the left
Imaginary Cloud logo

Langues associées

Le contexte vaut 80 points de QI.
— Alan Kay

Elm est fortement inspiré de Haskell et inspire beaucoup Purescript. Voici un aperçu de ce dont il s'agit :

Haskell

Le haskell est de loin la langue qui a le plus influencé Elm. Il s'agit de la norme actuelle pour les langages de programmation typés paresseux et il est développé par un comité d'universitaires du domaine. Les principales différences par rapport à Elm sont les suivantes :

  • Il s'agit d'un langage de programmation à usage général ;
  • Il fournit un système de types très polymorphe et complexe ;
  • L'évaluation est paresseuse (les expressions ne sont évaluées que lorsque leurs valeurs sont nécessaires) ;
  • Habituellement, il est compilé pour être assemblé ;
  • Possède des erreurs d'exécution.

Purescript

Purescript se situe quelque part entre Haskell et Elm. Les deux évoluent ensemble et s'influencent mutuellement au fur et à mesure de leur croissance. Ses principales caractéristiques sont les suivantes :

  • Langage de programmation à usage général ;
  • Compile en JavaScript ;
  • Comme Haskell, supporte un système de types très polymorphe et complexe ;
  • Des messages d'erreur pires que ceux d'Elm ;
  • Utilise l'environnement d'exécution de JavaScript plutôt que son propre environnement d'exécution ;
  • Interactions faciles (et dangereuses) avec le code JavaScript ;
  • Comme Elm (et contrairement à Haskell), il permet une évaluation stricte ;
  • Possède des erreurs d'exécution.

En raison de la complexité de son système de types, je ne pense pas qu'il soit possible pour la plupart des programmeurs JavaScript de passer à Purescript. Cependant, son interaction facile (et dangereuse) avec JavaScript en fait une option intéressante pour les personnes qui auraient pu passer par les étapes d'Elm ou de Haskell.

Dans l'écosystème de ce langage, trois projets tentent de résoudre le même problème que l'architecture Elm :

  • Thermite - Un emballage autour de React ;
  • Halogène - Un framework frontal tirant parti du système de types complexe de Purescript ;
  • Pux - En utilisant Halogen, ils se sont rendu compte que la complexité de la saisie était très difficile pour les débutants. Ils ont ensuite implémenté l'architecture d'Elm dans Purescript, sans trop s'éloigner de la simplicité de l'approche d'Elm. Le résultat a été un framework appelé Pux.
blue arrow to the left
Imaginary Cloud logo

Conclusion

Elm est un environnement de programmation intéressant, spécifique au front-end, qui prend en charge un écosystème logiciel immature. En raison de la conception du langage, ce jeune écosystème finit par fournir des garanties de sécurité atypiques. Beaucoup d'entre eux proviennent du compilateur convivial qui garantit l'absence d'erreur d'exécution.

Il est très agréable de travailler et permet un développement et une refactorisation faciles avec une sécurité et une joie sans précédent. Il a été conçu pour répondre aux besoins d'un programmeur JavaScript moderne et pour démarrer facilement.

Pour l'instant, il n'est pas prêt à développer des applications Web complexes à page unique en raison de l'absence de rendu côté serveur et de certaines optimisations importantes. La prochaine version (0.19) devrait résoudre ces problèmes et, bien qu'elle ne soit pas prête, il n'est peut-être pas judicieux de l'utiliser pour autre chose que de petites applications ou de petits composants.

Il convient de garder une certaine attention sur ce projet qui semble avoir le potentiel de devenir un outil très compétitif.

À Imaginary Cloud nous disposons d'une équipe d'experts en développement de logiciels. Si vous pensez avoir besoin d'aide pour votre projet numérique, écrivez-nous ici!

Ready for a UX Audit? Book a free call

Vous avez trouvé cet article utile ? Ceux-ci vous plairont peut-être aussi !

blue arrow to the left
Imaginary Cloud logo
blue arrow to the left
Imaginary Cloud logo
blue arrow to the left
Imaginary Cloud logo
blue arrow to the left
Imaginary Cloud logo
blue arrow to the left
Imaginary Cloud logo
Pedro Rolo
Pedro Rolo

Développeur de rails avec plus de 10 ans d'expérience dans diverses technologies. Je m'intéresse à la programmation fonctionnelle.

Read more posts by this author

People who read this post, also found these interesting:

arrow left
arrow to the right
Dropdown caret icon