Java para reescrever Clojure

97

Minha empresa me pediu para reescrever um aplicativo Java maior (50.000 linhas de código) (um aplicativo da web usando JSP e servlets) em Clojure. Alguém mais tem dicas sobre o que devo tomar cuidado?

Lembre-se de que conheço Java E Clojure muito bem.

Atualizar

Eu fiz a reescrita e ele entrou em produção. É bem estranho, pois a reescrita acabou indo tão rápido que foi feita em cerca de 6 semanas. Como muitas funcionalidades não eram necessárias, ele acabou ficando parecido com 3000 linhas de Clojure.

Ouvi dizer que eles estão satisfeitos com o sistema e ele está fazendo exatamente o que eles queriam. A única desvantagem é que o cara que mantinha o sistema teve que aprender Clojure do zero, e foi arrastado para ele chutando e gritando. Eu recebi um telefonema dele outro dia dizendo que agora ele ama Lisp .. engraçado :)

Além disso, devo fazer uma boa menção a Vaadin. Usar Vaadin provavelmente foi responsável por tanto tempo economizado e falta de código quanto Clojure. Vaadin ainda é o melhor framework da web que já usei, embora agora esteja aprendendo ClojureScript com raiva! (Observe que Vaadin e ClojureScript usam estruturas de GUI do Google por baixo do capô.)

appshare.co
fonte
55
Eu quero trabalhar para sua empresa.
mtyaka,
4
Bem, algumas empresas de defesa na Europa começaram a usar Clojure (ouvi dizer). Mas não me lembro de nenhum nome :)
appshare.co
1
@Zubair: 50 000 Java LOC não chega nem perto de "largish". Este é um projeto muito pequeno. Eu tenho um projeto Java de 250KLOC a 300KLOC aqui e é de tamanho médio ... Na melhor das hipóteses.
SyntaxT3rr0r
5
Na verdade, talvez eu tenha cometido um erro ao mencionar o tamanho da base de código para ser justo, uma redução no tamanho do código não é o objetivo da reescrita. O objetivo é duplo: 1) ter a base de código mais compreensível e, portanto, mais barato manter o código 2) Permitir que os usuários da ferramenta estendam o produto usando um editor Clojure no navegador da web (usando eval e outros recursos Clojure dinâmicos que são mais caros para fazer em Java)
appshare.co
1
Ei ... acabei de ver essa pergunta mais antiga e queria saber como está indo a reescrita?
novembro

Respostas:

82

O maior "problema de tradução" provavelmente será passar de uma metodologia Java / OOP para um paradigma de programação Clojure / funcional.

Em particular, em vez de ter um estado mutável dentro dos objetos, o "caminho Clojure" é separar claramente o estado mutável e desenvolver funções puras (sem efeitos colaterais). Você provavelmente já sabe de tudo isso :-)

De qualquer forma, essa filosofia tende a levar a um estilo de desenvolvimento "de baixo para cima", no qual você concentra os esforços iniciais na construção do conjunto certo de ferramentas para resolver seu problema e, finalmente, conecta-as no final. Isso pode ser parecido com isto

  1. Identifique as principais estruturas de dados e transforme-as em mapas Clojure imutáveis ​​ou definições de registro. Não tenha medo de aninhar muitos mapas imutáveis ​​- eles são muito eficientes graças às estruturas de dados persistentes do Clojure. Vale a pena assistir este vídeo para saber mais.

  2. Desenvolva pequenas bibliotecas de funções puras orientadas para a lógica de negócios que operam nessas estruturas imutáveis ​​(por exemplo, "adicionar um item ao carrinho de compras"). Você não precisa fazer tudo isso de uma vez, pois é fácil adicionar mais depois, mas ajuda fazer alguns no início para facilitar o teste e provar que suas estruturas de dados estão funcionando ... de qualquer maneira neste ponto você pode realmente começar a escrever coisas úteis interativamente no REPL

  3. Desenvolva separadamente rotinas de acesso a dados que podem persistir essas estruturas de / para o banco de dados ou rede ou código Java legado conforme necessário. O motivo para manter isso muito separado é que você não deseja que a lógica de persistência esteja vinculada às funções de "lógica de negócios". Você pode querer dar uma olhada no ClojureQL para isso, embora também seja muito fácil empacotar qualquer código de persistência Java de sua preferência .

  4. Escreva testes de unidade (por exemplo, com clojure.test ) que cobrem todos os itens acima. Isso é especialmente importante em uma linguagem dinâmica como Clojure, uma vez que a) você não tem uma rede de segurança contra a verificação de tipo estático eb) ajuda a ter certeza de que suas construções de nível inferior estão funcionando bem antes de você construir muito topo deles

  5. Decida como você deseja usar os tipos de referência do Clojure (vars, refs, agentes e átomos) para gerenciar cada estado mutável no nível do aplicativo. Todos eles funcionam de maneira semelhante, mas têm semânticas transacionais / simultâneas diferentes, dependendo do que você está tentando fazer. Refs provavelmente serão sua escolha padrão - eles permitem que você implemente um comportamento transacional STM "normal" envolvendo qualquer código em um bloco (dosync ...).

  6. Selecione o framework web correto - Clojure já tem alguns, mas eu recomendo fortemente o Ring - veja este excelente vídeo " One Ring To Bind Them " mais Fleet ou Enlive ou Hiccup dependendo de sua filosofia de modelagem. Em seguida, use isso para escrever sua camada de apresentação (com funções como "traduzir este carrinho de compras em um fragmento de HTML apropriado")

  7. Finalmente, escreva seu aplicativo usando as ferramentas acima. Se você executou as etapas acima corretamente, então essa será realmente a parte mais fácil, porque você será capaz de construir o aplicativo inteiro pela composição apropriada dos vários componentes com muito pouco texto padronizado.

