Welcome to Jungsoft's Elixir Style Guide. Sit down, have a cup of coffee and read this calmly. ☕
The goal of this guide is to help our team to understand and follow code style best practices, maintaining a pattern.
As this guide is an extension of the Christopher Adams Elixir Style Guide, we highly recommend reading it before you continue.
The aliases should be ordered alphabetically using the full path as it is easier to add and remove an alias and you do not need to rearrange the groupings.
# ❌ Bad
alias Jungsoft.{
AModule,
BModule,
CModule,
}
alias Jungsoft.AModule.ASubModule
# ✅ Good
alias Jungsoft.AModule
alias Jungsoft.AModule.ASubModule
alias Jungsoft.BModule
alias Jungsoft.CModule
# ❌ Bad
alias Jungsoft.{
AModule,
BModule,
CModule,
}
# ✅ Good
alias Jungsoft.AModule
alias Jungsoft.BModule
alias Jungsoft.CModule
# ❌ Bad
alias Jungsoft.AModule.ASubModule.ASubSubModule
alias Jungsoft.AModule.ASubModule
alias Jungsoft.CModule
alias Jungsoft.BModule
# ✅ Good
alias Jungsoft.AModule.ASubModule
alias Jungsoft.AModule.ASubModule.ASubSubModule
alias Jungsoft.BModule
alias Jungsoft.CModule
Blank lines are important in some cases, but in some others can make the code less readable. The examples below will give more details about this.
Modules should not contain a blank line between the moduledoc
and the module name.
# ❌ Bad
defmodule Jungsoft.NicePlaceToWork do
@moduledoc false
# DO SOMETHING
end
# ✅ Good
defmodule Jungsoft.NicePlaceToWork do
@moduledoc false
# DO SOMETHING
end
The module end
should not contain a blank space either.
# ❌ Bad
defmodule Jungsoft.BestPeople do
@moduledoc false
def foo do
true
end
end
# ✅ Good
defmodule Jungsoft.BestPeople do
@moduledoc false
def foo do
true
end
end
Different functions should contain exactly one blank space between each other.
# ❌ Bad
defmodule Jungsoft.GoodCoffee do
@moduledoc false
def foo, do: true
def bar, do: true
def func, do: true
end
# ✅ Good
defmodule Jungsoft.GoodCoffee do
@moduledoc false
def foo, do: true
def bar, do: true
def func, do: true
end
Functions should not contain a blank line between the function call and the parameters. In addition, they should not end with a blank line.
# ❌ Bad
defmodule Jungsoft.BeautifulOfficeView do
@moduledoc false
def foo do
1 + 1
end
end
# ✅ Good
defmodule Jungsoft.BeautifulOfficeView do
@moduledoc false
def foo do
1 + 1
end
end
The with do
parameters should not be separated by blank spaces. Except when else
contains multiple options. In this case should use the same logic as case
and cond
normal style (see here).
# ❌ Bad
with %StarWars{} <- Jungsoft.function_1(),
true <- Jungsoft.function_2()
do
## DO SOMETHING
else
%StarTrek{} ->
{:error, "Wrong choice"}
false ->
## DO SOMETHING
end
# ✅ Good
with %StarWars{} <- Jungsoft.function_1(),
true <- Jungsoft.function_2()
do
## DO SOMETHING
else
%StarTrek{} ->
{:error, "Wrong choice"}
false ->
## DO SOMETHING
end
When an enumerable contains more than 3 arguments, it should be broken into multiple lines. See an example for Lists below.
# ❌ Bad
list = ["value1", "value2", "value3", "value4"]
# ✅ Good
list = [
"value1",
"value2",
"value3",
"value4",
]
# ✅ Good
list = ["value1", "value2", "value3"]
# ❌ Bad
map = %{a: 1, b: 2, c: 3, d: 4}
# ✅ Good
map = %{
a: 1,
b: 2,
c: 3,
d: 4,
}
# ✅ Good
map = %{a: 1, b: 2, c: 3}
This is also valid for Keyword Lists.
Objects with the possibility to span in multiple lines should contain a comma dangle in the last parameter. See an example of lists below.
# ❌ Bad
list = [
"value1",
"value2",
"value3",
"value4"
]
# ✅ Good
list = [
"value1",
"value2",
"value3",
"value4",
]
This is also valid for Maps and Keyword Lists.
Modules that are meant to be public and used across the application (e.g. phoenix contexts, ecto schemas) must have a @moduledoc
with a description (not false
). Modules that are meant to be private for a specific context (e.g. an adapter for a public service), must have a @moduledoc false
. See more about this here: https://hexdocs.pm/elixir/writing-documentation.html#hiding-internal-modules-and-functions
# ❌ Bad
defmodule Jungsoft.Accounts do
@moduledoc false
# Public functions for the Accounts context
end
# ❌ Bad
defmodule Jungsoft.Storage.S3Adapter do
@moduledoc """
Adapter for AWS S3
"""
# Functions that must be used only in the Storage context
end
# ✅ Good
defmodule Jungsoft.Accounts do
@moduledoc """
The Accounts context that manipulates the users of the application.
"""
# Public functions for the Accounts context
end
# ✅ Good
defmodule Jungsoft.Storage.S3Adapter do
@moduledoc false
# Functions that must be used only in the Storage context
end
When with do
contains multiple lines, it's necessary to add two blank spaces before the first parameter. This is only valid when editor tab size is 2. If you followed the Jungsoft guidelines this should be your case. 😊
# ❌ Bad
with true <- Jungsoft.function_1(),
false <- Jungsoft.function_2()
do
## DO SOMETHING
end
# ❌ Bad
with true <- Jungsoft.function_1(),
false <- Jungsoft.function_2()
do
## DO SOMETHING
end
# ❌ Bad
with true <- Jungsoft.function_1() do
## DO SOMETHING
end
# ✅ Good
with true <- Jungsoft.function_1(),
false <- Jungsoft.function_2()
do
## DO SOMETHING
end
# ✅ Good
with true <- Jungsoft.function_1() do
## DO SOMETHING
end
The schemas should respect a pattern for organizing the parameters.
Independent of the schema type, the parameters should be grouped by type:
# ❌ Bad
schema "foo" do
field :name, :string
field :age, :integer
has_one :one, Bar
has_one :two, Module
timestamps()
end
# ✅ Good
schema "foo" do
field :name, :string
field :age, :integer
has_one :one, Bar
has_one :two, Module
timestamps()
end
The other patterns are different based on the type of schema (Ecto or GraphQL). These differences are listed below.
The Ecto schema parameters need to be organized in a order of importance:
Importance | Field |
---|---|
1º | field |
2º | belongs_to |
3º | has_one |
4º | has_many |
5º | timestamps |
In this way, field
should be inserted before belongs_to
, and so on.
The GraphQL schema parameters need to be organized in a order of importance:
Importance | Field |
---|---|
1º | normal fields |
2º | custom fields (with the resolve ) |
3º | associations |
In this way, normal fields
should be inserted before custom fields
, and so on.
Remember, the first schema rule should be respected here as well (see here). Therefore, normal fields
should be grouped and separated with a blank space. Same is valid with custom fields
and associations
.