Stack Clojure up-to-date

77 views
Skip to first unread message

Jérémie Grodziski

unread,
Mar 6, 2016, 11:45:58 AM3/6/16
to cloju...@googlegroups.com
Salut les Clojurists,

J'ai reçu cette demande de l'ami Yannick Grenzinger sur une stack Clojure qui serait à jour pour un side-project.
Ma réponse est en dessous, je pense qu'elle peut intéresser la communauté, n'hésitez pas à apporter vos contributions et à lancer les débats ! :-)

Je me lance dans un projet que j'aimerais faire en full clojure.
C'est vraiment un toy project assez basique. Juste convertir une feuille excel qui permet de calculer des prix de créations (prix HT, TTC, Vendeur, client final en fonction du temps de fabrication et du prix des matière 1ère).
Que me conseilles-tu ?
J'aime bien démarrer avec une stack fournissant un bon exemple (JHipster est très intéressant par exemple dans le monde Spring + Angulaire)

Bonne question, comment j'aborderais le truc ?
Premier point, regarder les couches externes du système : le front et le stockage, je prend comme hypothèse que tu feras du DDD au centre :-) 
  • Front : as tu envie de faire une Single-Page Application ou un truc plus classique à la MVC ?
  • Storage : base relationnel type Postgres, Mongo ou Datomic ?
C'est pour moi les deux gros points structurant, le reste est assez classique et tu peux l'ajouter au fur et à mesure si tu suis bien l'architecture hexagonale. C'est d'ailleurs dans ma todo list de talks "Archi hexagonale style DDD en Clojure" :-)
De manière générale les templates Leiningen sont assez bien fait (ex celui de Reagent) et te permettent un up-and-running rapide.Tu as des templates plus généraux comme Closp mais avec des choix plus arrêtés. Regardes également le bouquin Clojure Applied c'est très bien pour s'y retrouver, ainsi que le Technology Radar Clojure de Juxt.

Perso voici ce que je prendrais :
  • Domain : mount (moins intrusif que Component IMHO) + schema + clj-time + core.async si accès concurrents. Après il te faudra choisir quelques libs plus spécialisés comme pour l'authentification avec Buddy ou Friend mais c'est moins impactant.
  • Storage : au choix suivant les besoins, Datomic peut être too much pour des trucs simple, et le tooling de Postgres est quand même super mature. Je suis d'accord que le onboarding sur Mongo est super rapide (c'est après que ça se gâte :-)).
  • Front : 
    • côté web server un mélange de Ring + Hiccup ou Enlive si Designer non dev, 
    • côté API : pas d'idées arrêtés sur la couche API, Liberator est pas mal mais manque un vrai support du HATERAS (l'ami Hiram me souffle Yada).
    • côté client si l'interactivité requise justifie une SPA : Reagent + Datascript + Core.async en suivant ce que propose l'architecture elm. Je suis assez en phase avec le ROCA style mais en pratique c'est pas super simple.
  • Env de dév : moins structurant mais pénible à upgrader, perso je reste sur Leiningen + Cursive c'est mature et ça fait le taf (j'ai migré depuis emacs il y a 6 mois), j'ai pas encore saisi l'intérêt de passer à Boot hormis pour la customisation et la beauté de faire un pipeline plutôt que du déclaratif...

Précisions suite à mon retour :
Ca sera du SPA avec une api REST et sous MongoDB (parce que ça permet d'expérimenter rapidement au début).
La j'ai commencé avec Ring/Compojure et Monger (pour Mongo). Je pense que je vais mettre rapidement ça sur Github pour avoir du feedback.


Jérémie.

Karim SENHAJI

unread,
Mar 7, 2016, 7:22:52 AM3/7/16
to cloju...@googlegroups.com
Salut Jérémie,

Tu peux regarder du côté de Luminus qui crée un template avec pas mal de dépendances déjà setté.
Pour se lancer, ça permet d'éviter de devoir fouiner dans toute les biblis disponibles dans l'écosysteme Clojure.

Il fait des choix similaire à ce que tu proposes:
- Mount pour gérer le lifecycle
- Reageant et Hiccup avec le profile +cljs 
- Buddy avec le profile +auth
- Un profil pour postrgerSql ou Mongo
- Swagger et compojure api pour l'API et la doc qui va avec
Tout les profiles sont là: http://www.luminusweb.net/docs/profiles.md

Et la doc' de ce template est assez bien fourni (avec un livre qui l'utilise comme base qui vient de sortir dans sa seconde édition).

Bonne journée,
Karim

--
Vous recevez ce message, car vous êtes abonné au groupe Google Groupes "clojure-fr".
Pour vous désabonner de ce groupe et ne plus recevoir d'e-mails le concernant, envoyez un e-mail à l'adresse clojure-fr+...@googlegroups.com.
Pour obtenir davantage d'options, consultez la page https://groups.google.com/d/optout.

