Reescritura de Java a Clojure

97

Mi empresa me acaba de pedir que reescriba una aplicación Java grande (50.000 líneas únicas de código) (una aplicación web que usa JSP y servlets) en Clojure. ¿Alguien más ha recibido consejos sobre lo que debo tener en cuenta?

Tenga en cuenta que conozco bastante bien tanto Java como Clojure.

Actualizar

Hice la reescritura y entró en producción. Es bastante extraño ya que la reescritura terminó yendo tan rápido que se hizo en aproximadamente 6 semanas. Debido a que todavía no se necesitaba mucha funcionalidad, terminó más como 3000 líneas de Clojure.

Escuché que están contentos con el sistema y está haciendo exactamente lo que querían. El único inconveniente es que el tipo que mantenía el sistema tuvo que aprender Clojure desde cero, y fue arrastrado a él pateando y gritando. Recibí una llamada de él el otro día diciendo que ahora amaba a Lisp ... gracioso :)

Además, debería dar una buena mención a Vaadin. El uso de Vaadin probablemente representó la mayor parte del tiempo ahorrado y la brevedad del código como lo hizo Clojure. Vaadin sigue siendo el marco web superior que he usado, ¡aunque ahora estoy aprendiendo ClojureScript con ira! (Tenga en cuenta que tanto Vaadin como ClojureScript usan los marcos de GUI de Google debajo del capó).

appshare.co
fuente
55
Quiero trabajar para tu empresa.
mtyaka
4
Bueno, algunas empresas de defensa en Europa han comenzado a usar Clojure (escuché). Pero no recuerdo ningún nombre :)
appshare.co
1
@Zubair: 50 000 Java LOC no es ni de lejos "grande". Este es un proyecto muy pequeño. Tengo un proyecto Java de 250KLOC a 300KLOC aquí y es de tamaño mediano ... En el mejor de los casos.
Sintaxis T3rr0r
5
En realidad, tal vez cometí un error al mencionar el tamaño del código base, ya que para ser justo, una reducción en el tamaño del código no es el objetivo de la reescritura. El objetivo es doble: 1) hacer que el código base sea más comprensible y, por lo tanto, más económico de mantener el código 2) Permitir a los usuarios de la herramienta extender el producto usando un editor de Clojure en el navegador web (usando eval y otras bondades dinámicas de Clojure que son más costosas para hacer en Java)
appshare.co
1
Oye ... acabo de ver esta pregunta anterior y me preguntaba cómo va la reescritura.
Levante y

Respuestas:

82

El mayor "problema de traducción" probablemente será pasar de una metodología Java / OOP a un paradigma de programación funcional / Clojure.

En particular, en lugar de tener un estado mutable dentro de los objetos, la "forma de Clojure" es separar claramente el estado mutable y desarrollar funciones puras (libres de efectos secundarios). Probablemente ya sepas todo esto :-)

De todos modos, esta filosofía tiende a conducir hacia una especie de estilo de desarrollo "de abajo hacia arriba" en el que concentra los esfuerzos iniciales en crear el conjunto de herramientas adecuado para resolver su problema, y ​​finalmente conectarlos al final. Esto podría verse algo como esto

  1. Identifique estructuras de datos clave y transfórmelas en definiciones de registros o mapas Clojure inmutables. No tenga miedo de anidar muchos mapas inmutables: son muy eficientes gracias a las estructuras de datos persistentes de Clojure. Vale la pena ver este video para obtener más información.

  2. Desarrolle pequeñas bibliotecas de funciones orientadas a la lógica empresarial pura que operen en estas estructuras inmutables (por ejemplo, "agregar un artículo al carrito de compras"). No necesita hacer todo esto a la vez, ya que es fácil agregar más más adelante, pero ayuda hacer algunos desde el principio para facilitar las pruebas y demostrar que sus estructuras de datos están funcionando ... de cualquier manera en esto. punto que realmente puede comenzar a escribir cosas útiles de forma interactiva en el REPL

  3. Desarrolle por separado rutinas de acceso a datos que puedan conservar estas estructuras hacia / desde la base de datos o la red o el código Java heredado según sea necesario. La razón para mantener esto muy separado es que no desea que la lógica de persistencia esté ligada a sus funciones de "lógica empresarial". Es posible que desee mirar ClojureQL para esto, aunque también es bastante fácil envolver cualquier código de persistencia de Java que desee.

  4. Escriba pruebas unitarias (por ejemplo, con clojure.test ) que cubran todo lo anterior. Esto es especialmente importante en un lenguaje dinámico como Clojure ya que a) no tiene tanta red de seguridad para la verificación de tipos estáticos yb) ayuda a asegurarse de que sus construcciones de nivel inferior estén funcionando bien antes de construir demasiado en encima de ellos

  5. Decida cómo desea usar los tipos de referencia de Clojure (vars, refs, agentes y átomos) para administrar cada estado de nivel de aplicación mutable de parte. Todos funcionan de manera similar, pero tienen diferentes semánticas transaccionales / de concurrencia dependiendo de lo que intente hacer. Las referencias probablemente serán su elección predeterminada: le permiten implementar un comportamiento transaccional STM "normal" al envolver cualquier código en un bloque (dosync ...).

  6. Seleccione el marco web general correcto: Clojure ya tiene bastantes, pero recomiendo encarecidamente Ring: vea este excelente video " One Ring To Bind Them " más Fleet o Enlive o Hiccup, dependiendo de su filosofía de creación de plantillas. Luego, use esto para escribir su capa de presentación (con funciones como "traducir este carrito de compras en un fragmento HTML apropiado")

  7. Finalmente, escriba su aplicación usando las herramientas anteriores. Si ha realizado los pasos anteriores correctamente, entonces esta será la parte fácil porque podrá construir la aplicación completa mediante la composición adecuada de los diversos componentes con muy poco texto repetitivo.

