
contactez nous


J'ai jeté un œil au langage de programmation Elm et au framework Elm. Il s'agit d'une approche de programmation fonctionnelle typée du frontend qui influence d'autres technologies populaires d'une manière quelque peu perturbatrice. Cet article est un compte rendu de ce que j'ai découvert à propos d'Elm.
Cet article sera divisé en deux parties. Dans cette première partie, je vais me concentrer sur les fonctionnalités qui font d'Elm une alternative intéressante à Javascript.
Dans la deuxième partie, je me concentrerai sur la perspective historique qui fait qu'Elm vaut le détour ; je développerai les deux caractéristiques principales du langage : la pureté fonctionnelle et le typage statique ; et enfin, je regarderai qui utilise Elm dans le monde réel.
Elm est un framework et un langage de programmation fonctionnel typé destinés au développement frontal. Il s'inspire d'un langage de programmation appelé Haskell pour améliorer la maintenabilité de Javascript, tout en restant aussi simple et proche de Javascript que possible. L'architecture du framework est similaire à Redux, qui a d'ailleurs été fortement inspiré d'Elm.
Oubliez ce que vous avez entendu à propos de la programmation fonctionnelle. Des mots fantaisistes, des idées bizarres, un mauvais outillage.
— Evan Czaplicki, créateur d'Elm
Lors de la conception du langage, l'auteur d'Elm a choisi de placer l'utilisateur au centre de ses choix de conception. Si vous jetez un œil à son »Soyons mainstream«, vous remarquerez que l'accent est mis sur qui est l'utilisateur (le programmeur Javascript) et de quoi il a besoin, en utilisant ce que l'on appelle Conception axée sur l'utilisation. Cette philosophie réduit les caractéristiques du langage à l'essentiel et facilite son apprentissage.
[Un] concepteur de logiciels récemment embauché avait étalé les listes de sources sur la table de conférence et avait soigneusement passé un cristal suspendu à une longue chaîne sur le code source. De temps en temps, le designer a marqué un cercle en rouge sur la liste. Plus tard, un de mes collègues a demandé au designer ce qu'il avait fait dans la salle de conférence. La réponse nonchalante : « Trouver les bugs de mon programme ».
C'est une histoire vraie, elle s'est produite au milieu des années 1980, lorsque les gens espéraient vivement trouver des pouvoirs cachés dans les cristaux.
— MIT Press, Présentation des algorithmes, Dix-huitième impression (1997)
Les messages d'erreur d'Elm sont extrêmement sympathiques. D'une part, cela provient du système de types statiques, qui permet au compilateur de connaître et d'indiquer clairement les différences entre les types de valeurs attendues et celles fournies à nos fonctions. D'autre part, comme il n'existe pas de classes de types, le type d'information affiché dans les messages d'erreur est très réaliste :
Outre cette clarté atypique, le concepteur du langage a décidé que les messages d'erreur devaient être prioritaires. Ainsi, en plus d'indiquer formellement ce qui ne va pas dans les programmes, le compilateur fournit également des « conseils » sur les intentions du programmeur et propose des suggestions de solutions possibles, par exemple :
[Haskell ne sert à rien.]
— Simon Peyton Jones, Contributeur majeur à la conception du langage de programmation Haskell.
C'est vrai, ce n'est pas Haskell - La principale source d'inspiration d'Elm. Tout en suivant le processus de conception axé sur l'utilisation, de nombreuses fonctionnalités de Haskell n'étaient pas nécessaires et n'ont donc pas été ajoutées au langage. Parmi ceux-ci se trouvait le tristement célèbre système de classes de types.
Ce système apporterait tout le vocabulaire mathématique prétentieux que l'on entend généralement chez les programmeurs Haskell et rendrait Elm totalement inapproprié pour le « Joe normal ».
Mais n'avons-nous pas besoin de classes de caractères ? Ils doivent servir à n'importe quel but ! Pourquoi Haskell en a-t-il besoin et pas Elm ? - Eh bien, la réponse repose sur le domaine problématique abordé par chacun de ces langages : alors que Haskell est un langage de programmation polyvalent, Elm ne l'est pas. D'une part, Elm est simplement un langage de programmation frontal capable d'accomplir cette tâche sans avoir recours à une telle complexité. D'autre part, une partie de ce que cette complexité vise à traiter est gérée et cachée dans le runtime Elm, qui gère les effets secondaires et les mutations d'une manière spécifique au domaine.
Nous n'avons eu aucun échec d'exécution [...]. Nous avons également eu moins de bugs, en grande partie parce que le système de types d'Elm vous oblige à modéliser votre domaine avec plus de soin. [...] Pour résumer, notre responsable a mandaté que tout nouveau code soit écrit en Elm.
— Jeff Schomay, spécialiste du front-end chez Pivotal Tracker
Le système de type Elm est très sûr et sa conception a deux conséquences qui méritent d'être remarquées :
Mon objectif était de m'assurer que toute utilisation de références devait être absolument sûre, avec une vérification effectuée automatiquement par le compilateur. Mais je n'ai pas pu résister à la tentation [...]
— Tony Hoare, inventeur de la référence nulle
Alors que d'autres langages de programmation gèrent les erreurs en tant que partie du langage avec des fonctionnalités très spécifiques, généralement appelées exceptions ou erreurs, Elm ne propose aucune primitive spécifique pour déclencher des erreurs ou les gérer. La possibilité d'échec est plutôt modélisée à travers les types de valeurs renvoyées et gérées par les fonctions. Certains types paramétriques peuvent être utilisés pour transmettre des informations sur les défaillances, tels que les types Peut-être
; Résultat
et Tâche
.
Le Peut-être
type est le plus simple d'entre eux. Il est défini comme suit :
Le un
dans cette expression peut être remplacé par n'importe quel type spécifique, par exemple une valeur de type Peut-être String
peut soit prendre une valeur telle que Juste « une chaîne spécifique »
ou Rien
.
Ainsi, une fonction renvoyant une valeur de - par exemple - Peut-être String
peut renvoyer une valeur Juste « Je suis la chaîne renvoyée »
en cas de réussite ou de retour Rien
en cas d'échec. Par la suite, le programmeur est toujours obligé de choisir quoi faire dans les deux cas et le langage ne permet pas au programme de compiler si les deux possibilités ne sont pas gérées.
C'est grâce à l'approche présentée précédemment que le langage évite d'avoir une valeur nulle. Et débarrassez-vous ainsi de tous ces habituels undefined n'est pas une fonction
erreurs. En cas d'échec, le type transmettra explicitement ces informations et le compilateur forcera le programmeur à traiter ce cas.
Comme Elm est un langage purement fonctionnel, le but de l'évaluation d'un élément est d'en tirer une valeur. Ainsi, Elm oblige le développeur à fournir une valeur de retour pour chaque instruction de contrôle. Cela implique que chaque si
la déclaration a besoin d'un autre
clause et cas
les instructions doivent gérer toutes les valeurs d'entrée possibles.
Par exemple, examinons un type de données abstrait Discipline typographique
qui pourrait prendre comme valeur Statique
; Dynamique
ou Graduelle
:
et si nous gérons une valeur de ce type comme entrée d'une instruction case (une instruction switch), mais oublions de gérer l'une des possibilités :
le compilateur compile le programme :
Ainsi, lorsque nous modifions nos types pour ajouter plus de fonctionnalités, le compilateur nous avertit qu'il y a du code à ajouter pour gérer une nouvelle possibilité.
Tu dois trouver ce que tu aimes.
— Steve Jobs
Elm's boucle de rétroaction courte et syntaxe épurée en font un environnement de travail très agréable. Voyons comment ces éléments contribuent à la joie des développeurs d'Elm.
Évitez le succès à tout prix.
— Simon Peyton Jones, Contributeur majeur à la conception du langage de programmation Haskell.
Une conséquence intéressante des caractéristiques de sécurité décrites précédemment est la façon dont elles raccourcissent la boucle de rétroaction. L'activité de programmation consiste généralement à répéter les activités suivantes :
La dernière étape est souvent celle où les développeurs passent le plus de temps, et ce temps est soit consacré à l'écriture de tests automatisés, soit à l'interaction avec le programme pour confirmer qu'il est correct. La plupart des programmeurs diraient que cette phase est la moins joyeuse.
La sécurité d'Elm et l'absence d'exceptions d'exécution transfèrent une partie du Tests échelonner les efforts dans le Compiler phase. Lorsqu'il utilise Elm, le programmeur passe un peu plus de temps à la phase de compilation - à interagir avec le compilateur jusqu'à ce que le programme soit considéré comme correct - et beaucoup moins de temps à la phase de test, lorsque la seule chose qui peut échouer est de savoir si les exigences métier sont satisfaites - et non si le programme plante ou non.
En utilisant Elm, le programmeur sera informé plus tôt de ses erreurs, sans avoir à passer autant de temps pendant la longue phase de test.
La syntaxe d'Elm est inspirée de Haskell et minimaliste. Il n'y a que deux instructions de contrôle et très peu de mots réservés.
Le centre de cette syntaxe est la fonction. Si la caractéristique syntaxique la plus utilisée de tout langage de programmation structuré est l'invocation de fonctions, alors pourquoi la plupart des langages de style Algol ont-ils recours à autant de caractères spéciaux pour l'invocation et la définition des fonctions ?
Pour écrire la définition et l'invocation ci-dessus, nous avons dû taper 8 caractères spéciaux pour la définition de la fonction :
et 4 sur l'invocation de la fonction :
En fonction de la langue de votre clavier, le nombre de touches de modification enfoncées ; les désagréments et les blessures prématurées dues à des entorses répétitives peuvent varier.
Elm nettoie ça. Si la fonction est si importante, elle doit être facilement saisie et modifiée :
Comme vous pouvez le constater, cette définition de fonction ne nécessite aucun caractère spécial. Les signatures de type sont facultatives et déduites automatiquement par le compilateur, ce qui nous permet d'expérimenter rapidement sans avoir à les saisir explicitement. Ils sont néanmoins utiles : il est parfois utile d'avoir la signature typographique comme guide lors de l'écriture d'un morceau de code moins évident, et ils constituent souvent une forme de documentation utile. Ainsi, dans Elm, les signatures de type sont (éventuellement) écrites sur une ligne séparée (certains éditeurs généreront automatiquement la signature de type lorsque nous la demanderons !) :
Une autre caractéristique qui rend le langage assez amusant à utiliser est que chaque fonction est sélectionnée et peut donc être appliquée à un sous-ensemble de ses arguments, renvoyant une fonction dite partiellement appliquée qui n'attend que les arguments manquants. Ainsi, le code suivant :
correspond au code Javascript suivant :
Le principal avantage de cette fonctionnalité est que le code utilisant des fonctions d'ordre supérieur devient très propre :
Cependant, si nous enchaînons ces opérations, nous commençons à obtenir une mer de parents imbriqués, typique d'un Lisp:
Pour éviter ce problème, le langage fournit les opérateurs de tuyauterie (<|
et |>
). Ils permettent de chaîner les applications de fonctions avec une syntaxe similaire à celle de faire passer un argument dans un pipeline de transformations :
De la même manière ; vous pouvez également utiliser la composition (<<
) ou composition inversée (>>
) opérateurs pour exprimer la même chose sans avoir à faire explicitement référence à l'argument en cours de thread :
Cette syntaxe succincte et pratique, ainsi que les jolis messages d'erreur, font d'Elm un outil idéal pour les expériences interactives, à la fois en utilisant le REPL et en utilisant le compilateur.
Lorsque vous démarrez un projet Elm, vous bénéficiez immédiatement de nombreuses fonctionnalités prêtes à l'emploi :
Et cela vaut la peine de développer d'autres outils :
C'est l'une des choses que Redux a obtenues en implémentant l'architecture Elm. Lors du développement et de l'essai d'un programme, nous sommes en mesure d'inspecter les actions effectuées sur cette interface et de faire des allers-retours dans le temps afin d'analyser l'état du programme à chaque moment de son exécution.
Dans Redux, cette fonctionnalité est assez fragile en raison de la nature impérative de Javascript, et pour y faire face, il est nécessaire d'utiliser Immuable ou une autre bibliothèque pour éviter de modifier directement l'état de l'application. Dans Elm, ce problème n'existe tout simplement pas, car il n'existe pas de mutation au niveau de la langue. La conception du langage elle-même nous protège de ce type de problèmes et de la nécessité d'utiliser des bibliothèques supplémentaires.
De plus, vous pouvez modifier la langue directement sur le navigateur Web, sans avoir à installer quoi que ce soit. Voici un bon exemple de site proposant des fonctionnalités d'édition en direct :
Lors de la publication d'une nouvelle version du package, l'outil Elm vérifie si les fonctions exportées par nos modules :
Selon chacune de ces possibilités, la modification sera répercutée sur le numéro de version du package calculé automatiquement, ce qui permettra de savoir s'il s'agit de modifications majeures, de modifications mineures ou de corrections de bugs ; et s'il est possible de mettre à niveau la version d'une bibliothèque utilisée en toute sécurité.
Dans la partie 2 - disponible ici - Je vais expliquer pourquoi le typage statique et la pureté fonctionnelle sont liés aux tendances actuelles de l'écosystème Javascript. Je parlerai également de qui utilise Elm et de sa maturité. Restez à l'affût, car j'écrirai à ce sujet la semaine prochaine.
À 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: