Configurando Clojure com Atom

Bom, numa postarem anterior eu mostrei meu workflow com Clojure e Atom. Nesse post, farei um passo a passo bem mais detalhado.

A primeira coisa a se fazer é instalar, no sistema operacional, o Java SDK e o Leiningen. Isso torna possível rodar Clojure e ClojureScript no sistema operacional. Agora, vamos ao Atom.

As novas alterações do meu plug-in clojure plus trazem um suporte preliminar a ClojureScript também, usando o piggieback. Na verdade, qualquer biblioteca é possível, já que o plug-in permite que você defina um comando que abriria um console ClojureScript. Mas mais sobre isso mais tarde.

Atom e Profiles

Dentro do Atom, instale o proto-repl, clojure-plus, lisp-paredit e clojure-language. O primeiro plug-in faz a ponte entre o clojure e o editor, o segundo traz funcionalidades interessantes, o terceiro faz edição estrutural (se você quiser, claro), mas principalmente corrige a indentação de código Clojure quando se digita enter (o Atom tem uma regra genérica que não funciona em LISPs).

Enquanto esses plug-ins instalam, é hora de configurar seu profile. Em Clojure usando Leiningen (ou lein para os íntimos – demora muito digitar o nome completo) há um arquivo de profiles em seu diretório home. Esse arquivo define bibliotecas e plug-ins que sempre ficarão ativos em qualquer circunstância e em qualquer código que se esteja digitando. Desnecessário dizer quão poderoso é isso, certo? Basicamente, bibliotecas ficam disponíveis para todos os projetos, mesmo os que não a usam, em qualquer circunstância. Aqui vale um pequeno desvio:

Em Clojure, há muitas bibliotecas que não servem exatamente para serem usadas no código – basicamente, o uso delas é refatorar código (como o refactor nrepl), debug (como o sayid), autocomplete (como o compliment), etc. O que vamos fazer é adicionar o refactor-nrepl e o proto-repl no projeto. O proto-repl, na verdade, é só o agrupamento do compliment e do clojure.tools.nrepl, então se você quiser pode adicionar essas bibliotecas individualmente (bom caso algum bug numa delas esteja corrigido numa versão mais recente).

O seu arquivo de profiles vai ficar dentro do diretório home, subdiretório .lein, no arquivo profiles.clj. Se nem o arquivo nem o diretório existirem, crie-os. Logo, seu arquivo /home//.lein/profiles.clj ficaria assim:

{:user {:plugins [[refactor-nrepl "2.2.0"]]
        :dependencies [[slamhound "1.3.1"]
                       [proto-repl "0.3.1"]
                       [com.billpiel/sayid "0.0.10"]]}}

As dependências do slamhound e do sayid não tem uso ainda, mas estou pensando em integrá-las num futuro próximo ao clojure-plus, logo é bom mantê-las.

Nesse ponto, seu editor está pronto para ser usado. Você pode instalar também o plug-in parinfer, que infere parênteses a partir da indentação – muito útil, na minha opinião, mas devido a algumas semanticas provavelmente você vai querer usar o parinfer em conjunto com o paredit. Eu uso os dois juntos quando trabalho com Clojure.

Configuração dos plug-ins

Eu não gosto dos plug-ins que definem atalhos para mim, logo eu não defini nenhum atalho para o clojure-plus. O proto-repl, em compensação, define uma centena de atalhos, bem como o lisp-paredit. Eu costumo entrar em “View Installed Packages”, e dentro do proto-repl e do lisp-paredit eu removo os keybindings (de-selecionando o check Enable da área Keybindings de ambos os plugins). Agora, você provavelmente vai querer um atalho para mudar o modo “strict” do paredit, e atalhos para clojure. Então, abra seu arquivo de keymap, e vamos adicionar alguns. Nesse caso, eu vou adicionar keybindings compostos – “ctrl+espaço” vai ser o principal, e podemos usar outra tecla pra fazer o que queremos (ou seja, se você quiser se conectar no REPL, basta apertar “ctrl+espaço” e logo depois digitar “c”):

'atom-workspace atom-text-editor[data-grammar="source clojure"]':
'ctrl-space c': 'proto-repl:remote-nrepl-connection'
'ctrl-space l': 'clojure-plus:evaluate-last-code'
'ctrl-space s': 'lisp-paredit:toggle-strict'
'ctrl-space f': 'clojure-plus:display-full-symbol-name'
'ctrl-space w': 'clojure-plus:add-watch-in-selection'
'ctrl-space q': 'clojure-plus:remove-all-watches'
'ctrl-space r': 'clojure-plus:refresh-namespaces'
'ctrl-space space': 'proto-repl:clear-saved-values'

