Elixir + Phoenix, programando na velocidade da luz
Jul 17 (pt)Hoje resolvi trazer alguns "pontos chave" sobre como podemos ser mais produtivos programando com Elixir e Phoenix, este post pode ser tanto para quem já tem alguma experiência com a linguagem quanto para quem está iniciando. Talvez você já conheça algumas dessas dicas, outras talvez descubra agora, mas o principal é compartilhar e aprender. vamos lá:
1. Entenda todos os detalhes de pattern matching, guards, keyword lists e structs.
Conhecendo-os temos um grande ganho em produtividade. Diria que 60% do código que lemos e escrevemos com a linguagem envolvem essas estruturas, vale a pena dedicar bastante tempo as explorando e estudando, dessa forma ganhamos muito mais "fluidez" no desenvolvimento das demandas do dia a dia.
Veja alguns exemplos de detalhes que podem nos pegar de surpresa em determinado momento do nosso desenvolvimento:
Veja alguns exemplos de detalhes que podem nos pegar de surpresa em determinado momento do nosso desenvolvimento:
1.1 Pattern matching com structs funcionam dessa forma:
iex(1)> %x{} = %MinhaStruct{}
%MinhaStruct{hello: nil}
iex(2)> x
MinhaStruct
Porém, não conseguimos criar structs através de variáveis:
iex(12)> x = MinhaStruct
MinhaStruct
iex(13)> %x{}
** (CompileError) iex:13: expected struct name to be a compile time atom or alias, got: x
Caso isso seja necessário, devemos utilizar a função struct:
iex(13)> defmodule User do
...(13)> defstruct name: "john"
...(13)> end
iex(14)> x = User
iex(15)> struct(x)
%User{name: "john"}
1.2 Na definição de guards, não podemos utilizar funções definidas no módulo:
iex(4)> defmodule Teste do
...(4)> def maiorquequatro(x), do: x > 4
...(4)> def verifica(numero) when maiorquequatro(numero), do: IO.puts("é maior que quatro")
...(4)> def verifica(_numero), do: IO.puts("não é maior que quatro")
...(4)> end
** (CompileError) iex:6: cannot find or invoke local maiorquequatro/1 inside guard. Only macros can be invoked in a guard and they must be defined before their invocation. Called as: maiorquequatro(numero)
Para utilizar funções customizadas em guards, utilizamos macros:
iex(9)> defmodule Teste do
...(9)> defmacro maiorquequatro(numero) do
...(9)> quote do: unquote(numero) > 4
...(9)> end
...(9)> def verifica(numero) when maiorquequatro(numero), do: IO.puts("é maior que quatro")
...(9)> def verifica(_numero), do: IO.puts("não é maior que quatro")
...(9)> end
iex(10)> Teste.verifica(2)
não é maior que quatro
:ok
iex(11)> Teste.verifica(5)
é maior que quatro
:ok
1.3 Pattern matching em keyword lists funcionam dessa forma:
iex(4)> [{:name, nome} | _] = [name: "henrique", id: 3]
[name: "henrique", id: 3]
iex(5)> nome
"henrique"
Lembrando que keyword lists são um syntax sugar para uma lista de tuplas...
iex(7)> [{:name, nome}, {:id, 3}] == [name: "henrique", id: 3]
true
Se quisessemos extrair somente o nome, por exemplo, não poderiamos fazer dessa maneira:
iex(6)> [{:name, nome}] = [name: "henrique", id: 3]
** (MatchError) no match of right hand side value: [name: "henrique", id: 3]
Aqui vão links de estudo para se aprofundar bastante sobre esses temas:
https://hexdocs.pm/elixir/Kernel.html#defstruct/1
https://hexdocs.pm/elixir/Kernel.html#struct/2
https://www.poeticoding.com/the-beauty-of-pattern-matching-in-elixir/
https://joyofelixir.com/6-pattern-matching
https://elixir-lang.org/getting-started/pattern-matching.html
https://elixir-lang.org/getting-started/keywords-and-maps.html
2. Escreva um alias (autocomplete) na sua IDE para o require IEx; IEx.pry por favor.
Passamos bastante tempo "debugando" código nas aplicações, em qualquer linguagem. Felizmente o Elixir conta com ferramentas muito boas para nos auxiliar. Uma das mais usadas requer o módulo IEx:
require IEx
Dessa forma podemos criar um breakpoint que irá abrir um terminal quando o código passar por essa linha:
def hello(), do: IEx.pry
Porém, é comum esquecermos o require IEx no início do arquivo, logo passamos a escrever:
require IEx; IEx.pry
Acredite em mim, com o tempo você vai ficar cansado de escrever require IEx; IEx.pry toda hora! Na minha IDE tenho um alias que funciona da seguinte maneira, quando escrevo "pry" e salvo o arquivo ou dou um espaço ela automaticamente completa com o resto.
Se a sua IDE de preferência for o VIM (assim como a minha), adicione esse trecho de configuração no seu ~/.vimrc:
Se a sua IDE de preferência for o VIM (assim como a minha), adicione esse trecho de configuração no seu ~/.vimrc:
abbr pry require IEx; IEx.pry
Faça isso e seja feliz!
3. Rode testes com iex -S mix test --trace para não dar timeout na sessão do IEx
Quando vamos debugar algum ponto do código por um tempo mais longo (utilizando o require IEx; IEx.pry com os testes), o ideal é usar o comando acima ou alterar o tempo limite da sessão, caso contrário sua sessão encerrará em 60 segundos.
** (ExUnit.TimeoutError) test timed out after 60000ms. You can change the timeout:
Inclusive, também seria interessante criar um alias para esse comando, no seu terminal (~/.bashrc)
alias mixtest="iex -S mix test --trace"
4. Domine a biblioteca Plug
A biblioteca Plug é uma das principais "portas de entrada" para o Elixir na web, inclusive, o framework Phoenix foi construído baseado nela. Ter domínio e confiança em sua utilização nos trás mais segurança e assertividade nas decisões tomadas em projetos Phoenix.
links para estudo:
https://ieftimov.com/post/a-deeper-dive-in-elixir-plug/
https://elixirschool.com/pt/lessons/specifics/plug/
https://hexdocs.pm/plug/readme.html
5. Conheça essas dicas do IEx:
5.1 É possível escrever um arquivo de ajuda para iniciar automaticamente variáveis e tudo o que queremos quando abrirmos o terminal do IEx em um projeto. Basta criar um arquivo chamado .iex.exs na raiz do projeto, exemplo:
# Importe funções e módulos
import_if_available(MinhaApp.MeuModulo)
# De print em algo antes do terminal iniciar
IO.puts("hello world")
# Faça o bind de variáveis que ficarão disponíveis no terminal
value = 13
5.2 Existem diversas funções disponíveis no IEx que podem nos deixar mais produtivos, veja alguma delas:
• b/1 - prints callbacks info and docs for a given module
• c/1 - compiles a file into the current directory
• c/2 - compiles a file to the given path
• cd/1 - changes the current directory
• clear/0 - clears the screen
• exports/1 - shows all exports (functions + macros) in a module
• flush/0 - flushes all messages sent to the shell
• h/0 - prints this help message
• h/1 - prints help for the given module, function or macro
• i/0 - prints information about the last value
• i/1 - prints information about the given term
• ls/0 - lists the contents of the current directory
• ls/1 - lists the contents of the specified directory
• open/1 - opens the source for the given module or function in
your editor
• pid/1 - creates a PID from a string
• pid/3 - creates a PID with the 3 integer arguments passed
• ref/1 - creates a Reference from a string
• ref/4 - creates a Reference with the 4 integer arguments
passed
• pwd/0 - prints the current working directory
• r/1 - recompiles the given module's source file
• recompile/0 - recompiles the current project
• runtime_info/0 - prints runtime info (versions, memory usage, stats)
• v/0 - retrieves the last value from the history
• v/1 - retrieves the nth value from the history
5.3 Tab completa o nome de módulos, funções e também mostra os métodos quando finalizamos um nome com ".":
iex(9)> Enum.
EmptyError OutOfBoundsError all?/1
all?/2 any?/1 any?/2
...
Os exemplos foram retirados da documentação do IEx: https://hexdocs.pm/iex/IEx.html#module-the-iex-exs-file
6. Conheça e utilize os diversos plugins para Elixir e Phoenix na sua IDE
Não se limite ao básico! Os plugins existem para serem utilizados, abuse deles!
Se você é usuário do VSCode, este artigo tem dicas muito boas: https://thinkingelixir.com/elixir-in-vs-code/
Para o VIM, de uma lida aqui: https://medium.com/@siever/setup-vim-for-elixir-development-280a01150152
Para o Atom: https://atom.io/packages/atom-elixir
7. Seguindo as dicas acima e utilizando a biblioteca phoenix_up, chegaremos a "299.792.458 features" por segundo!:
phoenix_upadiciona mais generators para desenvolver projetos Phoenix, basicamente, com essa biblioteca não teremos mais o trabalho de escrever arquivo por arquivo e estruturas repetitivas como: "BlaController, BlaView, templates/bla, BlaControllerTest" e etc.. Nos meus projetos, eu sempre uso!
Concluindo..
Apesar de algumas dicas serem mais "práticas", podemos perceber que outras são pontos onde vale a pena reforçar o estudo! Particularmente, hoje me sinto bastante confortável e produtivo com Elixir e Phoenix, e isso foi graças a esse equilíbrio de buscar ferramentas que me auxiliassem e estudar a fundo pontos fundamentais!
Ei, o que achou desse artigo?
Compartilhe e dê sua opinião clicando em uma das redes abaixo:
Muito obrigado!