Convenções

Em primeira vista, as convenções podem parecer apenas uma escolha feita por um time de desenvolvimento. Mas ela é muito mais do que isso. É a definição de como algo deve ser feito, porém, criado por uma comunidade que está imerso no código da linguagem, sabendo que se isso não for respeitado, podemos ter grandes problemas no futuro.

Ganhamos algumas coias ao utilizar convenções:

  1. Padronização de código;

  2. Facilidade de membros de fora do projeto, conseguirem entender o que esta acontecendo;

  3. Várias bibliotecas seguem o mesmo padrão, então você tera o entendimento mais rápido e de forma fácil, conseguirá adicionar ao seu código sem mudar a estrategia ou organização.

Vamos a algumas convenções

Tupla {:ok, result} e {:error, reason}

Podemos facilmente entender que uma função não foi executada com sucesso, quando em seu retorno, temos essa estrutura {:error, "Something went wrong"}. Ou que tudo deu certo {:ok, %{...}}. Essa é uma convenção adotada pela comunidade elixir para facilitar a identificação de erros e sucessos, podendo tomar alguma ação com base nisso.

A definição de resposta funciona de duas formas.

  1. Em caso de sucesso retornamos uma tupla de :ok, junto com o result.

{:ok, result} = Authentication.login(email, password)

Podemos facilmente obter o resultado, garantindo que ele esteja funcionando devido ao pattern matching. Caso tenhamos uma resposta diferente de {:ok, result} o pattern matching falhará e saberemos que algo esta errado.

2. Para definir um erro, seguimos na mesma ideia, porém, utilizando o atom de :error e a reason.

{:error, reason} = Authentication.login(email, password)

Isso nos proporciona maior controle e também facilita a leitura do código.

O result e a reason são variáveis que criamos no pattern matching (para entender melhor isso, vá para a seção de Pattern Matching no livro.

Vou listar algumas bibliotecas famosas que utilizam dessa convenção:

Uma das grandes vantagens na utilização da tupla de :ok/:error é a utilização do with onde podemos controlar por meio de pattern matching os resultados esperados. De uma olhada na seção with do livro, para se aprofundar mais.

Um exemplo simples:

def do_something() do
  with {:ok, function_result} <- Module.function(), # tupla :ok
       {:ok, another_result} <-Module.another() do # tupla :ok
    IO.inspect("All good")
  else
    {:error, reason} -> IO.inspect("Something went worg: #{reason}") # tupla :error
  end
end

Função com bang (!)

Pode também ser notado que em alguns casos você pode adicionar um ponto de exclamação (!), chamada comumente de bang. Vimos isso nesse exemplo da lib HTTPoison HTTPoison.get!/2. Por convenção, essa invocação remove a tupla :ok/:error e retorna apenas o valor.

Isso faz com que não tenhamos o poder de saber se algo deu certo por pattern matching. Dependendo o caso, é o melhor a se fazer.

Um exemplo

iex> HTTPoison.get(url)
# {:ok, %HTTPoison.Response{...}}

iex> HTTPoison.get!(url)
# %HTTPoison.Response{...}

Função com interrogação (?)

Quando queremos uma resposta de sim ou não para alguém, fazemos perguntas. Em elixir não é diferente. Quando queremos que o tipo do dado seja booleano (que aceite true ou false) utilizamos em seu nome o ponto de interrogação. Quando você ver isso em alguma função você saberá que retorna-rá um boleano.

File.dir?("./test")
# true

Enum.any?([false, true, false])
# true

Conclusão

Sempre que tiver criando funções, tenha em mente que ela pode falhar, e caso isso aconteça, precisamos saber que isso aconteceu.

Quando uma função segue de um ponto de exclamação !, a convenção nos diz que a resposta dessa função não trará a tupla com :ok ou :error e sim o resultado diretamente. Exemplo

Last updated