'enter': 'lisp-paredit:newline'
'alt-left': 'lisp-paredit:barf-forwards'
'alt-right': 'lisp-paredit:slurp-forwards'
'alt-up': 'lisp-paredit:up-sexp'
'alt-down': 'lisp-paredit:down-sexp'

'ctrl-c': 'proto-repl:interrupt'
'shift-enter': 'clojure-plus:evaluate-block'
'ctrl-enter': 'clojure-plus:evaluate-top-block'
'ctrl-shift-enter': 'clojure-plus:evaluate-full-file'
'F12': 'clojure-plus:goto-var-definition'
'ctrl-d': 'proto-repl:print-var-documentation'

Ufa, muita coisa. Vamos por partes. As primeiras partes são para facilitar nossa vida – conectar a um REPL, rodar o último código que estávamos rodando, mudar o paredit para strict ou não (em modo strict, toda vez que abrimos um parênteses ele é fechado imediatamente, e não podemos manualmente remover parenteses). Normalmente você vai usar esse modo, ele é mais seguro. Para adicionar ou remover elementos dentro dos parênteses, usamos o segundo bloco – o primeiro muda o enter para adicionar uma nova linha, mas já calculando a correta indentação. Os dois próximos são para adicionar o próximo elemento à direita do cursor dentro dos parenteses, e para remover o último elemento dos parêntese. Uma imagem vale mais do que muitas palavras:

Paredit modificando texto

Os dois últimos são para navegar para os próximos parenteses dentro desses, ou para fora. De novo, uma imagem vale mais:

Paredit navegando nos arquivos

Por fim, o último bloco server para definir o ctrl-c para parar o que quer que estejamos rodando, ctrl-enter vai rodar o bloco de código inteiro que estamos, shift-enter vai rodar apenas o bloco que estamos dentro, ctrl-shift-enter vai rodar o arquivo inteiro, bloco a bloco, e os dois últimos são auto-explicativos. Embora não pareça, ctrl-d é mais útil do que parece – por definição, todas as funções de Clojure tem uma pequena documentação, mesmo que seja apenas mostrar os parâmetros que ela recebe.

Agora, algumas edições cosméticas (literalmente – mudar a cor de algumas coisas) talvez sejam úteis:

Mudanças de estilo

O plug-in lisp-paredit é educado o suficiente para nos mostrar quando há problemas com os parênteses, mas infelizmente ele é bem invasivo nisso – ele deixa o texto num vermelho berrante absurdo. Para tal, eu mudo na folha de estilos do Atom para deixar apenas um contorno: aperte ctrl-shift-p para abrir a paleta de comandos, e busque por Open your stylesheet. No fim do arquivo, coloque algo como:

atom-text-editor.is-focused[data-grammar="source clojure"]::shadow {
  .lisp-syntax-error .region {
    background-color: rgba(255, 150, 150, 0) !important;
    border: 1px solid rgba(204, 0, 0, 0.8) !important;
    border-radius: 5px;
  }
}

Ou qualquer outro estilo que você queira – é um arquivo less, que basicamente é um CSS com mais poder. Se você, assim como eu, for daltônico, talvez seja difícil de ver na barra de baixo do Atom se o paredit está em format strict ou não, então eu configuei o meu para ficar azul quando estiver no strict:

.lisp-paredit-status.strict.enabled > .strict-status {
  color: #0000FF;
  font-weight: bold;
}

Desenvolvimento

Desenvolver com Clojure, da forma como eu costumo fazer, costuma ser bem diferente do que o normal. Primeiro porque todas as coisas – autocomplete, rodar código, etc – normalmente são feitas pelo REPL. O que fazemos no Atom é que iniciamos um REPL na linha de comando usando lein repl, e depois conectamos ele ao Atom usando Remote Nrepl Connection. Aqui as coisas começam a ficar interessantes:

Idealmente, em cada projeto é bom ter um diretório reservado apenas para pequenos fragmentos de código úteis. Por exemplo, no arquivo project.clj, idealmente teríamos um pedaço assim:

