Riscrittura da Java a Clojure


97

La mia azienda mi ha appena chiesto di riscrivere un'applicazione Java di grandi dimensioni (50.000 singole righe di codice) (un'app Web che utilizza JSP e servlet) in Clojure. Qualcun altro ha suggerimenti su cosa dovrei fare attenzione?

Tieni presente che conosco abbastanza bene sia Java che Clojure.

Aggiornare

Ho riscritto ed è entrato in produzione. È abbastanza strano visto che la riscrittura è andata così veloce che è stata fatta in circa 6 settimane. Poiché molte funzionalità non erano ancora necessarie, sono finite più come 3000 linee di Clojure.

Ho sentito che sono contenti del sistema e sta facendo esattamente quello che volevano. L'unico svantaggio è che il tizio che mantiene il sistema ha dovuto imparare Clojure da zero, ed è stato trascinato dentro scalciando e urlando. Ho ricevuto una sua chiamata l'altro giorno che diceva che ora amava il Lisp .. divertente :)

Inoltre, dovrei fare una buona menzione a Vaadin. L'uso di Vaadin ha probabilmente rappresentato la maggior parte del tempo risparmiato e della brevità del codice rispetto a Clojure .. Vaadin è ancora il miglior framework web che abbia mai usato, anche se ora sto imparando ClojureScript con rabbia! (Si noti che sia Vaadin che ClojureScript utilizzano i framework GUI di Google sotto il cofano.)


55
Voglio lavorare per la tua azienda.
mtyaka

4
Ebbene, alcune aziende della difesa in Europa hanno iniziato a usare Clojure (ho sentito). Ma non ricordo nessun nome :)
appshare.co

1
@ Zubair: 50 000 Java LOC non è neanche lontanamente "grande". Questo è un progetto molto piccolo. Ho un progetto Java da 250KLOC a 300KLOC qui ed è di medie dimensioni ... Nella migliore delle ipotesi.
SyntaxT3rr0r

5
In realtà forse ho commesso un errore menzionando la dimensione del codice base in quanto per essere onesti una riduzione della dimensione del codice non è lo scopo della riscrittura. L'obiettivo è duplice: 1) avere la base di codice più comprensibile e quindi più economico per mantenere il codice 2) Consentire agli utenti dello strumento di estendere il prodotto utilizzando un editor Clojure nel browser web (utilizzando eval e altre bontà Clojure dinamiche che è più costoso da fare in Java)
appshare.co

1
Ehi ... ho appena visto questa vecchia domanda e mi chiedevo come stia andando la riscrittura?
levand

Risposte:


82

Il più grande "problema di traduzione" sarà probabilmente il passaggio da una metodologia Java / OOP a un paradigma di programmazione Clojure / funzionale.

In particolare, invece di avere uno stato mutabile all'interno degli oggetti, il "modo clojure" consiste nel separare chiaramente lo stato mutabile e sviluppare funzioni pure (prive di effetti collaterali). Probabilmente sai già tutto questo :-)

Ad ogni modo, questa filosofia tende a condurre verso uno stile di sviluppo "dal basso verso l'alto" in cui si concentra gli sforzi iniziali sulla costruzione del giusto set di strumenti per risolvere il problema, per poi collegarli insieme alla fine. Potrebbe assomigliare a questo

  1. Identifica le strutture di dati chiave e trasformale in una mappa Clojure immutabile o in definizioni di record. Non aver paura di annidare molte mappe immutabili: sono molto efficienti grazie alle strutture dati persistenti di Clojure. Vale la pena guardare questo video per saperne di più.

  2. Sviluppa piccole librerie di funzioni pure, orientate alla logica di business che operano su queste strutture immutabili (es. "Aggiungi un articolo al carrello"). Non è necessario eseguire tutte queste operazioni in una volta poiché è facile aggiungerne altre in seguito, ma aiuta a farne alcune all'inizio per facilitare i test e dimostrare che le strutture dei dati funzionano ..... in entrambi i casi in questo punto puoi effettivamente iniziare a scrivere cose utili in modo interattivo su REPL

  3. Sviluppare separatamente routine di accesso ai dati in grado di rendere persistenti queste strutture al / dal database o dalla rete o dal codice Java legacy secondo necessità. Il motivo per mantenerlo molto separato è che non si desidera che la logica di persistenza sia legata alle funzioni di "logica aziendale". Potresti voler guardare ClojureQL per questo, anche se è anche abbastanza facile avvolgere qualsiasi codice di persistenza Java che ti piace.

  4. Scrivi test unitari (ad esempio con clojure.test ) che coprano tutto quanto sopra. Questo è particolarmente importante in un linguaggio dinamico come Clojure poiché a) non hai molta rete di sicurezza dal controllo del tipo statico eb) aiuta ad essere sicuro che i tuoi costrutti di livello inferiore funzionino bene prima di costruire troppo sopra di loro

  5. Decidi come desideri utilizzare i tipi di riferimento di Clojure (vars, refs, agent e atoms) per gestire ogni parte mutabile dello stato a livello di applicazione. Funzionano tutti in modo simile ma hanno una semantica transazionale / concorrenziale diversa a seconda di ciò che si sta tentando di fare. I ref probabilmente saranno la tua scelta predefinita - ti permettono di implementare un comportamento transazionale STM "normale" avvolgendo qualsiasi codice in un blocco (dosync ...).

  6. Seleziona il framework web generale corretto - Clojure ne ha già un bel po ', ma ti consiglio caldamente Ring - guarda questo eccellente video " One Ring To Bind Them " più Fleet o Enlive o Hiccup a seconda della tua filosofia di template. Quindi usalo per scrivere il tuo livello di presentazione (con funzioni come "traduci questo carrello della spesa in un frammento HTML appropriato")

  7. Infine, scrivi la tua applicazione utilizzando gli strumenti sopra. Se hai eseguito correttamente i passaggi precedenti, questa sarà effettivamente la parte più facile perché sarai in grado di costruire l'intera applicazione mediante la composizione appropriata dei vari componenti con un boilerplate molto piccolo.