Esta é aproximadamente a sequência em que eu atacaria o problema, pois ela representa amplamente a ordem das dependências em seu código e, portanto, é adequada para um esforço de desenvolvimento "ascendente". Embora, é claro, em um bom estilo ágil / iterativo, você provavelmente se encontrará avançando cedo para um produto final demonstrável e, em seguida, voltando para as etapas anteriores com bastante frequência para estender a funcionalidade ou refatorar conforme necessário.

ps Se você seguir a abordagem acima, ficaria fascinado em saber quantas linhas de Clojure são necessárias para corresponder à funcionalidade de 50.000 linhas de Java

Atualização : desde que este post foi escrito originalmente, algumas ferramentas / bibliotecas extras surgiram na categoria "deve verificar":

  • Noir - estrutura da web que se baseia no Ring.
  • Korma - um DSL muito bom para acessar bancos de dados SQL.
Mikera
fonte
4
Nitpick re: "Decida qual dos tipos de referência STM do Clojure você deseja usar para gerenciar cada estado mutável no nível do aplicativo": Há apenas um tipo de referência STM. Os outros IRefs não envolvem STM. Caso contrário, parece um conselho sólido.
hmmm ... Acho que conto os refs, os agentes e os átomos como todos fazendo parte do sistema Clojure STM / simultaneidade. Por exemplo, todos eles suportam validadores e os agentes são coordenados com confirmações de transações. mas entendi, os refs são o modelo transacional "primário". fará uma alteração rápida.
Mikera,
2
Se eu pudesse dar a isso mais + 1s. Eu assisti os dois vídeos que você referenciou e eles foram ótimos. Obrigado.
jdl
1
Agora o noir está obsoleto. Suponho que você deva mencionar sobre compojure em vez de noir.
hsestupin
O link de um anel para vinculá-los está quebrado!
Adam Arold
5

Quais aspectos de Java seu projeto atual inclui? Log, transações de banco de dados, transações declarativas / EJB, camada da web (você mencionou JSP, servlets) etc. Observei que o ecossistema Clojure tem vários microestruturas e bibliotecas com o objetivo de fazer uma tarefa, e bem fazê-la. Eu sugeriria avaliar as bibliotecas com base em sua necessidade (e se seria escalável em grandes projetos) e tomar uma decisão informada. (Isenção de responsabilidade: eu sou o autor de bitumenframework ) Outra coisa a observar é o processo de construção - se você precisa de uma configuração complexa (desenvolvimento, teste, preparação, produção), pode ser necessário dividir o projeto em módulos e ter o processo de construção em script facilidade.

Shantanu Kumar
fonte
Servlets, JSP, framework de persistência caseiro (10 anos) e pojos, mas não EJB
appshare.co
4
Servlets podem ser facilmente substituídos por Ring + Compojure IMHO, e JSPs podem ser substituídos por StringTemplate (ou modelos FreeMarker / Velocity). Persistência em Clojure será diferente de Java. Se precisar de mapeamento relacional, você pode olhar para Clj-Record e SQLRat (ainda não muito desenvolvido). ClojureQL suporta apenas MySQL e PostgreSQL no momento AFAICT. A limitação atual do ccsql para não permitir sublinhados nos nomes das colunas pode ser uma surpresa. Acho que discutir os aspectos de desenvolvimento na lista Clojure como e quando necessário será útil. Boa sorte no projeto!
Shantanu Kumar,
Desde aquele projeto eu fiz outro aplicativo com Clojure e Clojurescript (nemcv.com) e estou usando o Ring agora, tentei ClojureQL, mas mudando para Korma para acesso ao banco de dados. Você pode ver o trabalho mais recente em github.com/zubairq/coils
appshare.co
4

Achei que a parte mais difícil foi pensar no banco de dados. Faça alguns testes para encontrar as ferramentas certas que deseja usar lá.

LenW
fonte
1
Bem, eu tentei clojureql para acesso a dados, mas é totalmente diferente do estilo Java de acesso a banco de dados, que é todo baseado em objeto. Só por curiosidade, qual acesso de banco de dados você usou para Java e o que você usou com Clojure?
appshare.co
1
Acabamos repensando muitas coisas e optando pelo mongodb, pois a persistência das estruturas de dados clojure era muito natural
LenW