Esta es aproximadamente la secuencia en la que atacaría el problema, ya que representa ampliamente el orden de las dependencias en su código y, por lo tanto, es adecuada para un esfuerzo de desarrollo "de abajo hacia arriba". Aunque, por supuesto, con un buen estilo ágil / iterativo, probablemente se encontrará avanzando desde el principio hacia un producto final demostrable y luego saltando a los pasos anteriores con bastante frecuencia para ampliar la funcionalidad o refactorizar según sea necesario.

ps Si sigue el enfoque anterior, me fascinaría escuchar cuántas líneas de Clojure se necesitan para igualar la funcionalidad de 50,000 líneas de Java

Actualización : desde que esta publicación se escribió originalmente, han surgido un par de herramientas / bibliotecas adicionales que se encuentran en la categoría "debe consultar":

  • Noir : marco web que se basa en Ring.
  • Korma : un DSL muy bueno para acceder a bases de datos SQL.
mikera
fuente
4
Nitpick re: "Decida cuál de los tipos de referencia STM de Clojure desea utilizar para administrar el estado de nivel de aplicación mutable de cada parte": solo hay un tipo de referencia STM. Los otros IRefs no involucran STM. De lo contrario, parece un consejo sólido.
hmmm ... Supongo que cuento referencias, agentes y átomos como parte del sistema Clojure STM / concurrencia. Por ejemplo, todos admiten validadores y los agentes se coordinan con las confirmaciones de transacciones. pero entiendo su punto, las referencias son el modelo transaccional "principal". hará una enmienda rápida.
mikera
2
Si tan solo pudiera darle más +1. Vi los dos videos que mencionaste, y fueron geniales. Gracias.
jdl
1
Ahora noir está en desuso. Supongo que tienes que mencionar la composición en lugar de noir.
hsestupin
¡El enlace de One Ring To Bind Them está roto!
Adam Arold
5

¿Qué aspectos de Java incluye su proyecto actual? Registro, transacciones de base de datos, transacciones declarativas / EJB, capa web (mencionó JSP, servlets), etc. He notado que el ecosistema Clojure tiene varios micro-frameworks y bibliotecas con el objetivo de hacer una tarea y hacerlo bien. Sugeriría evaluar las bibliotecas en función de sus necesidades (y si se ampliarían en proyectos grandes) y tomar una decisión informada. (Descargo de responsabilidad: soy el autor de bitumenframework ) Otra cosa a tener en cuenta es el proceso de compilación: si necesita una configuración compleja (desarrollo, prueba, preparación, producción), es posible que deba dividir el proyecto en módulos y tener el proceso de compilación programado para facilitar.

Shantanu Kumar
fuente
Servlets, JSP, marco de persistencia construido en casa (10 años) y pojos, pero no EJB
appshare.co
4
Los servlets se pueden reemplazar fácilmente con Ring + Compojure en mi humilde opinión, y los JSP se pueden reemplazar con quizás StringTemplate (o plantillas FreeMarker / Velocity). La persistencia en Clojure será diferente de Java. Si necesita mapeo relacional, puede mirar Clj-Record y SQLRat (aún no muy maduro). ClojureQL solo admite MySQL y PostgreSQL en este momento AFAICT. La limitación actual de ccsql para no permitir los guiones bajos en los nombres de las columnas puede resultar una sorpresa. Creo que será útil discutir los aspectos de desarrollo en la lista de Clojure cuando sea necesario. ¡Buena suerte en el proyecto!
Shantanu Kumar
Desde ese proyecto, hice otra aplicación con Clojure y Clojurescript (nemcv.com) y ahora estoy usando Ring, probé ClojureQL, pero cambié a Korma para acceder a la base de datos. Puede ver el último trabajo en github.com/zubairq/coils
appshare.co
4

Encontré que la parte más difícil fue pensar en la base de datos. Realice algunas pruebas para encontrar las herramientas adecuadas que desea utilizar allí.

LenW
fuente
1
Bueno, probé clojureql para el acceso a datos, pero es totalmente diferente del estilo Java de acceso a la base de datos, que se basa en objetos. Solo por interés, ¿qué acceso a la base de datos usó para Java y qué usó con Clojure?
appshare.co
1
Terminamos reconsiderando muchas cosas y optando por mongodb, ya que la persistencia de las estructuras de datos de clojure era muy natural
LenW