Programming Guide
Software Design
Exception names must have the Error
suffix. Reversely, modules that don’t call defexception
must not have the Error
suffix.
Pattern matching should be preferred over .
or []
operators for destructuring.
Deep nest digging macros should be preferred over manual deep structure re-assembly.
Keyword lists should be preferred over maps for internal passing of options.
Tuples should be preferred over lists for internal passing of short, predefined lists.
Functions that may result in success or failure and that must pass additional data upon success or
failure should return {:ok, ...}
and {:error, ...}
tuples.
Functions that don’t fail with {:error, ...}
should not return {:ok, ...}
as well.
Raising an exception should be preferred over returning error tuple for cases which don’t have to be handled.
Modules that express single action should be named with a verb prefix and have a def call
entry.
Modules that don’t express single action, should be named with nouns instead of verbs.
Repeating module name in its function names should be avoided. For example, User.valid?
should be
preferred over User.user_valid?
.
Operators and
and or
should be preferred over &&
and ||
when arguments are known for sure
to be booleans.
Guard-enabled functions and operators should be preferred over different means to achieve the same.
Nested controllers should be preferred over custom controller actions.
Named functions should be preferred over anonymous functions.
Function pointers should be preferred over redundant anonymous functions. For example, &func/1
is preferred over fn arg -> func(arg) end
.
Function pointers in &func/arity
format should be preferred over &func(&1)
format when there’s
no need for argument modification.
When a function in a module has many functions that are private to it, then it should be extracted into separate submodule along with its private functions.
Repeated or reusable calls to Ecto.Query.fragment
should be extracted to custom macros.
Functions that return nil
when fetched item is missing should be named with get
prefix.
Functions that need to return the reason for fetch failure should be named with fetch
prefix.
Functions that raise when item is missing should be named with !
suffix.
Sigils ~w{a b c}
and ~w{a b c}a
should be preferred over []
for defining string and atom
lists (code style).
When using _
for unused variables, it should still be named for description purposes.
For example, _user
is preferred over just _
.
Project Structure
Nested module files must be placed accordingly to nesting in their name. For example,
MyProject.Web.UserController
module must be placed in my_project/web
.
Within a module, submodule files may be segregated into subdirectories one level deep without
changing the module name. This is handy for keeping large modules organized. For example,
MyProject.Web.UserController
module may be placed, together with other controllers, in
my_project/web/controllers
. Inside each subdirectory, all files may share a common suffix in
order to guarantee unique module names.
Entry points for modules with submodules should be placed inside module directory with a file name
same as module name. Modules without submodules should not be placed in separate directory. For
example, MyProject.Accounts
module should be defined in my_project/accounts/accounts.ex
if
there are other submodules like MyProject.Accounts.User
and in my_project/accounts.ex
otherwise.
Module entry points should be kept as lightweight as possible and proxy heavier business logic to submodules.
Module entry points should be used as a place to document the module and all its public functions.