97 votes

Réécriture de Java vers Clojure

Mon entreprise vient de me demander de réécrire une application Java de grande envergure (50 000 lignes de code) (une application Web utilisant JSP et des servlets) en Clojure. Quelqu'un d'autre a-t-il des conseils à me donner sur ce à quoi je dois faire attention ?

N'oubliez pas que je connais très bien Java et Clojure.

Mise à jour

J'ai fait la réécriture et c'est parti en production. C'est assez étrange car la réécriture s'est déroulée si rapidement qu'elle a été réalisée en 6 semaines environ. Comme beaucoup de fonctionnalités n'étaient pas nécessaires, il s'agissait plutôt de 3000 lignes de Clojure.

J'ai entendu dire qu'ils étaient satisfaits du système et qu'il faisait exactement ce qu'ils voulaient. Le seul inconvénient est que le responsable de la maintenance du système a dû apprendre Clojure à partir de zéro, et qu'il y a été entraîné de force. Il m'a appelé l'autre jour pour me dire qu'il aimait Lisp maintenant drôle :)

Je dois également faire une mention spéciale à Vaadin. L'utilisation de Vaadin est probablement à l'origine d'une part aussi importante du gain de temps et de la brièveté du code que Clojure Vaadin reste le meilleur framework web que j'ai jamais utilisé, même si maintenant j'apprends ClojureScript avec colère ! (Notez que Vaadin et ClojureScript utilisent tous deux les frameworks GUI de Google sous le capot).

55 votes

Je veux travailler pour votre entreprise.

4 votes

Eh bien, certaines entreprises de défense en Europe ont commencé à utiliser Clojure (j'ai entendu dire). Mais je ne me souviens d'aucun nom :)

1 votes

@Zubair : 50 000 Java LOC, c'est loin d'être "énorme". Il s'agit d'un très petit projet. J'ai un projet Java de 250KLOC à 300KLOC ici et c'est un projet de taille moyenne... Au mieux.

82voto

mikera Points 63056

Le plus grand "problème de traduction" sera probablement de passer d'une méthodologie Java / POO à un paradigme Clojure / programmation fonctionnelle.

En particulier, au lieu d'avoir un état mutable dans les objets, la "méthode Clojure" consiste à séparer clairement l'état mutable et à développer des fonctions pures (sans effets secondaires). Vous savez probablement déjà tout cela :-)

Quoi qu'il en soit, cette philosophie tend à conduire à un style de développement "ascendant" dans lequel vous concentrez les efforts initiaux sur la construction du bon ensemble d'outils pour résoudre votre problème, puis vous les connectez ensemble à la fin. Cela peut ressembler à quelque chose comme ceci

  1. Identifiez les structures de données clés et transformez-les en définitions immuables de map ou d'enregistrement Clojure. N'ayez pas peur d'imbriquer beaucoup de maps immuables - elles sont très efficaces grâce aux structures de données persistantes de Clojure. À voir absolument cette vidéo pour en savoir plus.

  2. Développez de petites bibliothèques de fonctions pures, orientées vers la logique commerciale, qui opèrent sur ces structures immuables (par exemple, "ajouter un article au panier"). Il n'est pas nécessaire de tout faire en même temps car il est facile d'en ajouter plus tard, mais il est utile d'en faire quelques-unes dès le début pour faciliter les tests et prouver que vos structures de données fonctionnent...... De toute façon, à ce stade, vous pouvez commencer à écrire des choses utiles de manière interactive dans le REPL.

  3. Développez séparément des routines d'accès aux données qui peuvent faire persister ces structures vers/depuis la base de données ou le réseau ou le code Java hérité, selon les besoins. La raison de cette séparation est que vous ne voulez pas que la logique de persistance soit liée à vos fonctions de "logique commerciale". Vous pouvez envisager de ClojureQL pour cela, bien qu'il soit également très facile d'envelopper tout code de persistance Java que vous souhaitez.

  4. Écrire des tests unitaires (par exemple avec clojure.test ) qui couvrent tout ce qui précède. C'est particulièrement important dans un langage dynamique comme Clojure car a) vous ne disposez pas d'un filet de sécurité aussi important que la vérification statique des types et b) il est utile de s'assurer que vos constructions de niveau inférieur fonctionnent bien avant de construire trop au-dessus d'elles.

  5. Décidez de la manière dont vous souhaitez utiliser les types de référence de Clojure (vars, refs, agents et atomes) pour gérer chaque partie de l'état mutable au niveau de l'application. Ils fonctionnent tous de manière similaire mais ont une sémantique transactionnelle/de concordance différente selon ce que vous essayez de faire. Les refs seront probablement votre choix par défaut - ils vous permettent d'implémenter un comportement transactionnel STM "normal" en enveloppant tout code dans un bloc (dosync ...).

  6. Choisir le bon framework web global - Clojure en possède déjà plusieurs mais je recommande fortement Ring - voir cette excellente vidéo " Un anneau pour les lier "plus soit Flotte o Enlive o Hiccup en fonction de votre philosophie de modélisation. Utilisez ensuite cette couche pour écrire votre couche de présentation (avec des fonctions telles que "traduire ce panier d'achat en un fragment HTML approprié").

  7. Enfin, écrivez votre application en utilisant les outils ci-dessus. Si vous avez suivi correctement les étapes précédentes, cette étape sera en fait la plus facile, car vous serez en mesure de construire l'ensemble de l'application par la composition appropriée des différents composants avec très peu de texte passe-partout.