yannick grenzinger

unread,
Mar 7, 2016, 2:00:42 PM3/7/16
to clojure-fr
Hello,

Merci Jérémie pour avoir lancer cette discussion :)

J'ai un tout petit peu commencé avec Compojure / ring + Monger (parce que j'aime bien Mongo pour prototyper).

J'avais oublié d'aller regarder Luminus (et y a pedestal aussi ?).

Je vais me faire un PoC rapide sur Luminus.

yannick grenzinger

unread,
Mar 23, 2016, 9:59:10 AM3/23/16
to clojure-fr
Hop je suis parti sur Luminus et j'ai réussi à faire mon 1er service Web (merci Swagger pour les tests).

Maintenant j'ai un "gros" problème de productivité  ... principalement du au fait que : 
- je n'arrive pas à travailler avec le REPL avec l'ensemble de l'application
- je n'arrive pas à faire du code reload au save

En clair, pour l'instant, je fais un truc. Ca explose parce que je maitrise mal clojure et les libs (surtout monger). Je peux pas débug. Donc je coupe le "lein run" et je relance ... et je me prends 10 sec dans la vue ... :(

Je cherche donc un workflow plus efficace :)

Arnaud Bailly

unread,
Mar 23, 2016, 10:20:04 AM3/23/16
to cloju...@googlegroups.com
figwheel ?

-- 
Arnaud Bailly

twitter: abailly
skype: arnaud-bailly

Jérémie Grodziski

unread,
Mar 23, 2016, 10:40:18 AM3/23/16
to cloju...@googlegroups.com
Salut Yannick,

