Arquitetura líquida. É como o jazz - você improvisa, você trabalha junto, você se inspira nos outros, você cria alguma coisa, eles criam alguma coisa.
—Frank Gehry
Estilo é importante. Elixir tem muito estilo, mas como todas as linguagens, ele pode ser estragado. Não estrague o estilo.
Este é o guia de estilo da comunidade para a Linguagem de Programação Elixir. Sinta-se à vontade para enviar pull requests e sugestões, e seja parte da vibrante comunidade do Elixir.
Se você está procurando outros projetos para contribuir, por gentileza confira o site do gerenciador de pacotes Hex.
Traduções deste guia estão disponíveis nas seguintes línguas:
-
Use dois espaços por nível de recuo. Não use hard tabs. [link]
# não recomendado - quatro espaços def alguma_funcao do fazer_algo end # recomendado def alguma_funcao do fazer_algo end
-
Use quebra de linha estilo Unix (*Usuários de BSD/Solaris/Linux/OSX por padrão estão cobertos, usuários Windows tem que tomar muito cuidado). [link]
-
Se você está usando Git talvez você queira adicionar a seguinte configuração para evitar quebras de linha Windows adicionadas acidentalmente: [link]
git config --global core.autocrlf true
-
Use espaço ao redor de operadores, depois de vírgulas, dois pontos e ponto e vírgulas. Não coloque espaço ao redor de pares correspondentes como parênteses, colchetes e chaves. Espaço pode ser (na maioria das vezes) irrelevante no runtime do Elixir, mas seu uso apropriado é essencial para se escrever código leǵivel. [link]
soma = 1 + 2 {a, b} = {2, 3} [primeiro | resto] = [1, 2, 3] Enum.map(["um", <<"dois">>, "três"], fn num -> IO.puts num end)
-
Não use espaço depois de operadores que não são palavras e recebem um argumento; ou ao redor do operador range. [link]
0 - 1 == -1 ^pinned = alguma_funcao() 5 in 1..10
-
Use linhas em branco entre
def
s para quebrar uma função em seus parágrafos lógicos. [link]def alguma_funcao(algum_dado) do dado_alterado = Module.function(algum_dado) end def alguma_funcao do resultado end def alguma_outra_funcao do outro_resultado end def uma_funcao_mais_longa do um dois três quatro end
-
...mas coloque junto
def
s de uma linha só que correspondam à mesma função. [link]def alguma_funcao(nil), do: {:err, "Nenhum Valor"} def alguma_funcao([]), do: :ok def alguma_funcao([primeiro | resto]) do alguma_funcao(resto) end
-
Se você usar a sintaxe
do:
em funções, e o corpo da função tiver uma linha longa, coloque odo:
em uma nova linha com um nível de indentação a mais do que a linha anterior. [link]def alguma_funcao(args), do: Enum.map(args, fn(arg) -> arg <> " está em uma linha muito longa!" end)
Quando você usar a convenção acima e tiver mais que uma cláusula usando a sintaxe
do:
, coloque odo:
em uma nova linha para cada cláusula:# não recomendado def alguma_funcao([]), do: :vazio def alguma_funcao(_), do: :linha_muito_longa_aqui # recomendado def alguma_funcao([]), do: :vazio def alguma_funcao(_), do: :linha_muito_longa_aqui
-
Se você tiver mais que um
def
multilinha, não usedef
s de uma linha. [link]def alguma_funcao(nil) do {:err, "Nenhum Valor"} end def alguma_funcao([]) do :ok end def alguma_funcao([primeiro | resto]) do alguma_funcao(resto) end def alguma_funcao([primeiro | resto], opts) do alguma_funcao(resto, opts) end
-
Use parênteses em funções de aridade um ao usar o operador pipe (
|>
) [link]# não recomendado alguma_string |> String.downcase |> String.strip # recomendado alguma_string |> String.downcase() |> String.strip()
-
Use o operador pipe (
|>
) para encadear funções. [link]# não recomendado String.strip(String.downcase(alguma_string)) # recomendado alguma_string |> String.downcase |> String.strip # Pipelines multilinha não recebem indentação extra alguma_string |> String.downcase |> String.strip # Pipelines multilinha do lado direito de um pattern match # devem ser indentados em uma nova linha string_sanitizada = alguma_string |> String.downcase |> String.strip
Mesmo este sendo o método recomendado, lembre-se que copiar e colar pipelines multilinha no IEx pode resultar em erro de sintaxe, já que o IEx vai avaliar a primeira linha sem perceber que a próxima linha tem um pipeline.
-
Evite usar o operador pipe uma vez só. [link]
# não recomendado alguma_string |> String.downcase # recomendado String.downcase(alguma_string)
-
Use variáveis sozinhas na primeira parte de uma cadeia de funções. [link]
# PIOR JEITO! # Isto é interpretado como String.strip("não" |> String.downcase). String.strip "não" |> String.downcase() # não recomendado String.strip(alguma_string) |> String.downcase() |> String.codepoints() # recomendado alguma_string |> String.strip() |> String.downcase() |> String.codepoints()
-
Ao declarar uma linha que abrange múltiplas linhas, comece a lista em uma nova linha, e indente os elementos para mantê-los alinhados. [link]
# não recomendado - sem indentação lista = [:primeiro_item, :segundo_item, :proximo_item, :ultimo_item] # melhor, mas não recomendado - com indentação lista = [:primeiro_item, :segundo_item, :proximo_item, :ultimo_item] # recomendado - lista começa em uma linha própria # bom para listas menores lista = [:primeiro_item, :segundo_item, :proximo_item, :ultimo_item] # também recomendado - com cada elemento em uma linha # bom para listas longas, listas com elementos longos ou listas com comentários lista = [ :primeiro_item, :segundo_item, :proximo_item, # comentário :muitos_itens, :ultimo_item ]
-
Evite espaço em branco no fim das linhas [link]
-
Termine todos os arquivos com uma nova linha. [link]
-
Use parênteses quando um
def
tiver argumentos, e omita os parênteses quando ele não tiver argumentos. [link]# não recomendado def alguma_funcao arg1, arg2 do # corpo omitido end def alguma_funcao() do # corpo omitido end # recomendado def alguma_funcao(arg1, arg2) do # corpo omitido end def alguma_funcao do # corpo omitido end
-
Adicione uma linha em branco após uma declaração multilinha sinalizando que a declaração terminou. [link]
# não recomendado alguma_string = "Oi" |> String.downcase |> String.strip outra_string <> alguma_string # recomendado alguma_string = "Oi" |> String.downcase |> String.strip outra_string <> alguma_string
# também não recomendado alguma_coisa = if x == 2 do "Oi" else "Tchau" end String.downcase(alguma_coisa) # recomendado alguma_coisa = if x == 2 do "Oi" else "Tchau" end String.downcase(alguma_coisa)
-
Nunca use
do:
paraif
ouunless
multilinha. [link]# não recomendado if alguma_condicao, do: # uma linha de código # outra linha de código # note que este bloco não tem end # recomendado if alguma_condicao do # algumas # linhas # de código end
-
Use
do:
paraif/unless
de uma linha só. [link]# recomendado if alguma_condicao, do: # alguma_coisa
-
Nunca use
unless
comelse
. Reescreva estes com apenas casos positivos. [link]# não recomendado unless successo? do IO.puts 'falha' else IO.puts 'successo' end # recomendado if successo? do IO.puts 'successo' else IO.puts 'falha' end
-
Use
true
como a última condição docond
quando você precisa de uma cláusula que sempre dê match. [link]# não recomendado cond do 1 + 2 == 5 -> "Não" 1 + 3 == 5 -> "Oh, oh" :else -> "OK" end # recomendado cond do 1 + 2 == 5 -> "Não" 1 + 3 == 5 -> "Oh, oh" true -> "OK" end
-
Nunca coloque um espaço entre o nome da função e a abertura dos parênteses. [link]
# não recomendado f (3 + 2) + 1 # recomendado f(3 + 2) + 1
-
Use parênteses em chamadas de função, especialmente dentro de uma pipeline. [link]
# não recomendado f 3 # recomendado f(3) # não recomendado e é convertido como rem(2, (3 |> g)), que não é o que você quer. 2 |> rem 3 |> g # recomendado 2 |> rem(3) |> g
-
Omita parênteses em chamadas de macro onde um bloco
do
é passado. [link]# não recomendado quote(do foo end) # recomendado quote do foo end
-
Parênteses são opcionais em chamadas de função (fora de pipelines) quando o último argumento é uma expressão de função. [link]
# recomendado Enum.reduce(1..10, 0, fn x, acc -> x + acc end) # também recomendado Enum.reduce 1..10, 0, fn x, acc -> x + acc end
-
Use parênteses quando chamar funções de aridade zero, para que elas fiquem distintas de variáveis. A partir do Elixir 1.4 o compilador vai emitir
warnings
em lugares onde esta ambiguidade existir. [link]defp fazer_algo, do: ... # não recomendado def minha_funcao do fazer_algo # isto é uma variável ou uma chamada de função? end # recomendado def minha_funcao do fazer_algo() # isto claramente é uma chamada de função end
-
Sempre use a sintaxe simplificada para listas de palavras-chave. [link]
# não recomendado algum_valor = [{:a, "baz"}, {:b, "qux"}] # recomendado algum_valor = [a: "baz", b: "qux"]
-
Omita colchetes de listas de palavras-chave sempre que eles forem opcionais. [link]
# não recomendado alguma_funcao(foo, bar, [a: "baz", b: "qux"]) # recomendado alguma_funcao(foo, bar, a: "baz", b: "qux")
-
Indente e alinhe cláusulas
with
sucessivas. Coloque o argumentodo:
em uma nova linha, indentada normalmente. [link]with {:ok, foo} <- fetch(opts, :foo), {:ok, bar} <- fetch(opts, :bar), do: {:ok, foo, bar}
-
Se a expressão
with
tiver um blocodo
com mais de uma linha, ou tem uma opçãoelse
, use a sintaxe multilinha. [link]with {:ok, foo} <- fetch(opts, :foo), {:ok, bar} <- fetch(opts, :bar) do {:ok, foo, bar} else :error -> {:error, :bad_arg} end
-
Use
snake_case
para átomos, funções e variáveis. [link]# não recomendado :"algum átomo" :AlgumAtomo :algumAtomo algumaVar = 5 def algumaFuncao do ... end def AlgumaFuncao do ... end # recomendado :algum_atom alguma_var = 5 def alguma_funcao do ... end
-
Use
CamelCase
para módulos (mantenha siglas como HTTP, RFC, XML em maiúsculo). [link]# não recomendado defmodule Algummodulo do ... end defmodule Algum_Modulo do ... end defmodule AlgumXml do ... end # recomendado defmodule AlgumModulo do ... end defmodule AlgumXML do ... end
-
Os nomes das macros com predicado (funções geradas na hora da compilação que retornam um valor booleano) que podem ser usadas dentro de guards devem ser prefixados com
is_
. Para uma lista de expressões permitidas, veja nos documentos Guard. [link]defmacro is_cool(var) do quote do: unquote(var) == "cool" end
-
Os nomes de funções com predicados que não podem ser usadas em guards devem ter um ponto de interrogação à direita (
?
) em vez do prefixois_
(ou similar). [link]def cool?(var) do # Verificação complexa se var for cool não é possível em uma função pura. end
-
Funções privadas com o mesmo nome de funções públicas devem começar com
do_
. [link]def soma(list), do: do_soma(list, 0) # funções privadas defp do_soma([], total), do: total defp do_soma([head | tail], total), do: do_soma(tail, head + total)
-
Escreva código expressivo e busque transmitir a intenção do seu programa através de fluxo de controle, estrutura e nomenclaturas. [link]
-
Use um espaço entre o
#
do comentário e o texto do comentário. [link]String.first(alguma_string) #não recomendado String.first(alguma_string) # recomendado
-
Comentários de mais de uma palavra começam com maiúscula, e frases recebem pontuação. Use um espaço depois dos pontos finais. [link]
# não recomendado # este comentário em minúsculas não tem pontuação # recomendado # Exemplo com maiúscula # Use pontuação em frases completas.
-
Anotações normalmente devem vir na linha imediatamente acima do respectivo código. [link]
-
A palavra-chave de anotação é inteira em maiúsculas, seguida por dois-pontos e espaço, e então uma descrição do problema. [link]
# TODO: Deprecate in v2.0. def alguma_funcao(arg), do: {:ok, arg}
-
Nos casos em que o problema é tão óbvio que qualquer documentação seria redundante, as anotações podem vir no fim da linha em questão sem comentário adicional. Esta forma deve ser a exceção e não a regra. [link]
start_task() Process.sleep(5000) # FIXME
-
Use
TODO
para anotar funcionalidades que faltam ou funcionalidades que devem ser acrescentadas no futuro. [link] -
Use
FIXME
para anotar código quebrado que precisa ser corrigido. [link] -
Use
OPTIMIZE
para anotar código lento ou ineficiente que pode causar problemas de desempenho. [link] -
Use
HACK
para anotar lugares onde existem práticas questionáveis e que deveriam ser refatoradas. [link] -
Use
REVIEW
para anotar qualquer coisa que precise ser revista para confirmar que está funcionando conforme pretendido. Exemplo:REVIEW: Temos certeza que é assim que o cliente faz X hoje em dia?
[link] -
Use outras palavras-chave customizadas se apropriado, mas se certifique de documentá-las no
README
do seu projeto ou algo similar. [link]
-
Use um módulo por arquivo, a não ser que o módulo seja usado apenas internamente por outro módulo (um teste, por exemplo). [link]
-
Use nomes de arquivo em
snake_case
e nomes de módulo emCamelCase
. [link]# arquivo chamado algum_modulo.ex defmodule AlgumModulo do end
-
Expresse cada nível de aninhamento em um nome de módulo como um diretório. [link]
# arquivo chamado parser/core/xml_parser.ex defmodule Parser.Core.XMLParser do end
-
Não use uma linha em branco após um
defmodule
. [link] -
Use uma linha em branco após blocos de código em módulos. [link]
-
Liste atributos e diretivas de módulo na seguinte ordem: [link]
@moduledoc
@behaviour
use
import
alias
require
defstruct
@type
@module_attribute
@callback
@macrocallback
@optional_callbacks
Adicione uma linha em branco entre cada agrupamento, e ordene os termos (como nomes de módulos) alfabeticamente. Abaixo um exemplo geral de como você deve ordenar as coisas em seus módulos:
defmodule MeuModulo do @moduledoc """ Exemplo de módulo """ @behaviour MeuBehaviour use GenServer import AlgumaCoisa import OutraCoisa alias Meu.Nome.Comprido.Modulo alias Meu.Outro.Exemplo.Modulo require Integer defstruct name: nil, params: [] @type params :: [{binary, binary}] @module_attribute :foo @other_attribute 100 @callback alguma_funcao(termo) :: :ok | {:error, termo} @macrocallback nome_macro(termo) :: Macro.t @optional_callbacks nome_macro: 1 ... end
-
Use a pseudo variável
__MODULE__
quando um módulo se referir a si mesmo. Isto previne que tenhamos que atualizar auto-referências quando o nome do módulo mudar. [link]defmodule AlgumProjeto.AlgumModulo do defstruct [:nome] def nome(%__MODULE__{nome: nome}), do: nome end
-
Se você quiser um nome mais bonito para uma auto-referência de módulo, crie um alias. [link]
defmodule AlgumProjeto.AlgumModulo do alias __MODULE__, as: AlgumModulo defstruct [:nome] def nome(%AlgumModulo{nome: nome}), do: nome end
-
Evite repetir fragmentos em nomes e namespaces de módulos. Isto melhora a legibilidade e elimina aliases ambíguos. [link]
# não recomendado defmodule Todo.Todo do ... end # recomendado defmodule Todo.Item do ... end
Documentação em Elixir (quando lida seja no iex
com h
seja gerada com
ExDoc) usa os Atributos de Módulo @moduledoc
e @doc
.
-
Inclua sempre um atributo
@moduledoc
na linha imediatamente posterior aodefmodule
em seu módulo. [link]# não recomendado defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. """ ... end defmodule OutroModulo do use AlgumModulo @moduledoc """ Informação sobre o módulo. """ ... end # recomendado defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. """ ... end
-
Use
@moduledoc false
se você não pretende documentar o módulo. [link]defmodule AlgumModulo do @moduledoc false ... end
-
Separe o código que vem depois do
@moduledoc
com uma linha em branco. [link]# não recomendado defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. """ use OutroModulo end # recomendado defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. """ use OutroModulo end
-
Use heredocs com markdown na documentação. [link]
# não recomendado defmodule AlgumModulo do @moduledoc "Informação sobre o módulo." end defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. Exemplos: iex> AlgumModulo.alguma_funcao :resultado """ end # recomendado defmodule AlgumModulo do @moduledoc """ Informação sobre o módulo. ## Exemplos iex> AlgumModulo.alguma_funcao :resultado """ end
Typespecs são notações para declarar tipos e especificações, para documentação ou para o Dialyzer (ferramenta de análise estática).
Tipos customizados devem ser definidos no topo do módulo com as outras diretivas (veja Módulos).
-
Aplique definições
@typedoc
e@type
juntas, e separe cada par com uma linha em branco. [link]defmodule AlgumModulo do @moduledoc false @typedoc "O nome" @type name :: atom @typedoc "O resultado" @type result :: {:ok, termo} | {:error, termo} ... end
-
Se um tipo de união for longo demais para caber em um só linha, adicione uma nova linha e indente com espaços para alinhar os tipos. [link]
# não recomendado - sem indentação @type tipo_de_uniao_longo :: algum_tipo | outro_tipo | algum_outro_tipo | um_ultimo_tipo # recomendado @type tipo_de_uniao_longo :: algum_tipo | outro_tipo | algum_outro_tipo | um_ultimo_tipo # também recomendado - um tipo por linha @type tipo_de_uniao_longo :: algum_tipo | outro_tipo | algum_outro_tipo | um_ultimo_tipo
-
Nomeie como
t
o tipo principal de um módulo, por exemplo: a especificação de tipo para um struct. [link]defstruct nome: nil, params: [] @type t :: %__MODULE__{ nome: String.t | nil, params: Keyword.t }
-
Escreva especificações logo acima da definicação de uma função, sem separá-los com linha em branco. [link]
@spec alguma_funcao(termo) :: result def alguma_funcao(algum_dado) do {:ok, algum_dado} end
-
Use uma lista de átomos para campos de struct que tenham default de
nil
, seguidos por outras palavras-chave. [link]# não recomendado defstruct nome: nil, params: nil, ativo: true # recomendado defstruct [:nome, :params, ativo: true]
-
Omita colchetes quando o argumento de um
defstruct
for uma lista de palavras-chave. [link]# não recomendado defstruct [params: [], ativo: true] # recomendado defstruct params: [], ativo: true # obrigatório - colchetes não são opcionais, com ao menos um átomo na lista defstruct [:nome, params: [], ativo: true]
-
Indente linhas adicionais de defstruct, mantendo as primeiras chaves alinhadas. aligned. [link]
defstruct foo: "teste", bar: true, baz: false, qux: false, quux: 1
-
Adicione o sufixo
Error
aos nomes de exceções. [link]# não recomendado defmodule BadHTTPCode do defexception [:mensagem] end defmodule BadHTTPCodeException do defexception [:mensagem] end # recomendado defmodule BadHTTPCodeError do defexception [:mensagem] end
-
Use minúsculas em mensagens de erro quando emitindo exceções, sem pontuação ao final. [link]
# não recomendado raise ArgumentError, "Isto não é válido." # recomendado raise ArgumentError, "isto é válido"
A secão de Coleções do guia ainda não foi adicionada.
-
Dê match em strings usando o concatenador de strings, e não padrões binários. [link]
# não recomendado <<"minha"::utf8, _resto>> = "minha string" # recomendado "minha" <> _resto = "minha string"
A secão de Coleções do guia ainda não foi adicionada.
- Evite metaprogramação desnecessária. [link]
-
Ao escrever asserções ExUnit, mantenha a consistência entre a ordem dos valores esperados e reais que estão sob teste. Prefira usar o resultado esperado à direita, a não ser que a asserção seja um pattern match. [link]
# recomendado - resultado esperado à direita assert minha_funcao(1) == true assert minha_funcao(2) == false # não recomendado - ordem inconsistente assert minha_funcao(1) == true assert false == minha_funcao(2) # obrigatório - a asserção é um pattern match assert {:ok, expected} = minha_funcao(3)
-
Aleksei Magusev's Elixir Style Guide — Um guia de estilo Elixir opiniático inspirado nas práticas encontradas nas bibliotecas 'core' do Elixir. Desenvolvido por Aleksei Magusev e Andrea Leopardi, membros da equipe principal do Elixir. Apesar do projeto do Elixir não aderir a um guia de estilo específico, este é o guia mais próximo de suas convenções.
-
Credo's Elixir Style Guide — Guia de Estilo para a linguagem Elixir, implementada pelo Credo, ferramenta de análise estática de código.
Confira o Awesome Elixir para encontrar bibliotecas e ferramentas para te ajudar em análise e linting de código.
Esperamos que este se torne um ponto de encontro para discussões da comunidade sobre as melhores práticas em Elixir. Sinta-se bem-vindo(a) a abrir issues ou enviar pull requests com melhorias. Obrigado desde já por sua ajuda!
Confira as dicas de contribuição - em inglês e o código de conduta para saber mais.
Um guia de estilo de uma comunidade não faz sentido sem o apoio da comunidade. Por gentileza tuíte, dê estrelas e compartilhe [este guia][Elixir Style Guide] com todos, para que todos possam contribuir.
Este trabalho é licenciada sob uma Licença Creative Commons Attribution 3.0 Unported
A estrutura deste guia, alguns trechos de código dos exemplos, e muito pontos iniciais deste documento foram empresados do Guia de Estilo da Comunidade Ruby. Muitas coisas se aplicavam ao Elixir e nos permitiram publicar algum documento mas rápido e dar início ao projeto. out quicker to start the conversation.
Aqui está a lista das pessoas que gentilmente contribuíram com este projeto.