Esses últimos meses tenho estudado Clojure, ClojureScript, e me entendendo com o ecosistema de tudo isso. Mas sobre a linguagem fica para outro post. Por hora, vamos a uma frase famosa: A language that doesn’t affect the way you think about programming, is not worth knowing, ou Uma linguagem que não afeta a forma que você pensa sobre programar, não vale a pena aprender. Essa frase, de Alan Perlis, mostra muita coisa do que eu penso antes de aprender uma nova linguagem, e vai explicar muito ao aprender sobre Clojure.
Antes de mais nada, vejamos como as linguagens evoluíram – C++ e Java são linguagens orientadas a objeto. Ruby, Python, e Scala também. Mas vejamos como usar uma lista em Java: abrimos o Java, numa IDE lenta como o Eclipse (que precisa de instalação, etc), importamos a lib…. qual lib mesmo? Bom, entramos num Javadoc, procurarmos a lib…. isso em C++ é pior ainda, já que em Java, pelo menos a IDE completa automaticamente os métodos (e algumas vezes, até os imports) pra nós.
Em Scala e Ruby? Abrimos o console, criamos uma lista, atribuímos a uma variável e digitamos: variable., seguido de alguns tabs e o console completa para a gente. Esse é o poder de um REPL (Read-Eval-Print-Loop, ou console, IRB, etc), e o REPL muda completamente a forma de escrever, explorar, entender e até mesmo de pensar em programação. Precisamos um dado no banco de dados? Entramos no REPL, digitamos User.create!(login: “foobar”), e voilá – temos um objeto criado. Não precisamos criar uma tela de cadastro para criar esse dado, não precisamos abrir o gerenciador do banco, etc.
Isso, com Clojure, é elevado ao limite.
Primeiramente, Clojure leva o REPL tanto em consideração que uma boa parte da documentação é usada para dizer se aquela construção é amigável com o REPL – isso é, se eu rodá-la duas vezes, a segunda definição vai sobrescrever a primeira, vai ser ignorada, ou mesmo lançará um erro. Isso porque é comum rodar várias vezes o mesmo código no REPL e testar cada uma das soluções.
Segundo, que a maioria dos editores tem algum tipo de integração com o REPL. Na verdade, o próprio REPL padrão da linguagem – nREPL – abre uma porta, pra os editores se conectarem… e o core da linguagem tem uma lib para se conectar ao nREPL. Dado isso, a maior parte das bibliotecas tem conexão com o REPL. Programando pra web com ClojureScript? Ele abre um REPL, que roda os códigos direto no navegador. Salva-se um arquivo, e o navegador é atualizado na hora, com os mesmos dados que estávamos editando, exibindo, ou o que quer que seja. Quer testar algo? Escreva o código que quer testar no LightTable, CTRL+ENTER, e o navegador atualiza, e o resultado do que você digitou vem para o LightTable. Mágica.
Claro que Clojure, a linguagem, auxilia nesse processo. Uma linguagem funcional prefere estruturas imutáveis, então não há muita “redefinição” no REPL. Mas o fluxo disso tudo é muito diferente – por exemplo, há plug-ins para o LightTable que rodam os testes e informam a linha de teste que falhou. Há bibliotecas de teste que usam a biblioteca padrão do Clojure, já que ela suporta reporters diferentes. Na verdade, o padrão da biblioteca de teste é informar: “tal assertion falhou. Esperado era tal, obtive tal”, num formato de HashMap, que podemos re-formatar e aplicar um diff, ou adicionar cores, etc.
Como Clojure suporta macros, então tudo fica mais simples ainda – não gosta da sintaxe padrão do clojure.test? Escreva uma macro que modifique-a. Não é difícil:
(defmacro expect [value to|!to matcher match] (let [assertion (if (= matcher 'be) <code>(= ~value ~match)</code>(~matcher value match))] (if (= to|!to 'not-to) <code>(is (not ~assertion))</code>(is ~assertion)))) (testing &quot;Sum is working&quot; (expect (+ 2 2) not-to be 3) (expect (+ 2 1) to be 3)) ;; isso expande para: (testing &quot;Sum is working&quot; (is (not (= (+ 2 2) 3))) (is (= (+ 2 1) 3)))
Poucas linhas de código e adaptamos um pedaço do RSpec para rodar na biblioteca padrão. Isso significa que, se algum dia, a biblioteca padrão começar a rodar as coisas em paralelo, ou adicionar mais funcionalidades, a gente ganha essas funcionalidades de brinde. Ao invés de re-inventar a roda, podemos escrever simplesmente um tradutor – macros – que se aproveitam do que a linguagem tem de melhor.
No LightTable, a idéia ainda é mais profunda: se precisamos saber por que tal teste falha, basta adicionar uma sequencia de “watch variables”, ou seja, escutar mudanças nessas variáveis, e rodar o teste – simples, prático, e sem sair do editor. Ainda com a vantagem que, se estamos rodando em ClojureScript e nosso código falha só em um browser, o LightTable rodará nossa suíte completa de testes usando o javascript daquele browser. De novo, sem sair do editor.
A diferença de produtividade é tão grande que, no Atom (meu editor atual), eu preciso de uma série de plugins para fazer o que eu normalmente faço – um para integrar com o TMux (rodar testes), um para integrar com o spring (porque o Rails demora para carregar), um terminal com o tmux preparado, um terminal com o Rails Console ligado, e o navegador com o devtools preparado. Em Clojure? Escrevi um plugin para integrar o parinfer (auxilia a manter a indentação alinhada com os parênteses, além do mais, é legal ver os parênteses fechando sozinhos), instalei o plugin que refatora códigos clojure (renomeia símbolos e variáveis, roda testes, mostra onde uma função está sendo usada), e… bom, e parou aí. Eu não preciso de um browser (o LightTable é um browser também), não preciso de um console (o LightTable roda códigos do console), não preciso de um tmux (de novo, LightTable), e até mesmo o uso do debugger é limitado (tenho watches e posso rodar pedaços de expressões, além do mais, quase tudo é imutável). Isso tudo numa linguagem que roda sobre a JVM (mas como os testes aproveitam a JVM do REPL ou o JS do browser, não preciso carregar várias vezes). Além disso, tenho a mesma linguagem no navegador e no backend…
Claro que essa é mais uma das coisas que Smalltalk já tinha desde sempre. Mas, diferente de Smalltalk, muitas coisas não mudam – você ainda pode usar vários navegadores, você ainda pode editar seu texto num arquivo de texto, você ainda pode mudar seu editor, e principalmente, usar as ferramentas de análise que todos conhecemos, como cobertura de testes, GIT ou outro controle de versão, ferramentas de revisão de código, servidores web como Jetty, Tomcat, JBoss, etc… basicamente, temos as vantagens de Smalltalk sem a necessidade de ficarmos presos a uma VM totalmente isolada do resto do mundo.
Notavelmente, é uma linguagem que muda a forma de pensar. E sinceramente, é bem difícil de voltar a usar algo sem essa integração tão forte com o código.
1 Comment
Clojure, gentilmente | Maurício Szabo · 2016-04-19 at 20:33
[…] e simplicidade. Se tiver curiosidade sobre a forma diferente de se programar, há o post sobre programação com o LightTable. Por fim, um pouco mais sobre programação funcional, e […]
Comments are closed.