16 points par GN⁺ 2025-02-25 | 3 commentaires | Partager sur WhatsApp
  • Clojure n’est pas l’un des langages de programmation dominants, et peut être peu familier pour certaines personnes
  • Principaux atouts de Clojure
    • Productivité des développeurs : Clojure est interactif, réduit les tâches répétitives et offre un environnement de développement efficace. Les développeurs peuvent livrer rapidement des produits tout en y prenant du plaisir
    • Maintenabilité à long terme : le langage Clojure et son écosystème sont matures et stables. Il est possible de construire des systèmes de haute qualité tout en réduisant les coûts de maintenance
    • Culture centrée sur les idées : la communauté Clojure explore des idées issues du passé et du présent, du monde académique et de l’industrie, afin de trouver de meilleures façons de développer des logiciels. Elle offre aux développeurs de nouveaux défis et de nouvelles occasions d’apprentissage

(hello 'clojure)

  • Clojure est un langage de la famille Lisp, née dans les années 1950
    • Lisp a commencé comme modèle théorique, mais offre aussi en programmation réelle une grande élégance conceptuelle
    • Comme la syntaxe du code correspond directement aux structures de données, il présente plusieurs avantages par rapport aux langages à syntaxe complexe
    • Il a été l’un des principaux langages utilisés lors des précédents booms de l’IA
  • Les langages de la famille Lisp ont connu des vagues de popularité avant de retomber, mais Clojure s’est particulièrement fait remarquer au cours des dix dernières années
  • Clojure fonctionne sur la JVM de Java et intègre des concepts de programmation modernes
    • prise en charge puissante des structures de données immuables
    • conception pensée pour la concurrence
  • C’est une petite communauté qui a grandi sans le soutien de grands groupes, mais avec des caractéristiques de langage très fortes
  • Clojure peut s’exécuter dans divers environnements
    • ClojureScript : s’exécute après compilation vers JavaScript
    • ClojureCLR : s’exécute dans l’environnement .NET
    • Babashka : interpréteur de script rapide basé sur GraalVM
    • Jank : prise en charge de la compilation native
  • Apprendre Clojure permet de réutiliser les mêmes connaissances dans plusieurs environnements

Développement interactif

  • Programmer est un processus itératif d’écriture de code et de validation
    • Sans retour rapide, il est difficile d’être certain qu’un code fonctionne correctement
    • Méthodes de feedback courantes :
      • exécuter des scripts en boucle
      • interagir avec l’UI et afficher des logs
      • utiliser des tests unitaires
      • utiliser le compilateur et des outils d’analyse statique
    • La rapidité du feedback a un impact majeur sur la productivité des développeurs
      • Plus le feedback ralentit, plus le temps de débogage augmente et moins il reste de temps pour écrire du code
  • Au-delà de ces méthodes classiques, Clojure propose une approche de développement interactif (interactive development)
    • Le cœur du modèle repose sur le REPL (Read-Eval-Print Loop)
    • Avant d’écrire du code, le développeur lance le runtime Clojure et le connecte à son éditeur
    • Il peut exécuter des fragments de code un par un et obtenir un retour immédiat
    • Grâce à la structure syntaxique cohérente de Lisp, il est possible d’exécuter librement aussi bien de petits fragments que de grands blocs de code
  • Contrairement à un REPL classique, Clojure permet d’exécuter des fragments de code en étant connecté à un système déjà en cours d’exécution
    • Cette approche offre une boucle de feedback bien plus puissante que le schéma traditionnel « écrire du code → exécuter → déboguer »
    • Il devient possible de modifier et déboguer le programme en temps réel
    • Ce n’est pas un simple REPL, mais un outil d’interaction puissant utilisable jusque dans les environnements de production

Une culture tournée vers la stabilité

  • Choisir Clojure, ce n’est pas seulement adopter une technologie puissante, c’est aussi devenir membre d’une communauté dotée d’une philosophie et de principes particuliers
    • Si l’on adopte seulement la technique sans échanger avec la communauté, il est difficile d’en expérimenter la véritable valeur
  • La communauté Clojure accorde une grande importance à la stabilité et à la rétrocompatibilité
  • Le langage cœur continue d’être amélioré et étendu presque sans jamais introduire de changements cassants
  • L’écosystème open source de Clojure suit la même philosophie et minimise les changements inutiles (churn)
    • Cela contraste avec la plupart des autres écosystèmes de langages modernes
    • Le gaspillage de ressources dû aux changements inutiles représente à l’échelle mondiale des milliards de dollars
  • Dans Clojure, mettre à niveau vers les versions récentes du langage et des bibliothèques est quelque chose de très naturel
    • On profite des corrections de bugs, des mises à jour de sécurité et des gains de performance sans avoir à réécrire la base de code
    • Là où, dans d’autres langages, une nouvelle version peut casser du code existant, ce code reste généralement intact en Clojure
  • Certains développeurs peuvent se demander : « comment progresser sans changement ? »
    • Mais stabilité et stagnation sont deux choses différentes
    • Clojure évolue en ajoutant de nouvelles fonctionnalités et en s’améliorant sans casser l’existant
    • Les développeurs peuvent ainsi bénéficier en continu de meilleurs outils sans retouches de code inutiles

Systèmes d’information et représentation des connaissances

  • Dans le développement web et les applications métier, collecter, accéder et traiter l’information est central
  • Pourtant, les langages grand public montrent souvent une conception inefficace pour la représentation et la manipulation de l’information
    • Ils imposent des structures de données de bas niveau qui introduisent une complexité inutile
    • Leurs systèmes de types statiques peuvent être trop rigides, ce qui complique la manipulation souple des données
  • Clojure fournit nativement des structures de données fonctionnelles et de puissantes capacités de manipulation des données
    • En tant que langage dynamique, il suit l’« Open World Assumption »
      • une approche qui maximise l’extensibilité et la flexibilité des données
    • Il est fortement influencé par RDF (framework de modélisation des données pour le Web sémantique)
      • D’où une forte synergie avec des bases de données graphe comme Datomic
      • Grâce aux mots-clés avec namespace, il est possible d’attribuer un sens indépendant du contexte
  • La structure de Map Clojure basée sur des mots-clés namespacés permet d’exprimer le sens de façon plus fine qu’un simple JSON
  • L’extension des données devient facile, avec une représentation intuitive qui évite les collisions de noms

Petites fonctions composables et données immuables

  • En Clojure, il est courant de programmer en se concentrant sur les fonctions pures (pure functions) et les données immuables (immutable data)
  • On peut écrire du code impératif à la manière de Java, Ruby ou C, mais un Clojure idiomatique est très différent
    • Fonctions pures : elles renvoient un résultat uniquement à partir de leurs entrées, sans modifier d’état externe
    • Données immuables : leur sens repose sur des valeurs plutôt que sur des références ou des identités d’objet
  • Comme elles ne dépendent pas d’un état extérieur, la prévisibilité du code est élevée
  • Il n’y a pas de modification de variables globales ni d’effets de bord imprévus (side effects)
  • Puisqu’il n’y a pas de risque que les données changent, le traitement parallèle et la résolution des problèmes de concurrence deviennent plus simples

Gestion de la concurrence

  • Le calcul moderne repose sur des processeurs multicœurs, et la concurrence est devenue incontournable
    • À mesure que la loi de Moore atteint ses limites, l’exploitation du parallélisme devient la clé des gains de performance
    • Mais dès qu’on manipule un état mutable (mutable state), il faut gérer des problèmes de synchronisation et des contraintes de timing complexes
  • Clojure met l’accent sur l’immutabilité (immutability) pour résoudre les problèmes de concurrence à la racine
    • Manipuler une mémoire mutable crée des dépendances au timing et à l’ordre d’exécution
    • Une approche de transformation pure des données (data-in, data-out) peut toujours être exécutée en parallèle de façon sûre
  • Clojure s’appuie sur les mécanismes de concurrence existants de la JVM (java.util.concurrent), tout en offrant des outils plus abstraits et de plus haut niveau
    • Atoms : opérations atomiques basées sur CAS (Compare-and-Set) avec retry automatique
    • Refs : fournissent de la Software Transactional Memory (STM)
    • Agents : appliquent les mises à jour de manière asynchrone
    • Futures : fournissent une interface fork-and-join basée sur des pools de threads
  • La bibliothèque core.async est également disponible
    • Elle prend en charge le modèle CSP (Communicating Sequential Processes), comparable aux goroutines de Go
    • On peut aussi la rapprocher du modèle Actor d’Erlang/Elixir ou d’Akka en Scala
  • Il est aussi possible d’utiliser des techniques de contrôle de concurrence de plus bas niveau sans passer par les abstractions de haut niveau de Clojure
    • files synchronisées, références atomiques, verrous (lock), sémaphores (semaphore), divers pools de threads, gestion manuelle des threads, etc.
  • Un contrôle fin est possible si nécessaire, mais dans la plupart des cas, utiliser les outils abstraits est plus sûr et plus efficace

Raisonnement local (Local Reasoning)

  • Il existe une limite à la complexité de code qu’on peut garder en tête à un instant donné
  • Quand l’état du programme et ses modifications sont répartis en plusieurs endroits, comprendre et maintenir le code devient difficile
  • Pourquoi Clojure facilite le raisonnement local
    • Code centré sur les fonctions pures (pure function)
      • On peut comprendre complètement le comportement d’une fonction à partir de ses seules entrées
      • Il n’est pas nécessaire de prendre en compte un état externe à la fonction
    • Différence avec les langages orientés objet
      • Clojure réduit au minimum le polymorphisme (polymorphism), ce qui permet de repérer facilement où le code s’exécute
      • En programmation orientée objet (OOP), « tout se passe ailleurs », alors qu’en Clojure, il suffit de suivre les fonctions définies dans les namespaces
  • Grâce à la structure syntaxique cohérente de Clojure, le refactoring du code est simple
    • L’utilisation de données immuables et de fonctions pures réduit les effets de bord inattendus lors des modifications
    • En isolant séparément le minimum de code impératif nécessaire, on peut composer harmonieusement code impératif et code fonctionnel

Tests faciles

  • Avec un code Clojure fondé sur les fonctions pures, il suffit de fournir une entrée et de vérifier la sortie pour tester
    • Pas besoin d’initialisations d’état complexes, de configuration d’objets mock ni de contrôle du timing
    • Les tests sont donc plus fiables et moins sujets à la flakiness (échecs de tests inconsistants)
  • Prise en charge d’une technique avancée : Property Based Testing (Generative Testing)
    • Elle génère des entrées aléatoires pour rechercher les cas qui violent certaines propriétés ou invariants
    • Elle prend aussi en charge la technique de shrinking, qui aide à trouver le plus petit cas d’échec
  • Ce concept est né en Haskell, puis a été implémenté dans de nombreux langages via des frameworks de test inspirés de QuickCheck
  • En Clojure, il est encore plus efficace grâce à la synergie entre structures de données immuables et développement basé sur le REPL

Les avantages du recrutement de développeurs Clojure

  • En général, les développeurs Clojure sont relativement moins nombreux que ceux de langages populaires comme JavaScript ou Python
  • Mais comme ils sont peu nombreux, les entreprises qui utilisent Clojure ne sont pas non plus très nombreuses
    • L’équilibre global entre offre et demande se maintient donc
    • Dans la pratique, les entreprises qui recherchent des développeurs Clojure et les développeurs eux-mêmes se rencontrent assez souvent de manière pertinente
  • Les développeurs Clojure ont souvent un haut niveau de capacité à résoudre des problèmes
    • Plutôt que de suivre simplement les technologies à la mode, beaucoup cherchent à explorer de nouvelles façons de penser et de nouvelles idées
    • Les entreprises qui utilisent Clojure constatent souvent que, même si les candidats sont moins nombreux, leur niveau est élevé
    • Exemple : Nubank a formé avec succès des centaines de développeurs au Clojure au Brésil
  • Trouver des développeurs Clojure n’est pas simple, mais lorsqu’on identifie le bon profil, on a de fortes chances de recruter un excellent développeur
    • Plutôt que de rechercher uniquement des personnes ayant déjà l’expérience du langage, former des développeurs à forte capacité d’apprentissage peut aussi être un bon choix
    • La communauté Clojure a elle-même la particularité d’attirer des développeurs qui réfléchissent profondément aux problèmes et à leur résolution

Trade-offs et ajustement du niveau d’abstraction

  • Clojure est un langage high-level, orienté vers une écriture de code concise et expressive
    • Grâce à ses structures de données fonctionnelles (immuables) et à ses puissantes API de manipulation de données, la complexité inutile diminue
  • Les structures de données de Clojure utilisent en interne une structure en arbre (Hash Array Mapped Trie) pour garantir l’immuabilité
    • Lors des mises à jour, il peut y avoir du path copying, ce qui peut augmenter la charge du GC (garbage collector)
    • L’interopérabilité avec Java peut aussi entraîner de la runtime reflection et du boxing/unboxing
    • Dans les applications courantes, ce coût est presque négligeable, tandis que le gain en productivité de développement est important
  • Pour des cas exigeant de hautes performances, comme les moteurs graphiques temps réel, le traitement du signal ou le calcul numérique, des optimisations de bas niveau sont possibles
    • En Clojure, les type hints permettent de supprimer la reflection et d’optimiser les opérations sur types primitifs
    • L’utilisation de tableaux contigus de types primitifs permet de tirer parti du cache CPU
    • Il est aussi possible d’utiliser des bibliothèques d’accélération GPU
  • La plupart des langages de haut niveau doivent recourir à des extensions natives en C/Rust quand la performance devient critique, mais Clojure peut résoudre la plupart des problèmes de performance grâce aux optimisations de la JVM (compilation JIT)
    • Avec du profiling et quelques optimisations, il est possible de maximiser les performances de composants comme les event loops

Métaprogrammation et API centrées sur les données

  • En tant que langage de la famille Lisp, Clojure permet de traiter le code comme des données
    • D’une manière proche de JSON, mais dans une structure plus lisible, il devient possible de représenter des programmes
    • Clojure utilise un format de données appelé EDN (Extensible Data Notation), qui fournit une représentation proche de JSON
  • Clojure offre aussi la possibilité de transformer le code lui-même à l’aide de macros
    • Cependant, la communauté Clojure a une culture de restriction prudente de l’usage des macros
    • Les macros peuvent être difficiles à déboguer et moins compatibles avec les outils d’analyse statique
  • À la place, on privilégie une conception d’API data-driven
    • Exemples : routage HTTP, génération HTML/CSS, validation de données
    • Au lieu d’appeler directement une fonction donnée, on décrit le comportement à l’aide de structures de données (maps, vecteurs)
    • Les API fondées sur les données sont manipulables dynamiquement et permettent d’enregistrer et modifier facilement les configurations utilisateur
  • Grâce aux API centrées sur les données, il devient possible de reconfigurer dynamiquement un système à l’exécution
    • Cela facilite la mise en œuvre de systèmes de simulation très flexibles, de gestion dynamique de configuration et de métaprogrammation

Interop Java et exploitation de l’écosystème

  • Le développement d’applications modernes consiste à combiner d’innombrables bibliothèques open source et API
    • Comme Clojure s’exécute sur la JVM, il peut exploiter des millions de packages Java disponibles sur Maven Central
    • Il est possible d’appeler simplement des bibliothèques Java même sans reflection
  • Clojure est bien plus concis que Java, et facilite une programmation exploratoire avec le REPL
    • Il permet d’explorer et de combiner des API bien plus vite que Java
    • Avec ClojureScript, on peut utiliser de la même façon JavaScript et l’écosystème NPM

Une culture centrée sur les idées

  • Quel que soit le langage utilisé, un projet peut réussir ; inversement, utilisé de la mauvaise façon, n’importe quel langage peut mener à l’échec
    • De bons outils ne fabriquent pas automatiquement de bons développeurs
  • Clojure a une courbe d’entrée élevée et demande souvent des tâtonnements à l’apprentissage, mais cela ouvre aussi la voie à une réflexion plus profonde
  • Certains projets Clojure restent marqués par une façon d’écrire héritée de Java ou Python, et n’exploitent donc pas pleinement le langage
    • En revanche, les équipes qui adoptent la philosophie et les idées de Clojure développent une meilleure capacité de conception logicielle
  • La communauté Clojure remet sans cesse en question les façons de développer existantes et explore de meilleures approches
    • Les conférences de Rich Hickey (créateur de Clojure) ne sont pas de simples présentations techniques, mais une exploration de principes fondamentaux de conception logicielle
    • Dans les conférences Clojure, les idées, l’analyse d’articles académiques et le partage d’expérience passent souvent avant la simple présentation de bibliothèques

Conclusion

  • Clojure n’est pas seulement un langage de programmation, mais une communauté de personnes qui réfléchissent à de meilleures façons de développer des logiciels
  • Dans cette communauté, élargir ses limites et explorer de nouvelles possibilités est une valeur essentielle
  • Un développeur qui grandit dans cette culture ne se contente pas de bien maîtriser Clojure : il devient aussi un ingénieur logiciel doté de meilleures capacités de résolution de problèmes

3 commentaires

 
roryk 2025-02-26

Personnellement, j’utilise Clojure, et je suis largement d’accord avec le contenu de l’article.
Dans mon travail, j’ai surtout utilisé Python et Java(Type)Script, mais dès qu’on relâche un peu la maintenance, il devient facile de ne plus suivre l’évolution du langage lui-même et de ses bibliothèques, et le code se transforme vite en legacy code. Avec Clojure, en revanche, j’ai été très satisfait de constater qu’un code écrit une fois reste très facile à relire, modifier et faire évoluer, même un an plus tard.
Depuis, pour mes usages personnels, sauf contrainte liée à une bibliothèque spécifique, j’utilise volontiers Clojure.

 
plumpmath 2025-02-25

Pourquoi Clojure ?

Jank Jank~!

 
GN⁺ 2025-02-25
Avis Hacker News
  • Lorsqu’on me demande quel type de programmation j’ai aimé, je réponds que c’était construire des pipelines de traitement de données dans le shell et écrire en Clojure et ClojureScript ces cinq dernières années

    • Aujourd’hui, nous sommes quatre à écrire en Clojure, avec au total plus de 30 ans d’expérience sur Clojure
    • Nous avons lancé à Prague une société de conseil qui privilégie Clojure, et nous pensons que cela peut être un bon choix pour divers systèmes
  • J’utilise Clojure depuis 12 ans, et avant cela j’ai utilisé Java pendant plus de 12 ans

    • J’ai créé d’excellentes applications et bibliothèques en Clojure et en Java
    • Je décris Clojure comme « le langage de programmation le moins mauvais », avec un cœur puissant et stable
    • Une fois les outils maîtrisés, la vitesse de travail et la précision s’améliorent
    • Le workflow orienté REPL de Clojure est une proposition de valeur importante
  • J’adore écrire en Clojure, et j’ai réalisé qu’il n’était pas nécessaire d’expliquer en profondeur cet attachement à Clojure en le comparant à d’autres langages

    • Les problèmes personnels que certains ont avec d’autres langages ne m’intéressent pas, et mon amour pour Clojure repose sur des raisons théoriques, pratiques, émotionnelles et financières
    • Clojure n’est pas parfait, mais c’est le plus satisfaisant des langages de programmation généralistes
  • Mon cofondateur vise à créer le maximum de produit avec le minimum d’entreprise

    • Après cinq ans en bootstrap, nous avons atteint plus d’un million de dollars d’ARR, et Clojure y a joué un grand rôle
    • Clojure a aussi contribué à mon bonheur en tant que programmeur, et nous prévoyons de faire grandir à l’avenir l’équipe produit cœur autour de Clojure
  • J’ai exploité une activité SaaS pendant 10 ans avec Clojure, et cela aurait été impossible sans lui

    • La stabilité du langage est extrêmement utile, alors que dans d’autres écosystèmes il faut souvent réécrire le logiciel
    • Je recommande de lire les billets pertinents de personnes qui ont réellement utilisé le langage, plutôt que des critiques superficielles
  • Je recommande <a href="https://www.flow-storm.org/">Flow Storm</a> à ceux qui utilisent Clojure

    • Avec une bonne suite de tests, cela permet de déclencher différents scénarios
  • J’ai beaucoup appris de Rich Hickey et j’étais passionné par Clojure et la FP

    • Mais à mesure que l’entreprise grandissait, le typage dynamique est devenu un fardeau, et après le départ de personnes clés il a été difficile de trouver des développeurs Clojure
    • Aujourd’hui, l’essentiel de notre stack est en Python et en Go
  • Certains ont fait remarquer que la documentation de ClojureDocs était ancienne, et ils auraient voulu ajouter une fonction permettant de voter pour les réponses

    • Grâce à l’algorithme de Google, c’est surtout ClojureDocs qui est utilisé
  • Le passage sur la stabilité de Clojure m’a surpris, car à chaque fois que j’essayais chaque année, j’avais l’impression que tout avait changé

    • Je me demande si exécuter « Hello World » est toujours aussi lent, et même si lire du Clojure est agréable, l’écrire a toujours été un obstacle
  • J’ai commencé avec Common Lisp avant de passer à Go et Rust, mais je regarde à nouveau Clojure récemment

    • Grâce au REPL et à la programmation interactive, on peut travailler vite
    • La JVM est un excellent runtime