Questa è più o meno la sequenza in cui attaccherei il problema poiché rappresenta ampiamente l'ordine delle dipendenze nel codice e quindi è adatta per uno sforzo di sviluppo "dal basso verso l'alto". Anche se, naturalmente, in un buon stile agile / iterativo, probabilmente ti ritroveresti a spingere in avanti in anticipo verso un prodotto finale dimostrabile e poi tornare ai passaggi precedenti abbastanza frequentemente per estendere la funzionalità o il refactoring secondo necessità.

ps Se segui l'approccio di cui sopra, sarei affascinato nel sentire quante righe di Clojure servono per abbinare la funzionalità di 50.000 righe di Java

Aggiornamento : da quando questo post è stato scritto originariamente, sono emersi un paio di strumenti / librerie extra che si trovano nella categoria "check out":

  • Noir - framework web che si basa su Ring.
  • Korma - un DSL molto carino per l'accesso ai database SQL.

4
Nitpick re: "Decidi quale dei tipi di riferimento STM di Clojure vuoi utilizzare per gestire ogni parte modificabile dello stato a livello di applicazione": C'è solo un tipo di riferimento STM. Gli altri IRef non coinvolgono STM. Altrimenti sembra un consiglio solido.

hmmm ... immagino di contare gli arbitri, gli agenti e gli atomi come tutti facenti parte del sistema Clojure STM / concorrenza. Ad esempio, supportano tutti i validatori e gli agenti sono coordinati con i commit delle transazioni. ma ho capito il tuo punto, gli arbitri sono il modello transazionale "primario". farà una rapida modifica.
mikera

2
Se solo potessi dare più +1. Ho guardato entrambi i video a cui hai fatto riferimento ed erano fantastici. Grazie.
jdl

1
Ora il noir è deprecato. Suppongo che tu debba menzionare il compojure invece del noir.
hsestupin

Un anello per legarli è interrotto!
Adam Arold

5

Quali aspetti di Java include il tuo progetto attuale? Registrazione, transazioni di database, transazioni dichiarative / EJB, livello web (hai menzionato JSP, servlet) ecc. Ho notato che l'ecosistema Clojure ha vari micro-framework e librerie con l'obiettivo di svolgere un'attività e farlo bene. Suggerirei di valutare le biblioteche in base alle tue necessità (e se scalare in progetti di grandi dimensioni) e prendere una decisione informata. (Dichiarazione di non responsabilità: sono l'autore di bitumenframework ) Un'altra cosa da notare è il processo di costruzione: se hai bisogno di una configurazione complessa (dev, testing, staging, prod) potresti dover dividere il progetto in moduli e avere il processo di build programmato per facilità.


Servlet, JSP, framework di persistenza costruito in casa (10 anni) e pojo, ma nessun EJB
appshare.co

4
I servlet possono essere facilmente sostituiti con Ring + Compojure IMHO e i JSP possono essere sostituiti con forse StringTemplate (o modelli FreeMarker / Velocity). La persistenza in Clojure sarà diversa da Java. Se hai bisogno di mappatura relazionale, puoi guardare Clj-Record e SQLRat (non ancora molto maturo). ClojureQL supporta solo MySQL e PostgreSQL al momento AFAICT. L'attuale limitazione in ccsql di non consentire il carattere di sottolineatura nei nomi delle colonne potrebbe sorprendere. Penso che sarà utile discutere gli aspetti di sviluppo nell'elenco Clojure come e quando sarà necessario. Buona fortuna per il progetto!
Shantanu Kumar

Da quel progetto ho realizzato un'altra applicazione con Clojure e Clojurescript (nemcv.com) e ora sto usando Ring, ho provato ClojureQL, ma sono passato a Korma per l'accesso al database. Puoi vedere l'ultimo lavoro su github.com/zubairq/coils
appshare.co

4

Ho scoperto che la parte più difficile era pensare al database. Esegui alcuni test per trovare gli strumenti giusti che desideri utilizzare lì.


1
Beh, ho provato clojureql per l'accesso ai dati, ma è totalmente diverso dallo stile Java di accesso al database che è tutto basato su oggetti. Solo per interesse quale accesso al database hai usato per Java e cosa hai usato con Clojure?
appshare.co

1
Abbiamo finito per ripensare un sacco di cose e andare con mongodb poiché la persistenza delle strutture di dati clojure era molto naturale
LenW
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.