(defproject my-project "0.0.1-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
  :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :profiles {:dev {:source-paths ["dev"]}}) ; ```

Basicamente, a linha em destaque define um novo diretório aonde os códigos-fonte serão avaliados, mas **apenas em desenvolvimento** - isso não fará parte do código final. Isso é muito útil especialmente em casos aonde se desenvolve um código que sobe componentes - por exemplo, um servidor web. O código abaixo, colocado no arquivo `dev/user.clj`, define duas funções - uma que sobre o servidor numa porta de desenvolvimento (3000, nesse caso) e outra que derruba o servidor se ele existir.

```clojure
(ns user
  (:require [my.handler :as handler]
            [ring.adapter.jetty :as jetty]))

(def server (atom nil))

(defn start-system []
  (reset! server (jetty/run-jetty #'handler/app {:port 3000 :join? false})))

(defn stop-system []
  (when-let [s @server]
    (.stop @server)
    (reset! server nil)))

Dessa forma, eu configuro o plug-in clojure-plus para possuir os seguintes comandos:

  • Before Refresh Cmd: (alter-var-root #'clojure.test/*load-tests* (constantly true)) (user/start-system)
  • After Refresh Cmd: (alter-var-root #'clojure.test/*load-tests* (constantly true)) (user/stop-system)

Eu também configuro o plug-in para, ao salvar, tentar fazer o refresh dos namespaces. Dessa forma eu sei que o código que eu estou digitando sempre está correto – mas, ao mesmo tempo, esse tipo de abordagem é mais perigosa. Quando o código não consegue fazer refresh (por qualquer motivo – var não definida, etc) sequer o autocomplete funciona. Logo, no meu workflow, eu digito código, aperto ctrl-enter para rodar o código atual, e se eu não tiver exceptions, me sinto confiante em salvar o arquivo e deixar o refresh me falar se eu cometi algum erro.

Outra coisa importante pra mencionar, e que eu mencionei no meu post anterior – a primeira parte do Before e do After refresh, (alter-var-root #'clojure.test/*load-tests* (constantly true)), servem para evitar rodar testes do Midje. Se for usado com clojure.test, provavelmente os testes em Clojure não serão definidos – então, rodar um (run-tests) ou (run-all-tests) vai simplesmente ignorar todos os testes depois de um refresh. Provavelmente esse não é o comportamento desejado, então é melhor remover essa parte do código (ou fazer algo MUITO clever: detectar se há um Midje antes no projeto, e se houver, desativar o *load-tests*:

(try 
  (require '[midje.sweet :as midje]) 
  (alter-var-root #'clojure.test/*load-tests* (constantly false)) 
  (catch Exception e nil)) 
(user/stop-system)

E colocar isso no Before Refresh Cmd. Basicamente, isso vai resolver os problemas de refresh e deixar o código genérico para usar midje ou clojure.test.

Um pouco do workflow

Resolvi também gravar um vídeo com o meu workflow. Nesse vídeo, eu mostro como estou tentando integrar o Sayid (biblioteca de debug para Clojure) no clojure-plus, e alguns testes automatizados que comecei a fazer. É bem interessante porque mostra uma situação real, inclusive com problemas como “por que essa coisa não funcionou?” (eu achava que estava fazendo corretamente o parsing da função no meu plug-in. Não estava, e foi um bug que eu corrigi no vídeo).

Segue o vídeo, e bom divertimento!

Publicado em Clojure, Vídeo Aulas | Marcado com , , , , , | Deixe um comentário

Minha estadia no Nubank

Ultimamente eu tenho estudado muito de programação funcional, principalmente em Clojure. E nada melhor para estudar uma linguagem do que se aventurar num emprego em que se usa ela, certo? 

Foi assim que eu fiz o processo seletivo no Nubank. E passei, e comecei a trabalhar em maio.

Muitas coisas foram diferentes para mim nessa pequena jornada. A primeira empresa em que o atendimento ao cliente está muito próximo do dia a dia, a primeira empresa com muitos funcionários, a primeira empresa que opera com muito investimento, a primeira empresa que usa intensivamente micro serviços, e a primeira empresa em que eu, de fato, fui demitido (e não que eu pedi demissão). 

Apesar de tudo, eu já tinha meus planos de sair. Mas isso não vem ao caso, nem vem ao caso as circunstâncias que levaram ao acontecido. O importante é o que fica, e as coisas que eu aprendi. 

Pela primeira vez na vida eu trabalhei com microserviços, e pela primeira vez eu consegui ver a vantagem real de uma linguagem funcional nesse processo. Há muito tempo atrás, no mundo de Ruby, uma implementação chamada Maglev prometeu entregar persistência de objetos Ruby completos, inclusive exceptions. O Maglev mesmo nunca foi muito utilizado, mas essa ideia de persistir exceptions e sessions e depois reproduzir o bug simplesmente pegando a session e replicando os passos que causaram o erro ficaram na minha mente. 

Quando eu trabalhei com microserviços, era exatamente isso que eu fazia – cada ponto de entrada em um serviço era um conjunto de dados, e como a maior parte das coisas era imutável, se algo dava erro a mensagem era rejeitada, e depois podíamos simplesmente chamar o mesmo entrypoint com a mesma mensagem, e garantir que a mesma exception ocorreria. Se fosse algum erro de comunicação com banco de dados ou com outro entrypoint, nada de errado ocorreria – e aqui entra a segunda coisa diferente.

Para suportar todas essas características, todos os entrypoints tinham que ser indepotentes – ou seja, se uma mesma mensagem fosse enviada para ele duas, três, ou quatro vezes, o entrypoint se compraria como se tivesse recebido apenas uma. O importante aqui é não depender de um id de mensagem ou qualquer coisa assim – é importante que a mensagem inteira seja responsável por ser indepotente.
Continuar lendo

Publicado em Infra estrutura e SO | Marcado com , , , , , | Deixe um comentário

Quick post – Motorola não carrega

​Um dia desses o celular de minha esposa, um moto G segunda geração, ficou se bateria e desligou. Até aí, tudo normal. 

O problema é que deixamos ele carregando a noite inteira e com o carregador original, e no dia seguinte, um Led branco estava piscando e nada do celular carregar. Detalhe interessante que eu nem sabia da existência desse Led… basicamente, esse é um quick post para recuperar um Android nesse caso. 

O primeiro ponto é que isso é normal em androids da Motorola. Parece um bug que eles não corrigiram até hoje. A solução (tanto para Motorola como qualquer outro celular Android) é entrar no modo fastboot

No caso da Motorola, faz-se isso segurando o botão de ligar junto com o de baixar volume por uns 5 a 10 segundos. Especificamente no meu caso, eu segurava os dois botões por uns 10 segundos depois soltava apenas o botão de ligar (mantendo o baixar volume apertado), e aí ele iniciava o fastboot

Esse modo é bem simples – ele tem meia dúzia de informações sobre o Android, e você pode selecionar as diversas opções usando os botões de volume e confirmar com o botão de ligar o Android. Mas na verdade, para recuperar um Android nessa situação, você vai querer conectar ele na saída USB de um computador – no plug na tomada não funciona.

Feito isso, na tela do fastboot, aparecerá uma informação de battery low, charging. Deixe assim por pelo menos uma hora, e só depois reinicie o celular. 
Continuar lendo

Publicado em Quick Post | Marcado com , , | Deixe um comentário

Empregos, Linguagens, e Identidade

Quando eu comecei esse blog, eu dei o subtítulo de “diário de um rubyista”. Quase imediatamente eu mudei para “diário de um desenvolvedor de sistemas”, e agora estou mudando de novo.

Existe um motivo pra isso, assim como existe um motivo para um monte de coisas que fazemos e que não nos damos conta. Conforme o tempo foi passando, muitas coisas mudaram na minha vida pessoal e profissional, e me fizeram repensar minha própria identidade.

Talvez esse pareça ser um assunto muito filosófico pra um blog técnico, mas de qualquer maneira, acho importante que ele seja mencionado. Eu conheço muita gente que se deixa definir pela linguagem que usa. Há vários blogs online que, por exemplo, se recusam a aceitar críticas da sua linguagem preferida, de seu framework, num nível que parece irracional. Na verdade, Martin Fowler já falou sobre isso num artigo simples chamado keep your identity small. E é sobre isso que eu vou falar.

Muitas coisas aconteceram desde que comecei a escrever nesse blog – a ideia original dele era divulgar coisas interessantes, intermediárias para avançadas, para um público que fala português – e esse último detalhe é importante também. Por que meus subtítulos do blog foram “diário de um rubyista”, quando não era esse o intuito do blog, é algo que eu não sabia dizer – até agora.
Continuar lendo

Publicado em Divagações | Marcado com , , , , | 3 Comentários

Meu workflow em Clojure

Há algum tempo postei sobre LightTable e Clojure, e embora minha opinião sobre essa nova forma de programar não tenha mudado, algumas coisas infelizmente mudaram bastante.

A primeira foi o esquema de plug-ins do LightTable. Ele tem poucos plug-ins úteis, e alguns dos que existem não funcionam com as versões mais novas. A documentação da API do LightTable é inexistente, e eu passei mais tempo lendo o código fonte do editor do que eu gostaria. Então, resolvi experimentar novamente o Atom, com seu novo plug-in proto-repl.

Uma das vantagens (grandes vantagens) do Atom é que ele facilita muito a criação de plug-ins. Embora ele não seja livre de problemas (eu mesmo postei no fórum deles sobre como as APIs mudam sem aviso prévio), ele ainda é melhor que todos os outros editores que eu usei para esse fim. Além do mais, recentemente o Atom ganhou duas bibliotecas interessantes – Ink, que permite fazer o que o LightTable faz (exibir resultados próximo de onde o código que o gerou está) e também ganhou, nativamente, decorações em bloco – uma ou mais linhas inteiras aonde se pode exibir qualquer informação, e o usuário não pode digitar nessas linhas. Isso é muito bom, e abre o caminho para coisas bem interessantes.

Infelizmente, eu ainda não achei uma maneira simples de lidar com ClojureScript, então vamos pensar apenas em Clojure agora. A primeira coisa a fazer é instalar o Parinfer, Ink, proto-repl e o LISP Paredit. Sim, esse último é necessário pelo motivo mais bobo – o Atom não indenta direito códigos Clojure… Além disso, recentemente comecei a trabalhar profissionalmente com Clojure, e por esse motivo, muitas vezes eu pego códigos legados aonde a indentação está completamente errada, e eu não posso alterar um arquivo inteiro se meu intuito é acrescentar uma linha.

A segunda coisa a se fazer é inserir o proto-repl no arquivo de profiles do lein. Isso é importante para não ter que inseri-lo em todos os projetos a serem desenvolvidos.

; dentro do arquivo ~/.lein/profiles.clj
{:user {:plugins [[refactor-nrepl "2.0.0-SNAPSHOT"]] ; Para alguns códigos que vamos usar
        :dependencies [[org.clojure/tools.nrepl "0.2.12"]
                       [proto-repl "0.1.2"]]}}

Como funciona?

O proto repl adiciona a habilidade de rodar códigos clojure no editor. Ele pode abrir um repl para você, ou você pode abrir um e se conectar a ele. Essa segundo opção é bem mais saudável, então normalmente é a que eu uso. Uma vez conectado ao repl, o proto vai tentar fazer o que se chama de refresh do namespace – isso significa que ele vai pré carregar todos os arquivos do seu projeto, identificar dependências, e uma vez que você mude um arquivo ele tentará recarregar esse arquivo, e tudo o que depende dele. Isso significa que, se há algum código que pede que o usuário digite algo, ou algo código que interage com o sistema fora de um defn ou alguma outra estrutura que não rode imediatamente, o código vai rodar nesse processo de refresh.

Extensões ao workflow

Claro que não é só essa a vantagem. Eu, por exemplo, uso o vim plus no atom. Por isso, eu criei dois atalhos – um no modo de comando que expande a seleção da sexp. Outro no modo visual, que também expande a seleção. Isso significa que, ao apertar s s em modo de comando, ele selecionará uma string. Apertando s de novo, selecionará a string e também as aspas. Apertando mais uma vez, selecionará os parêntese aonde essa string está, e assim por diante.

Nesse ponto, tudo está praticamente pronto. Mas, infelizmente, a vida não pode ser correta e bela ao mesmo tempo, já diria Douglas Adams…

Correções…

Bom, o Atom, para variar, tem alguns bugs bem irritantes que não são corrigidos. Primeiramente, quando as coisas acontecem no fim da tela (tipo, perto da parte de baixo do editor), há um flickering ridículo, reportado nesse bug. Enquanto isso, eu uso um hack no meu editor, adicionando nas stylesheets as linhas abaixo. Além disso, o Lisp Paredit, quando não faz “match” dos parenteses, deixa uma cor vermelho-berrante, então eu também estilizo de forma diferente:

// O flicker ainda existe, mas é mais suave.
.autocomplete-plus {
  transition: top ease 0.4s, left ease 0.4s;
}

atom-text-editor::shadow .lisp-syntax-error .region {
  background-color: rgba(204, 0, 0, 0) !important;
  border: 1px solid rgba(204, 0, 0, 0.8) !important;
}

No meu caso, eu tenho muitos projetos que usam o midje. Isso significa que cada refresh do código vai rodar testes, e o refresh deveria ser algo bem rápido. Eu tentei resolver isso com “injections” no meu profiles.clj – o proto-repl prefere chamar uma função user/reset, e se isso falhar, chama o clojure.tools.namespace.repl/refresh, mas isso não funcionou muito bem… por isso, desabilitei o refresh do proto-repl, e adicionei uma função de refresh no meu plug-in (ainda não publicado) Clojure Plus.

Outras extensões

Eu tive que mexer também na forma como se trabalha com ambientes docker. No proto-repl, os caminhos dos arquivos são absolutos. Acabei fazendo um monkey patch para poder remover a parte absoluta e deixar tudo relativo, e logo depois migrei para meu pacote (abaixo). O que eu fiz foi, após conectar ou desconectar do proto-repl, ele abre uma API para subscription. Minhas alterações estão no meu GitHub.

Além disso tudo, estou trabalhando num plug-in para adicionar certas funcionalidades do Cursive no Atom, no meu repositório Clojure Plus. Poucas delas são uma busca de códigos que dependem de determinado símbolo, adicionar require de namespaces automaticamente, e basicamente fazer o que o refactor nrepl faz com o emacs no Atom. Outra funcionalidade que estou estudando adicionar são as watch expressions do LightTable no Atom, e também numa forma de gerar autocomplete em ClojureScript, ou pelo menos adicionar a possibilidade de subir dois repls diferentes – um para Clojure é um para ClojureScript (ou mesmo dois para Clojure, fazendo algo semelhante às connections do LightTable). Essa parte provavelmente é fácil – basta fazer um cache de todas as conexões que já foram feitas, e remover as que não existem mais. Como isso será feito ainda segue um exercício.

O ideal é fazer o que se faz há anos com Smalltalk – um ambiente rodando o aplicativo que se reflete no editor. Uma coisa possível, e que hoje o Atom não faz, é sintax highlight de forma semântica. Por exemplo, todas as vars são de uma determinada cor, todos os defs de outra, etc. Porém, isso para mim não é suficiente – o ideal seria ter isso de forma customizada. Com o esquema de subscription do Atom, seria fácil fazer uma ferramenta que, uma vez que o Atom começa o highlight de um arquivo Clojure, ele repassa para um plug-in externo o símbolo e o que ele significa naquele contexto. Digamos que um plug-in quer fazer sintaxe semântica – todos os símbolos de um mesmo let tem a mesma cor. Ele iria fazer um subscribe, e receberia a AST com um repl conectado, e a posição que está sendo feito o highlight, e a partir dali é decidir o que fazer. Outras possibilidades são mostrar automaticamente quando um método vem de um schema (tipo o Prismatic Schema) e o schema não vai bater, ou quando um método não aceita aquele tipo de parâmetro (no caso de um defmulti, por exemplo, ou de um protocol), ou mesmo – e é aqui que as coisas podem realmente ficar interessantes – uma forma de eval inteligente – ele define que aquele bloco que se quer rodar está dentro de um bloco específico, vê os símbolos que deveriam existir naquele escopo, e então pede, num pop-up, os parâmetros que faltam.

Conectando num ambiente, as possibilidades são infinitas. Provavelmente vou escrever bastante sobre isso nos próximos posts. Por hora, um pequeno vídeo sobre essas novidades (em inglês, com legendas):

Bom divertimento.

Publicado em Clojure | Marcado com , , , , , | Deixe um comentário

Clojure, gentilmente

Nos últimos posts eu percebi que me empolguei um pouco no assunto Clojure. Então, esse é um post para tentar começar com a linguagem, ao invés de tentar entender detalhes. Vou atualizar os outros posts para indicar que esse é o primeiro da série, apesar de estar por último…

Clojure é uma linguagem baseada em LISP. Isso, pra muita gente, significa parênteses intermináveis e sintaxe horripilante. Mas não é bem assim.

Os parênteses são um desafio, um degrau. Então ignore-os por enquanto. Use um editor com suporte ao parinfer – Atom ou LightTable. Acho que o vim também. Isso vai tratar de manter os parênteses em sincronia, baseado na indentação, e também de forçar você a entender a indentação de Clojure. A partir daí, é entender por que esses parênteses existem. Então vamos lá:

Em LISPs, ou seja, em Clojure, parênteses nunca são opcionais. Nunca. Então nem tente resolver seu código com “vou tentar colocar um parênteses aqui” porque não vai funcionar. Você sempre abre um parênteses quando você vai chamar uma função ou special form, ou macro. A soma, multiplicação, divisão e subtração (+ * / e -, respectivamente) são funções. Concatenação de strings (str) também, bem como map, reduce, split e join. Já o if não é uma função – é uma special form, bem como fn* (retorna uma nova função) e def (define novas variáveis, que os LISPs gostam se chamar de símbolos). E o or, o and, e o defn são macros. Para poder usar todos eles, sem exceção, você tem que abrir um parêntese.

Primeiros passos

Para somar 4 números, abrimos um parêntese e o primeiro elemento é a função da soma. Ou seja:

(+ 5 3 9 7)

Isso vai somar os quatro números. Normalmente deixamos grudado ao parêntese a função que vamos rodar.
Continuar lendo

Publicado em Clojure | Marcado com , | 1 Comentário

Clojure e simplicidade

AVISO – me empolguei um pouco nessa postagem, para uma introdução mais gentil, verifique o post após esse.

Qualquer linguagem baseada em LISP, como Clojure, tem o mesmo problema: as pessoas falam de como a linguagem é fantástica, como ela revoluciona como você programa, até o momento em que você resolve entender por que. Aí você estuda a linguagem, aprende uma ou outra coisa, e não entende porque as pessoas falam tão bem dela.

Esse ciclo se repete várias vezes, e várias vezes, e você nunca entende o motivo das pessoas falarem tão bem. Até um dia em que você finalmente entende – e é aí que você vira uma dessas pessoas que falam bem, mas ninguém mais entende por que.

Clojure é, basicamente, um LISP que roda sobre a JVM. Porém, diferente de common LISP, Clojure possui duck typing – LISP não. É essa foi a primeira realização – tipagem dinâmica não implica em duck typing.

Ruby, JS, e Clojure possuem métodos (ou keywords, ou funções) que rodam sobre qualquer tipo que atenda aquele protocolo. for element in array, por exemplo, roda em Ruby e JS da mesma maneira para Arrays, ou para Objects (em JS) ou Hash, Set, para Ruby. Em Ruby, é porque todos implementam o método .to_a. Já em Clojure, o nth serve para pegar um elemento de uma coleção qualquer, seja ela uma List ou Vector, usando (nth ["some" "elements"] 1). E como é isso em Common LISP? Bom, se for uma List, usa-se: (nth 1 '("some" "elements")). Se for um Vector, com (aref (vector "some" "elements") 1). E assim por diante (o que quer que isso signifique nessa situação, já que nem posicionamento dos parâmetros nem nome das funções é consistente).

A segunda coisa interessante de Clojure é a sua “sintaxe”, ou na verdade, ausência de sintaxe. Na prática, a sintaxe não existe – você programa definido diretamente as S-Expressions, como se fosse uma lista de comandos. Por exemplo:

; uma definição de uma função
(defn sum-ages [people]
  (reduce + (map :age people)))

; uma definição de uma lista
`(defn sum-ages [people]
   (reduce + (map :age people)))

A segunda expressão, apenas pela presença de um “quote”, torna-se uma lista. O primeiro e segundo elementos são Symbol, o terceiro elemento é um Vector que contém outro Symbol, e o quarto elemento é outra List: (reduce + (map :age people)), e assim as coisas continuam. Symbols, em Clojure, serão convertidos em sintaxe mais cedo ou mais tarde, então defn será clojure.core/defn, e chamará a função, símbolo, ou special-form desse nome mais cedo ou mais tarde. E isso é uma coisa fantástica pelos motivos que veremos a seguir. Mas o primeiro deles é bem óbvio: você não tem códigos – apenas dados. E como a linguagem é composta de dados, podemos manipulá-la, moldá-la, e alterá-la com macros. Além disso, Clojure é uma linguagem muito simples – ao contrário por exemplo, de Ruby, aonde a linguagem é complexa, mas programar nela é simples, em Clojure a linguagem é simples, mas programar nela é um pouco mais complicado.

E o motivo, por mais absurdo que pareça, é que nós, programadores, aprendemos a programar de forma errada
Continuar lendo

Publicado em Clojure | Marcado com , , , , | 1 Comentário