Je ne connais pas Luminus mais je sais que ring avec son plugin Lein (lein-ring) fait de l'auto-reload et ça marche très bien. 
Sinon regarde Component (https://github.com/stuartsierra/component) ou Mount (https://github.com/tolitius/mount), Mount a ma préférence car moins intrusif je trouve que Component. 

laurent joigny

unread,
Mar 24, 2016, 7:29:13 AM3/24/16
to clojure-fr
Yannick,

Si tu veux profiter de la productivité du repl il faut effectivement que tu travailles dans le repl ou du moins dans sa jvm.
Plus généralement si tu veux du rechargement de code, il faut que les modifications de ton code impactent la jvm où tourne ton application.

Petit récap jvm

 - lein repl => jvm 1
 - Tu lances un repl local à ton éditeur/IDE => jvm 2
 - Tu connectes ton éditeur/IDE à "remote repl" lancé avec lein => jvm1 (le code évalué dans l'éditeur est "visible" dans la console lein repl)
 - lein run => jvm 3
 - lein ring server => jvm 4


Maintenant tu veux du rechargement de code, tu as différentes techniques plus ou moins efficaces ou plus ou moins à la mode.


1 - Les outils de base de Clojure (évaluation & require)

Clojure fourni un mécanisme de rechargement de code dans le repl, il suffit en générale de ré-évaluer une expression. Quand on a fait des changements un peu partout, difficile de savoir quoi ré-évaluer alors on peut utiliser `require` avec les options :reload ou :reload-all.

En utilisant `require` les vars définies avec `defonce` ne seront pas affectées, ce qui veux dire que si tu as un état de ton appli défini avec `defonce`, après rechargement tu conserves ton état.

1.1 - Require manuel
  - Tu démarres un repl, tu connectes ton IDE au repl, vous êtes dans la même jvm youpi
  - Tu démarres ton serveur web dans le repl avec ton handler ring (oui oui tout seul comme un grand du démarre jetty)
  - Ya plus qu'à faire des modifs de code, a ré-évaluer des expressions ou à faire des `require` :reload

  points + : IDE et repl sont liés (introspection des vars, etc), utilisation possible de `defonce`
  points - : on démarre tout soi-même dans la jvm du repl

1.2 - Require automatique avec Lein Ring
  Si tu utilises le plugin Ring de Lein, celui-ci démarre un serveur web avec ton handler dans une jvm spécifique qui n'est pas liée à ton IDE.
  Le plugin surveille les fichiers sources, dès qu'il y a des changements il fait des `require` en tache de fond.

  points + : Ya plus qu'à coder, utilisation possible de `defonce`
  points - : Le code évaluer dans le repl de l'IDE n'a pas de lien avec la jvm du plugin, donc pas possible de faire de l'introspection des vars du programme


2 - Un rechargement plus robuste : clojure.tools.namespace.repl

Je te laisse lire plus en détail le README du projet clojure.tools.namespace, mais le `require` de Clojure peut louper quelques redéfinitions notamment lorsque tu utilises les protocols, les multimethods, les macros entre différents namespaces.

Donc M. Sierra à fait cette lib pour faire tous les `require` nécessaires au bon rechargement de ton code, et comme il veut un état bien propre après rechargement il vire même les `defonce`.

2.1 - Emergence d'un workflow
  Travailler avec c.t.n.repl impose un certain workflow, qui est un peu expliqué dans le README du projet. En effet on ne peut conserver l'état de l'application après rechargement, il faut donc avoir un moyen de re-créer rapidement cet état. M. Sierra propose de se faire des fonctions d'aides à la création/destruction de l'état du programme dans le namespace 'user' (namespace par défaut du repl qui peut être adossé à un fichier user.clj dans le classpath).

2.2 - Component
  M. Sierra a poussé la réflexion plus loin et a fini par faire la lib Component pour formaliser un workflow adapté à l'utilisation de c.t.n.repl.

2.3 - Mount
  D'aucuns diront qu'utiliser Component demande de se soumettre à une façon d'exprimer ses dépendances qui ressemble beaucoup aux concepts OO avec une utilisation massive des Records.
  D'où la création de la lib Mount pour n'utiliser que des fonctions et faire confiance à Clojure pour gérer la dépendance entre namespace.


Voilà voilà j'avais un peu de temps libre ;)

yannick grenzinger

unread,
Mar 24, 2016, 11:30:48 AM3/24/16
to clojure-fr
Mon cerveau brule mais ça me donne des pistes.

Pour info, Luminus est basé sur Ring et aussi Mount.
Malheureusement contrairement à ce que dis la doc, démarrer lein repl dans mon projet ne passe sur le bon namespace et reste sur le namespace 'user'.

C'est la où je me dis que les frameworks c'est bien pour démarrer et avoir une structure. Mais dés que ça ne marche pas, le débutant se prend une pelle dans la tronche :(

Arnaud Bailly

unread,
Mar 24, 2016, 11:35:44 AM3/24/16
to cloju...@googlegroups.com

Bon j'ai dit une connerie bien sur : figwheel c'est pour clojurescript...

m cb

unread,
Mar 24, 2016, 3:55:16 PM3/24/16
to cloju...@googlegroups.com
Bonjour,

Je ne sais pas si parler de mount/component à un débutant en clojure soit une bonne idée. Certes, ce sont des outils très pratiques/puissants, mais que l'on doit aborder après avoir acquis les bases du langage, les outils autour (lein, ide...), et la bonne utilisation du REPL.

Même Luminus finalement je trouve ça assez violent pour un débutant. Trop de libs, trop de dépendances... De quoi être perdu très vite.

Il faut selon moi se focaliser sur l'essentiel, c'est à dire :

- ring/compojure, avec la méthode "1.2 - Require automatique avec Lein Ring" conseillée par Laurent. Avec cela, en 2 minutes on a un projet prêt à l'emploi, un repl qui fonctionne... C'est pas parfait mais suffisant quand on commence le langage.

D'ailleurs, je pense que pour un débutant le mieux est de commencer un projet non web, quitte à rajouter la couche web après. Cela permet de n'avoir pas à gérer la partie serveur web/reload, du moins au début.

Bref, se concentrer d'abord par exemple sur la partie db, en créant quelques namespaces permettant de faire les opérations de base, puis quelques autres namespaces qui rajoutent la logique autour de tout ça, avoir quelques fonctions qui renvoient sous forme de map (prêtes à être transformées en json ;) ) les résultats attendues aux différentes opérations, découvrir clojure.test et l'utilisation du repl...

Yannick, je te conseille vivement cette approche. J'ai lu que tu voulais faire du Mongo, crée juste un ou deux namespaces en important la lib mongo et commence à écrire quelques fonctions pour insert/update... Puis crée quelques namespaces qui utilisent ces namespaces mongo. N'utilise que le REPL, et pourquoi pas clojure.test, pour simuler ton service rest.
Une fois les bases saisies, là on peut commencer la partie web (en restant simple). Branche tout simplement aux routes Compojure les fonctions que tu as écris précédemment.

C'est selon moi une mauvaise approche, surtout pour un débutant, de ce lancer dans un projet demandant de maitriser trop de libs d'un coup. Commencez petit, créez votre projet fonction par fonction, namespace par namespace, en rajoutant les dépendances au fur et à mesure, c'est ça la force de Clojure ! Une fois le langage maîtrisé/les outils connus, utiliser des outils comme Luminus/component... pourquoi pas, mais pas pour un débutant.

Clojure n'est pas forcément très facile d'accès pour un débutant (syntaxe non habituelle pour beaucoup de gens, doc parfois pas top, environnement de dev difficile à mettre en place comme on peut le voir dans cette discussion), il ne faut surtout pas rajouter plus de complexité (c'est le meilleur moyen de faire fuir les gens).

Cordialement,

Mathieu


yannick grenzinger

unread,
Mar 25, 2016, 6:18:26 AM3/25/16
to clojure-fr
Merci pour tous ces conseils :)


Le dimanche 6 mars 2016 17:45:58 UTC+1, Jérémie Grodziski a écrit :
Reply all
Reply to author
Forward
0 new messages