Liquid architecture. It's like jazz - you improvise, you work together, you play off each other, you make something, they make something.
-- Frank Gehry
Style matters. Elixir has plenty of style but like all languages it can be stifled. Don't stifle the style.
This is my attempt at starting a community style guide for Elixir. Please feel free to make pull requests and contribute. I really want Elixir to have as vibrant of a community as any language that's been around five times as long.
If you're looking for other projects to contribute to please see Elixir's list of projects
- Source Code Layout
- Syntax
- Naming
- Comments
- Exceptions
- Collections
- Strings
- Regular Expressions
- Metaprogramming
- Misc
- Tools
- Use two spaces per indentation level. No hard tabs.
# bad - four spaces
def some_method do
do_something
end
# good
def some_method do
do_something
end
-
Use Unix-style line endings. (*BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.)
- If you're using Git you might want to add the following configuration setting to protect your project from Windows line endings creeping in:
$ git config --global core.autocrlf true
- Use spaces around operators, after commas, colons and semicolons, around
{
and before}
. Do not put spaces after the opening or before the closing parenthesis. Whitespace might be (mostly) irrelevant to the Elixir runtime, but its proper use is the key to writing easily readable code.
sum = 1 + 2
{ a, b } = { 2, 3 }
Enum.map(["one", "two", "three"], fn (num) -> IO.puts num end)
- Use empty lines between
def
s and to break up a method into logical paragraphs.
def some_method(some_data) do
altered_data = Module.Function(data)
end
def some_method do
result
end
def some_other_method do
another_result
end
- ...but run different clauses that match for the same function together.
def some_method([]) do
:ok
end
def some_method([first|rest]) do
some_method(rest)
end
- Use the pipeline operator ( |> ) to chain methods together
# bad
String.strip(String.downcase(some_string))
# good
some_string |> String.downcase |> String.strip
- Use bare variables in the first part of a function chain
# THE WORST!
# This actually parses as String.strip( "nope" |> String.downcase ).
String.strip "nope" |> String.downcase
# bad
String.strip(some_string) |> String.downcase |> String.codepoints
# good
some_string |> String.strip |> String.downcase |> String.codepoints
- Avoid trailing whitespace.
- Use parens when you have arguments, no parens when you don't
# bad
def some_method arg1, arg2 do
# body omitted
end
def some_method() do
# body omitted
end
# good
def some_method(arg1, arg2) do
#body omitted
end
def some_method do
# body omitted
end
- Never use
do:
for multi-lineif/unless
.
# bad
if some_condition, do:
# a line of code
# another line of code
# note no end in this block
# good
if some_condition
# some
# lines
# of code
end
- Use
do:
for single lineif/unless
statements
# good
if some_condition, do: # some_stuff
- Never use
unless
withelse
. Rewrite these with the positive case first.
# bad
unless success?
IO.puts 'failure'
else
IO.puts 'success'
end
# good
if success?
IO.puts 'success'
else
IO.puts 'failure'
end
- Never put a space between a method name and the opening parenthesis.
# bad
f (3 + 2) + 1
# good
f(3 + 2) + 1
- Use parentheses in function calls, especially inside a pipeline.
# bad
f 3
# good
f(3)
# bad and parses as f(3 |> g), which is not what you want
f 3 |> g
# good
f(3) |> g()
- Omit parentheses in macro calls when a do block is passed.
# bad
quote(do
foo
end)
# good
quote do
foo
end
- Optionally omit parentheses in function calls (outside a pipeline) when the last argument is a function expression.
# good
Enum.reduce(1..10, 0, fn x, acc ->
x + acc
end)
# also good
Enum.reduce 1..10, 0, fn x, acc ->
x + acc
end
- Use
snake_case
for atoms, methods and variables.
# bad
:"some atom"
:SomeAtom
:someAtom
someVar = 5
def someMethod do
...
end
def SomeMethod do
...
end
# good
:some_atom
def some_method do
...
end
- Use
CamelCase
for modules. (Keep acronyms like HTTP, RFC, XML uppercase.)
# bad
defmodule Somemodule do
...
end
defmodule Some_Module do
...
end
defmodule SomeXml do
...
end
# good
defmodule SomeModule do
...
end
defmodule SomeXML do
...
end
- The names of predicate functions (a function that return a boolean value) should end in a question mark.
def is_string?(var) do
# check if var is string
end
- Write self-documenting code and ignore the rest of this section. Seriously!
- Use one space between the leading
#
character of the comment and the text of the comment. - Comments longer than a word are capitalized and use punctuation. Use one space after periods.
# bad
String.upcase(some_string) # Capitalize string.
-
Keep existing comments up-to-date. An outdated comment is worse than no comment at all.
-
Avoid writing comments to explain bad code. Refactor the code to make it self-explanatory. (Do or do not - there is no try. --Yoda)
-
Annotations should usually be written on the line immediately above the relevant code.
-
The annotation keyword is followed by a colon and a space, then a note describing the problem.
-
If multiple lines are required to describe the problem, subsequent lines should be indented two spaces after the
#
. -
In cases where the problem is so obvious that any documentation would be redundant, annotations may be left at the end of the offending line with no note. This usage should be the exception and not the rule.
-
Use
TODO
to note missing features or functionality that should be added at a later date. -
Use
FIXME
to note broken code that needs to be fixed. -
Use
OPTIMIZE
to note slow or inefficient code that may cause performance problems. -
Use
HACK
to note code smells where questionable coding practices were used and should be refactored away. -
Use
REVIEW
to note anything that should be looked at to confirm it is working as intended. For example:REVIEW: Are we sure this is how the client does X currently?
-
Use other custom annotation keywords if it feels appropriate, but be sure to document them in your project's
README
or similar.
- Avoid needless metaprogramming.
It's my hope that this will become a central hub for community discussion on best practices in Elixir. Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help!
This work is licensed under a Creative Commons Attribution 3.0 Unported License
The structure of this guide, bits of example code, and many of the initial points made in this document were borrowed from the Ruby community style guide. A lot of things were applicable to Elixir and allowed me to get some document out quicker to start the conversation.
A community style guide is meaningless without the community's support. Please Tweet, star, and let any Elixir programmer know about this guide so they can contribute.