Deixe Seu Código Mais Legível Usando Threading Macros
Clojure fornece várias maneiras de criar um pipeline
de funções, dentro de um let
, por exemplo, você pode fazer várias transformações sobre uma coleção. O problema é que muitas vezes esse pipeline
pode causar confusão durante a leitura do código, especialmente para aqueles que não possuem experiência com linguagens funcionais. É possível deixá-lo mais legível usando as threading macros.
Considere o exemplo abaixo que cria alguns livros (representando-os como Map
):
Com essa coleção de livros em mãos, agora é necessário somar o valor apenas dos livros referentes a linguagem Ruby:
Um desenvolvedor familiarizado com programação funcional, mais especificamente com Lisp, não terá dificuldades para entender o que se passa no código acima:
- A partir de uma sequência de livros
- Filtre todos cuja linguagem é Ruby
- Obtenha o preço de cada um deles
- Some o valor de todos eles
Lembre-se que códigos Lisp são lidos mais facilmente de dentro para fora, um pouco diferente do que estamos acostumados a ver em outras linguagens.
Clojure possui duas macros que ajudam na criação de códigos mais legíveis, na prática facilitam a leitura do pipeline
, de um modo que podemos lê-lo de maneira sequencial. O código acima pode ser melhorado com o uso da macro thread last ->>
:
A macro thread last ->>
pega o elemento passado no primeiro form
e passa-o como último argumento do form
seguinte. No código acima, isso significa passar seq books
como último argumento para filter #(= (:language %) "Ruby")
. O resultado do filter
então é passado como último argumento do map :price
, e assim por diante.
Esse comportamente pode ser visto utilizando a macro macroexpand-all
, que é capaz de retornar o resultado da chamada a macro thread last:
O código é quase idêntico a versão sem thread last, exceto pela função anônima que declaramos usando um alias
.
Existe outra macro que funciona de maneira bem semelhante e nos ajuda e muito a criar pipelines
mais legíveis.
Vamos supor que em algum momento seja necessário adicionar mais informações dentro do Map
que representa cada um dos livros, por exemplo, informações sobre o autor:
Se quisermos apenas o email do autor, normalmente faríamos (:email (:author ruby-a-linguagem-mais-divertida))
. Com muitos Map
aninhados o código pode se tornar novamente não muito legível.
A macro thread first ->
, que passa um determinado form
como segundo argumento ao invés do primeiro ao próximo form
, pode deixar nosso último pipeline
mais agradável.
Executar (-> ruby-a-linguagem-mais-divertida :author :email)
é o mesmo que passar o form ruby-a-linguagem-mais-divertida
como segundo argumento do form :author
, ou seja, (:author ruby-a-linguagem-mais-divertida)
. Por fim, passar o resultado do último form como segundo argumento do form :email
, ou seja, (:email {:email "lucasas@gmail.com", :name "Lucas Souza"})
Usando a macro macroexpand-all
é possível checar que o que ocorre é exatamente o que foi descrito acima:
Em resumo, comprovamos que é possível deixar códigos com pipeline
mais legíveis usando thread first e thread last.
No próximo post vou mostrar que a combinação entre ambas pode ser mais útil ainda.
Comentários: