Les meilleures pratiques pour créer et déployer des applications Clojure: bons tutoriels?

Je suis nouveau à Clojure et je commence à expérimenter avec la création d’une application.

Jusqu’à présent, tout ce que j’ai vu des tutoriels sur la compilation des programmes Clojure implique l’interactivité. Par exemple, “chargez le fichier REPL et saisissez-le (fichier de chargement” this-or-that “) pour qu’il fonctionne, ce n’est pas suffisant.

Je suis tellement habitué aux idiomes d’édition-compilation de langages comme C ou Delphi, que je suis instinctivement amené à faire des modifications, puis appuyez sur “Mx comstack”.

Le problème est que “lein uberjar”, ce qui, à mon avis, équivaut à “make”, est douloureusement lent à exécuter, même pour un monde salutaire. Donc, je vais devoir comprendre comment fonctionne ce “développement interactif”, cesser d’utiliser le uberjar comme si c’était rapide, et ne le sauvegarder que pour la fin de la journée.

Une autre chose que j’ai remarquée lors de la construction (en utilisant lein uberjar) est que la petite application graphique sur laquelle je travaille affiche des images dans le processus de compilation, comme si elles s’exécutaient lors de la compilation. Cela me semble un peu contre-intuitif; ce n’est pas aussi analogue à “faire” que je le pensais.

Je sais que la méthode Lisp pour développer les choses fonctionne de manière interactive dans le REPL, et je n’essaie pas de changer cela: j’aimerais m’adapter à ce mode de vie. Malheureusement, j’ai peu vu sous forme de documentation sur la façon de le faire. Par exemple, comment réinitialiser l’état actuel de la machine. Il semble juste assez compliqué de continuer à comstackr des extraits individuels à la volée sans pouvoir effectuer une sorte de réinitialisation.

La plupart des tutoriels que j’ai vus sur Clojure (et Lisp) en général semblent se concentrer sur le piratage dans la REPL. Les meilleures pratiques en matière de déploiement d’applications restnt un mystère pour moi. Mes utilisateurs vont juste être des utilisateurs; ils ne vont pas être des développeurs qui vont charger des fichiers dans une REPL.

Voici donc ma question: des ressources pour de bonnes informations ou des tutoriels sur l’ensemble du processus de création d’une application Clojure, y compris le déploiement?

(Remarque: tous les prérequirejs sont installés et fonctionnent (par exemple, Emacs, Slime, Leiningen, etc.), ce n’est donc pas une question à ce sujet).

Quelques astuces, puis quelques liens:

N’utilisez pas lein uberjar pendant le développement; préférez le lein jar . La différence est que lein uberjar met toutes vos dépendances dans le lein uberjar jar généré (y compris Clojure lui-même), de sorte que votre fichier jar est un package entièrement autonome avec votre application à l’intérieur; lein jar ne lein jar que votre propre code. L’approche uberjar présente des avantages évidents pour le déploiement, mais pour le développement, vous devriez pouvoir utiliser le chemin de classe approprié lors de l’exécution de votre application, ce qui vous permet de gagner du temps pour préparer un uberjar. Si vous ne souhaitez pas gérer manuellement le classpath pour les tests, consultez le plugin lein run .

De plus, il est fort probable que la majorité de votre code ne devrait pas être compilé par AOT. AOT est nécessaire dans certains scénarios d’interopérabilité Java, mais la plupart du temps, cela amène une légère augmentation de la vitesse de démarrage et des problèmes gênants avec la compatibilité binary avec différentes versions de Clojure. Je suppose que ce dernier problème ne concerne pas un type de projet d’application autonome uberjar , mais au moins tout code de bibliothèque devrait être laissé à JIT si possible. Avec Leiningen, vous pouvez mettre une clause :namespaces dans le formulaire defproject dans project.clj pour déterminer les espaces de noms à comstackr. tout ce que vous omettez sera actuellement JIT-ed par défaut. Les anciennes versions de Leiningen compilaient tout par défaut, ce qui est une bonne raison de mettre à jour!

En ce qui concerne les fenêtres apparaissant lors de la compilation, je suppose que vous exécutez du code de sortie de fenêtre pendant le temps d’expansion de la macro ou en dehors de toute définition de fonction ou construction similaire. (Quelque chose comme (println "Foo!") Au plus haut niveau.) C’est quelque chose que vous ne devriez pas faire, je suppose – à moins que vous ne vouliez exécuter votre code en tant que script. Pour éviter le problème, placez le code à effet de côté dans les définitions de fonction et fournissez un point d’entrée à votre application à l’aide de la clause :main dans project.clj . (Si vous dites :main foo , alors la fonction -main de l’espace de noms foo sera utilisée comme point d’entrée de votre application. C’est le défaut, de toute façon, et le nom du code ci-dessus semble avoir le nom codé – pas sûr de lein lui-même.)

En ce qui concerne la réinitialisation de l’état du REPL, vous pouvez simplement le redémarrer. Avec SLIME, Mx slime-restart-inferior-lisp le fera tout en conservant tous les autres états de votre session Emacs.

Voir aussi ces discussions sur le groupe Google Clojure:

  1. Clojure pour l’administration du système
  2. Préparation de l’emballage pour l’emballage (était: Re: Clojure pour l’administration du système)
  3. Leiningen, Clojure et les bibliothèques: qu’est-ce qui me manque?

Non, vous n’entrez pas de fonctions sur le REPL.

Vous éditez vos fichiers sources, comme d’habitude. L’avantage Lisp est que le système est exécuté en arrière-plan en même temps. Vous pouvez donc comstackr des fonctions individuelles à partir de votre fichier source et les placer dans le système en cours d’exécution, ou même les remplacer.

Si vous utilisez Slime, appuyez sur Cc Cc dans votre fichier source pour comstackr et charger la fonction au point. Vous pouvez ensuite basculer vers REPL pour tester et explorer, mais tout ce que vous voulez conserver comme source, vous le mettez dans vos fichiers sources.

Les didacticiels commencent généralement par saisir des éléments sur REPL, car il n’y a pas grand chose à configurer pour cela, mais un développement sérieux intègre le système en cours et la gestion des fichiers sources.


Juste pour illustrer, mon workflow habituel (j’utilise Common Lisp, mais Clojure est similaire) est comme ceci:

  • Démarrer Emacs
  • Mx slime pour démarrer Slime, le système Lisp, et connecter les deux via Swank
  • , (commande) foo load-system de chargement pour charger le projet en cours (compilation uniquement si nécessaire) dans l’image
  • Cx b passer à un tampon source
  • Cc ~ fait du répertoire source le répertoire courant et le paquet source le paquet actuel du REPL

Maintenant, je suis configuré avec mon système en arrière-plan. Travailler c’est alors:

  • changer ou append une définition de fonction ou de classe
  • Cc Cc pour comstackr et charger dans l’image
  • passer à REPL, tester
  • déboguer

Il n’y a pas de pauses de compilation significatives, car je ne comstack jamais tout à la fois, juste des définitions individuelles.