C'est à peu près l'ordre dans lequel j'attaquerais le problème car il représente largement l'ordre des dépendances dans votre code, et convient donc à un effort de développement "ascendant". Bien sûr, dans un bon style agile/itératif, vous vous retrouveriez probablement à avancer rapidement vers un produit final démontrable, puis à revenir assez fréquemment aux étapes précédentes pour étendre les fonctionnalités ou remanier le code si nécessaire.

p.s. Si vous suivez l'approche ci-dessus, je serais fasciné d'entendre combien de lignes de Clojure il faut pour correspondre à la fonctionnalité de 50 000 lignes de Java.

Mise à jour : Depuis que ce billet a été écrit, quelques outils/bibliothèques supplémentaires sont apparus et font partie de la catégorie " à vérifier absolument " :

  • Noir - qui s'appuie sur Ring.
  • Korma - un très beau DSL pour accéder aux bases de données SQL.

4 votes

Nitpick re : "Décidez lequel des types de référence STM de Clojure vous voulez utiliser pour gérer chaque partie de l'état mutable au niveau de l'application" : Il n'y a qu'un seul type de référence STM. Les autres IRefs n'impliquent pas de STM. Sinon, c'est un conseil solide.

0 votes

Hmmm... Je pense que je considère que les refs, les agents et les atomes font tous partie du système STM/concurrence de Clojure. Par exemple, ils supportent tous les validateurs, et les agents sont coordonnés avec les commits des transactions. Mais je comprends votre point de vue, les refs sont le modèle transactionnel "primaire". Je vais faire une modification rapide.

2 votes

Si seulement je pouvais lui donner plus de +1. J'ai regardé les deux vidéos que vous avez référencées, et elles étaient excellentes. Merci.

5voto

Shantanu Kumar Points 558

Quels aspects de Java votre projet actuel inclut-il ? Logging, transactions de base de données, transactions déclaratives/EJB, couche web (vous avez mentionné JSP, servlets), etc. J'ai remarqué que l'écosystème Clojure comporte divers micro-frameworks et bibliothèques dont le but est de réaliser une tâche, et de la réaliser correctement. Je vous suggère d'évaluer les bibliothèques en fonction de vos besoins (et de savoir si elles peuvent s'adapter à de grands projets) et de prendre une décision éclairée. (Disclaimer : Je suis l'auteur de cadre de bitume ) Une autre chose à noter est le processus de construction - si vous avez besoin d'une configuration complexe (dev, testing, staging, prod) vous pouvez avoir à diviser le projet en modules et avoir le processus de construction scripté pour la facilité.

0 votes

Servlets, JSP, cadre de persistance maison (vieux de 10 ans) et pojos, mais pas d'EJB.

4 votes

Les servlets peuvent être facilement remplacés par Ring+Compojure, et les JSP peuvent être remplacés par StringTemplate (ou des modèles FreeMarker/Velocity). La persistance en Clojure sera différente de celle de Java. Si vous avez besoin d'un mappage relationnel, vous pouvez vous tourner vers Clj-Record et SQLRat (pas encore très mature). ClojureQL ne supporte pour l'instant que MySQL et PostgreSQL (AFAICT). La limitation actuelle de c.c.sql qui interdit les underscores dans les noms de colonnes peut être une surprise. Je pense qu'il sera utile de discuter des aspects du développement sur la liste Clojure au fur et à mesure des besoins. Bonne chance dans ce projet !

0 votes

Depuis ce projet, j'ai réalisé une autre application avec Clojure et Clojurescript (nemcv.com) et j'utilise maintenant Ring, j'ai essayé ClojureQL, mais je passe à Korma pour l'accès aux bases de données. Vous pouvez voir les derniers travaux à github.com/zubairq/coils

4voto

LenW Points 1336

J'ai trouvé que la partie la plus difficile était de penser à la base de données. Faites quelques tests pour trouver les bons outils que vous voulez utiliser là-bas.

1 votes

J'ai essayé clojureql pour l'accès aux données, mais c'est totalement différent du style Java d'accès aux bases de données, qui est entièrement basé sur les objets. Juste par curiosité, quel accès aux bases de données utilisiez-vous pour Java et qu'utilisiez-vous avec Clojure ?

1 votes

Nous avons fini par repenser beaucoup de choses et par opter pour mongodb, car la persistance des structures de données en clojure était très naturelle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X