
contactez nous


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.
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.
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.
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.
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 ?
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é.
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.
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é.
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.
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.
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.
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.
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.
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.
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.
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) :
L'objectif principal de cette version sera de fournir un système acceptable pour développer des applications Web complexes d'une seule page.
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 :
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 :
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 :
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 :
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 :
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!
Vous avez trouvé cet article utile ? Ceux-ci vous plairont peut-être aussi !
Développeur de rails avec plus de 10 ans d'expérience dans diverses technologies. Je m'intéresse à la programmation fonctionnelle.
People who read this post, also found these interesting: