Modifier des programmes «pendant qu’ils fonctionnent»? Pourquoi?

Je me suis intéressé aux langages Lisp et Lispy récemment, et je les trouve très puissants.

Une chose que j’ai lue partout sur le net est qu’un des avantages de l’écriture en Lisp, Clojure, etc., est que vous pouvez éditer votre programme “pendant qu’il fonctionne”.

Peut-être que je manque quelque chose, mais quel est le point?

Bien sûr, cela pourrait économiser quelques secondes, mais est-ce tout? Chaque fois que je modifie mon programme, je l’arrête, le redémarre et cela fonctionne depuis des décennies.

Il doit y avoir une raison autre que de gagner du temps – qu’est-ce que c’est?

Est-ce que quelqu’un peut me donner une bonne étude de cas qui me fera baver sur cette fonctionnalité? 🙂

Au plaisir de baver!

Il y a des cas d’utilisation extrêmement cool. Un exemple en est la programmation par interface graphique – j’ai vu cela en développant une application graphique en temps réel car elle fonctionnait à côté de mes Emacs: j’ai ajouté du code pour un nouveau bouton et appuyez sur “Cc Cc” pour comstackr cette fonction unique. dans la fenêtre! Je n’ai pas eu à fermer et rouvrir l’application. Puis j’ai commencé à peaufiner les widgets et à manipuler la mise en page, et la fenêtre ouverte se réorganisait instantanément – les boutons se déplaçaient, de nouveaux champs de texte apparaissaient, etc. dès que j’exécutais chaque petit changement que j’avais apporté.

Un autre exemple est un excellent screencast sur la bibliothèque Clojure OpenGL “Penumbra” où le programmeur crée un jeu de tesortings 3D en temps réel. Il commence par une fenêtre OpenGL vide à côté de ses emacs. Il définit un object cube – CMx – et il est à l’écran. Exécute une commande pour le faire pivoter, il commence immédiatement à tourner. Exécute une boucle définissant 5 cubes supplémentaires à différents endroits, pop-pop-pop-pop-pop. Tout est immédiatement réactif, la boîte à outils OpenGL complète est là pour jouer avec. Ajoutez une nouvelle texture de surface à votre cube et voyez-la apparaître immédiatement. Cela devient un monde 3D malléable – le code modifie dynamicment le monde existant au lieu de fermer et de rouvrir le canevas 3D à chaque changement.

Penumbra Livecoding Screencast – téléchargez la version HD pour une meilleure expérience.

Il y a aussi une excellente présentation / screencast sur la bibliothèque audio “Overtone” pour Clojure. La bibliothèque est un toolkit de synthétiseur où vous disposez d’un ensemble de fonctions de synthé pour manipuler l’onde sonore. Lors de la présentation, le développeur écrit un bit de code qui lance une tonalité. Il passe ensuite dix secondes à écrire une boucle qui reproduit ce son 10 fois, mais rend la fréquence plus élevée à chaque fois, et à nouveau CMx et vous l’entendez, notes plus élevées. En l’espace de 20 minutes en temps réel, il obtient une chanson. Cela ressemble à une tonne de plaisir.

Lien de présentation

Les autres utilisations seraient, par exemple: Exploration Web / exploration de données – développer et affiner des algorithmes pour extraire des informations en temps réel, en voyant les données renvoyées à chaque étape; Programmation robotique – envoyer des commandes à un robot en direct; Reconnaissance faciale / image – avec une bibliothèque comme OpenCV, regardez vos modifications instantanément mettre à jour ce que la bibliothèque reconnaît dans une image / vidéo lorsque vous développez le code; Travail de mathématiques (Clojure a “Incanter” pour les statistiques); et tout environnement dans lequel vous souhaitez voir immédiatement quel effet vos modifications ont eu sur les données avec lesquelles vous travaillez.

C’est donc l’aspect le plus amusant d’avoir un REPL devant vous. Des choses qui ne sont pas tangibles, malléables, interactives, commencent à l’être. Conception graphique, graphiques 3D, production sonore programmatique, extraction et transformation de données, ces opérations ont normalement été effectuées à distance. Mais avec Clojure (et dans une certaine mesure aussi avec d’autres langages dynamics), il est vraiment tangible et immédiat. vous voyez chaque changement dès que vous écrivez le code, et si quelque chose ne fonctionne pas ou que vous ne récupérez pas le résultat escompté, il vous suffit de changer ce que vous avez manqué et de le ré-exécuter immédiatement.

Clojure est très bien orienté vers cela. La chose sauvage est que vous pouvez utiliser les bibliothèques Java en temps réel de la même manière – malgré le fait que Java lui-même ne le peut pas! Ainsi, Overtone utilise une bibliothèque de synthétiseurs Java en temps réel malgré le fait que vous ne le pouviez jamais en Java, Penumbra utilise les liaisons Java OpenGL, etc. Rich Hickey a conçu Clojure pour pouvoir le comstackr à la volée. C’est une langue étonnante – Clojure a grandement consortingbué à l’incroyable plaisir de la programmation.

Il doit y avoir une raison autre que de gagner du temps – qu’est-ce que c’est?

Non, il n’y en a pas. Je veux dire, il n’y en a jamais : toute la raison d’utiliser un ordinateur est de gagner du temps. Il n’y a rien qu’un ordinateur puisse faire à la main. Cela prend juste un peu plus de temps.

Dans ce cas, je ne rejetterais pas “quelques secondes”, étant donné que c’est l’une des choses que je fais le plus souvent, toute la journée, pour toute ma carrière de programmation. Quelques secondes pour recomstackr, quelques secondes pour se relancer, quelques secondes pour recréer l’état de mon programme précédent – même sur un poste de travail rapide, il peut facilement y avoir une minute entre les itérations. (C’était bien pire, mais le matériel plus rapide l’a rendu moins terrible, pas bon. Les recompilations de fichiers entiers ou pires sont liées aux E / S, et ne peuvent jamais * correspondre à la vitesse de compilation plus granulaire.)

Dans Lisp, recomstackr une seule fonction dans un processus déjà en cours est presque instantané (je ne l’ai jamais vu même 0,1 sec, même sur mon portable de 5 ans), et les redémarrages signifient que je n’ai pas à recréer mon état , même quand quelque chose signale.

Voici un outil qui me donne une accélération de 100 fois sur l’une des tâches les plus lentes et les plus courantes en tant que programmeur. Je ne sais pas quoi d’autre tu aurais besoin. Nous pouvons probablement inventer certaines raisons, mais si ce n’est pas une raison suffisante, je ne sais pas ce que ce serait. Euh, c’est aussi très cool? 🙂

(* Chaque fois que quelqu’un dit “jamais” à propos de quelque chose impliquant la technologie, cette personne finit invariablement par ressembler à un imbécile complet 2 ans plus tard, et malgré la longévité de Lisp, je suis sûr de ne pas faire exception.)

Il y a un slogan marketing pour Lisp:

Avec Lisp et sa méthode de développement incrémentiel, le coût d’une modification d’un système logiciel dépend de la taille du changement et non de la taille de l’ensemble du logiciel.

Même si nous avons un grand logiciel, le coût (temps,…) d’un changement rest en relation avec la taille d’un changement. Si nous ajoutons une nouvelle méthode ou modifions une nouvelle méthode, l’effort rest en relation avec l’effort de modification de la méthode, la compilation incrémentielle de la méthode et le chargement incrémentiel de la méthode.

Dans de nombreux environnements logiciels traditionnels, le changement de méthode peut nécessiter une recompilation partielle, un nouvel exécutable lié, un redémarrage, un rechargement, etc. Plus le logiciel est grand, plus il prend de temps.

Pour un humain, cela signifie que nous sums peut-être hors d’ état de stream . Cela fait partie de la productivité des bons environnements Lisp: on peut apporter beaucoup de modifications à un système logiciel en peu de temps, une fois que le programmeur se sent à l’aise et entre dans cet état de stream . J’imagine que beaucoup ont vécu cela, où le travail se fait en peu de temps – par opposition aux périodes où l’on se trouve devant un système qui ne répond pas et où nous sums confrontés à des temps d’attente.

Il y a aussi peu de distance cognitive entre nous et le programme sur lequel nous travaillons. Par exemple, si vous modifiez une classe dans un environnement de traitement par lots, vous devez imaginer l’effet des modifications. Dans Lisp, vous éditez une classe et modifiez en même temps les objects eux-mêmes. Cela signifie que vous modifiez le comportement des objects directement – et non une nouvelle version après un cycle d’édition de compilation-exécution-liaison-exécution.

Dans un système Lisp, vous modifiez une classe dans un système de CAO et vous pouvez l’activer immédiatement. Lorsque les gens se demandent si Lisp fonctionne pour de grandes équipes de logiciels, la réponse est peut-être que l’équipe de logiciels importante n’est pas nécessaire si vous travaillez de manière incrémentielle. Le problème était alors / est-ce que de très bons développeurs de logiciels compétents familiarisés avec le développement incrémental étaient (sont?) Rares.

Dans de nombreuses applications, il existe une couche de langage de script séparée, parfois destinée aux développeurs d’origine (et non aux utilisateurs). En Lisp, ce n’est pas nécessaire, Lisp est son propre langage d’extension .

Dans le monde réel, ceci est principalement utilisé dans le développement et, comme de nombreuses fonctionnalités, il ne vaut mieux que baver dans le bon contexte.

  1. bonheur personnel programmeur illumination *
  2. véritable déploiement continu.
  3. zéro temps d’arrêt prévu Accords de niveau de service.
  4. déboguer les serveurs de production.

* pas de garantie.


Pour moi, et je soupçonne certains autres, le véritable avantage de ce développement basé sur REPL est qu’il peut être indescriptiblement amusant. même addictif. Cela peut parfois donner un sens à l’artisanat. essayez-le … allez, essayez-le, le premier REPL est toujours gratuit 🙂


un gros tirage ces jours-ci est le déploiement continu.

Actuellement, l’idée d’un déploiement continu consiste à changer une chose, à tout construire (ou à en faire un package), puis à la déployer. Avec le modèle lisp, il est en effet possible d’éditer une boîte déployée (généralement une boîte recevant un miroir de sessions client réelles) pendant son déploiement.

juste une note pédante. vous ne modifiez pas réellement les classes en cours d’exécution. vous comstackz une nouvelle copie de la classe et la laissez dans un emplacement connu (un var), la nouvelle copie est trouvée et utilisée lors de sa prochaine utilisation. Ce n’est pas vraiment en cours d’ édition et, tout comme le nouveau code prend effet immédiatement, cela réduit la scope du processus de développement des programmes aux expressions (généralement des fonctions).


Un autre point d’intonation est la possibilité d’obtenir des correctifs de sécurité sans avoir à déclarer de temps d’arrêt . vous pouvez faire une mise à niveau sans que cela ne coûte à votre SLA aucun de vos précieux «temps d’arrêt programmés». Si vous devez planifier des temps d’arrêt planifiés six mois à l’avance et que vous n’en avez que deux heures (pour ces pauvres âmes), cela pourrait les faire baver.


Si vous disposez d’un access de remplacement à votre application en cours de déploiement (potentiellement (avec autorisation) sur un site client), vous pouvez vous connecter à l’application en cours d’exécution et exécuter des tests sur le code existant dans le contexte existant sans avoir à arrêter et connectez un débogueur. vous ne recevrez aucune perte de vitesse avec un débogueur. Il est possible de le faire sans REPL, mais lorsque vous obtenez le répl, vous pouvez créer un nouveau code facilement (certains diront que l’injection de chargeurs de classes dynamics via le débogueur est facile) et que les problèmes sont résolus. Vous pouvez donc vous connecter à un serveur en cours d’exécution. découvrez qu’une fonction n’a pas réussi à se reconnecter à une firebase database après une courte interruption, puis reconnectez-la immédiatement.


Comme pour toutes les constructions de programmation, il n’y aura jamais de solution miracle et ce déploiement / développement continu a un inconvénient intéressant: votre programme peut être correct en mémoire et mal sur le disque. Si vous comstackz une fonction, alors casser et enregistrer alors la seule copie de travail du code est celle en cours d’exécution. Je suis utile pour être conscient de cela et réévaluer les fichiers juste après les avoir sauvegardés.


Cela peut sembler fantaisiste, alors jetez un œil à comment intégrer un Clojure REPL dans votre application de production.

Je me souviens que quelqu’un de la NASA a décrit son expérience. Son équipe a mis au point le soft utilisé dans un vaisseau spatial dans les années 70. Et ils ont effectivement modifié leur logiciel à distance à la volée lorsque des bogues ont été trouvés.

Ou imaginez que vous avez un long processus qui prend des jours pour exécuter et à la fin, il ne peut pas écrire de résultats à cause des permissions ou d’autres petits problèmes.

Encore un autre exemple. Vous êtes en phase d’intégration et vous devez apporter beaucoup de petits changements. Et encore beaucoup d’entre eux. Je rêve d’une telle possibilité en Java car il me faut actuellement 30 à 40 min pour reconstruire et réinstaller mon application (pour la reconstruire à nouveau dans 10 min).

Si vous regardez quelque chose comme Erlang, le but est d’éviter les temps d’arrêt.

Il fonctionne sur des choses comme les commutateurs de téléphone que vous ne pouvez pas simplement éteindre pendant quelques secondes.

Pour des utilisations plus normales, cependant, c’est une fonctionnalité “agréable à avoir”, mais oui, probablement pas critique.

Vous voyez des données réelles. C’est un gros avantage. Vous n’avez alors pas à spéculer.

Parce que vous pouvez?

Sérieusement, essayez-le pendant un certain temps, et vous sentirez la douleur lorsque vous reviendrez dans votre ancien langage de programmation sans REPL.

Un retour instantané, des tests rapides et faciles sans avoir à configurer un état de programme faux dans votre système de test. Possibilité d’inspecter l’état du programme en cours d’exécution (quelle est la valeur de cette variable). Tout cela est un gain de temps réel.

C’est surtout pour le développement, où il ne fait que gagner du temps.

Mais les gains de temps sont d’une importance capitale.

Une fois que vous avez l’habitude de retourner à l’ancienne, vous avez l’impression de passer du vol à la nage dans le goudron.

Dans les systèmes indussortingels, il est utilisé pour la programmation des automates programmables afin de réduire les temps d’arrêt et les conditions dangereuses.

Ce sont des systèmes qui sont utilisés sur les centrales nucléaires, les systèmes de fabrication, les aciéries, etc. Le processus est toujours en cours, continuellement et les temps d’arrêt sont très coûteux ou dangereux. Imaginez un système qui contrôle le refroidissement d’un réacteur nucléaire, vous ne pouvez pas désactiver ce système pour déployer un nouveau code, vous devez pouvoir le modifier en cours d’exécution.

Ceci est similaire à la réponse Erlang pour les systèmes de commutation téléphonique.

Eh bien, imaginez que vous devez patcher un serveur et ne pas l’ arrêter.

Si vous faites cela dans une langue “typique”, cela impliquera de la magie lourde. Vous devez contourner le code d’exécution. Je pense que cela exigerait de patcher les tables de fonctions et ainsi de suite, tout en assemblant et en manipulant les pointeurs vers les fonctions. Un bon endroit pour les insectes.

Dans Lisp, l’idée de mettre à jour sans temps d’arrêt est intégrée au modèle de langage. Bien qu’il y ait des complexités de mise à jour dont vous ne pouvez pas vous passer (comment gérer une connexion de longue durée), cela ne nécessite pas la lourde magie d’un langage compilé.

Bien que je n’y ai pas passé beaucoup de temps (c’est-à-dire quelque chose d’utile), j’ai élaboré un prototype de serveur en Common Lisp qui ferait au moins quelques patches en direct sur un réseau sans temps d’arrêt.

Une autre bonne chose à part la modification du programme à la volée sans avoir à tout redémarrer (cela fait des décennies ne signifie pas que c’est la meilleure chose, non?), Est-ce que vous devez inspecter votre programme dans son état actuel et être capable de comprendre ce qui se passe.

Casey Muratori vient de faire quelques leçons sur la façon de faire avec C et le compilateur C / C ++ de Microsoft. C’est en fait assez simple, juste quelques dizaines de lignes de code. Découvrez les vidéos 24/24/25:

https://www.youtube.com/watch?v=WMSBRk5WG58

En matière de conception de jeux, la raison d’être est d’être capable de régler plus rapidement les constantes pour trouver le ténor émotionnel que vous visez. Des choses comme la sensation de jeu, les scripts de comportement des non-joueurs et l’éclairage / l’ambiance de la pièce en bénéficient beaucoup.