{"id":16702739,"url":"https://github.com/lexmag/elixir-style-guide","last_synced_at":"2025-04-04T17:09:57.272Z","repository":{"id":71491845,"uuid":"43909852","full_name":"lexmag/elixir-style-guide","owner":"lexmag","description":"An opinionated Elixir style guide","archived":false,"fork":false,"pushed_at":"2024-03-27T16:45:29.000Z","size":49,"stargazers_count":517,"open_issues_count":4,"forks_count":35,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-05-02T05:23:27.934Z","etag":null,"topics":["elixir","style-guide"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lexmag.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-10-08T18:52:55.000Z","updated_at":"2024-04-29T09:47:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"896a4657-4c1f-4aa4-bd12-f94d37bbb04b","html_url":"https://github.com/lexmag/elixir-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexmag%2Felixir-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexmag%2Felixir-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexmag%2Felixir-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexmag%2Felixir-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lexmag","download_url":"https://codeload.github.com/lexmag/elixir-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247217222,"owners_count":20903009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","style-guide"],"created_at":"2024-10-12T19:05:59.093Z","updated_at":"2025-04-04T17:09:57.250Z","avatar_url":"https://github.com/lexmag.png","language":null,"funding_links":[],"categories":["Styleguides"],"sub_categories":[],"readme":"# Elixir Style Guide\n\n\u003e A programmer does not primarily write code; rather, he primarily writes to another programmer about his problem solution. The understanding of this fact is the final step in his maturation as technician.\n\u003e\n\u003e — \u003ccite\u003eWhat a Programmer Does, 1967\u003c/cite\u003e\n\n## Table of Contents\n\n* [Linting](#linting)\n  * [Naming](#naming)\n  * [Comments](#comments)\n  * [Modules](#modules)\n  * [Regular Expressions](#regular-expressions)\n  * [Structs](#structs)\n  * [Exceptions](#exceptions)\n  * [ExUnit](#exunit)\n\nThe following section are automatically applied by the code formatter in Elixir v1.6 and listed here only for documentation purposes:\n\n* [Formatting](#formatting)\n  * [Whitespace](#whitespace)\n  * [Indentation](#indentation)\n  * [Term representation](#term-representation)\n  * [Parentheses](#parentheses)\n  * [Layout](#layout)\n\n## Linting\n\n* \u003ca name=\"pipeline-operator\"\u003e\u003c/a\u003e\n  Favor the pipeline operator `|\u003e` to chain function calls together.\n  \u003csup\u003e[[link](#pipeline-operator)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  String.downcase(String.strip(input))\n\n  # Good\n  input |\u003e String.strip() |\u003e String.downcase()\n  ```\n\n  For a multi-line pipeline, place each function call on a new line, and retain the level of indentation.\n\n  ```elixir\n  input\n  |\u003e String.strip()\n  |\u003e String.downcase()\n  |\u003e String.slice(1, 3)\n\n* \u003ca name=\"needless-pipeline\"\u003e\u003c/a\u003e\n  Avoid needless pipelines like the plague.\n  \u003csup\u003e[[link](#needless-pipeline)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  result = input |\u003e String.strip()\n\n  # Good\n  result = String.strip(input)\n  ```\n\n* \u003ca name=\"anonymous-pipeline\"\u003e\u003c/a\u003e\n  Don't use anonymous functions in pipelines.\n  \u003csup\u003e[[link](#anonymous-pipeline)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  sentence\n  |\u003e String.split(~r/\\s/)\n  |\u003e (fn words -\u003e [@sentence_start | words] end).()\n  |\u003e Enum.join(\" \")\n\n  # Good\n  split_sentence = String.split(sentence, ~r/\\s/)\n  Enum.join([@sentence_start | split_sentence], \" \")\n  ```\n\n  Consider defining private helper function when appropriate:\n\n  ```elixir\n  # Good\n  sentence\n  |\u003e String.split(~r/\\s/)\n  |\u003e prepend(@sentence_start)\n  |\u003e Enum.join(\" \")\n  ```\n\n* \u003ca name=\"no-else-with-unless\"\u003e\u003c/a\u003e\n  Never use `unless` with `else`. Rewrite these with the positive case first.\n  \u003csup\u003e[[link](#no-else-with-unless)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  unless Enum.empty?(coll) do\n    :ok\n  else\n    :error\n  end\n\n  # Good\n  if Enum.empty?(coll) do\n    :error\n  else\n    :ok\n  end\n  ```\n\n* \u003ca name=\"no-nil-else\"\u003e\u003c/a\u003e\n  Omit the `else` option in `if` and `unless` constructs if `else` returns `nil`.\n  \u003csup\u003e[[link](#no-nil-else)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  if byte_size(data) \u003e 0, do: data, else: nil\n\n  # Good\n  if byte_size(data) \u003e 0, do: data\n  ```\n\n* \u003ca name=\"true-in-cond\"\u003e\u003c/a\u003e\n  If you have an always-matching clause in the `cond` special form, use `true` as its condition.\n  \u003csup\u003e[[link](#true-in-cond)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  cond do\n    char in ?0..?9 -\u003e\n      char - ?0\n\n    char in ?A..?Z -\u003e\n      char - ?A + 10\n\n    :other -\u003e\n      char - ?a + 10\n  end\n\n  # Good\n  cond do\n    char in ?0..?9 -\u003e\n      char - ?0\n\n    char in ?A..?Z -\u003e\n      char - ?A + 10\n\n    true -\u003e\n      char - ?a + 10\n  end\n  ```\n\n* \u003ca name=\"boolean-operators\"\u003e\u003c/a\u003e\n  Never use `||`, `\u0026\u0026`, and `!` for strictly boolean checks. Use these operators only if any of the arguments are non-boolean.\n  \u003csup\u003e[[link](#boolean-operators)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  is_atom(name) \u0026\u0026 name != nil\n  is_binary(task) || is_atom(task)\n\n  # Good\n  is_atom(name) and name != nil\n  is_binary(task) or is_atom(task)\n  line \u0026\u0026 line != 0\n  file || \"sample.exs\"\n  ```\n\n* \u003ca name=\"patterns-matching-binaries\"\u003e\u003c/a\u003e\n  Favor the binary concatenation operator `\u003c\u003e` over bitstring syntax for patterns matching binaries.\n  \u003csup\u003e[[link](#patterns-matching-binaries)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  \u003c\u003c\"http://\", _rest::bytes\u003e\u003e = input\n  \u003c\u003cfirst::utf8, rest::bytes\u003e\u003e = input\n\n  # Good\n  \"http://\" \u003c\u003e _rest = input\n  \u003c\u003cfirst::utf8\u003e\u003e \u003c\u003e rest = input\n  ```\n\n### Naming\n\n* \u003ca name=\"snake-case-atoms-funs-vars-attrs\"\u003e\u003c/a\u003e\n  Use `snake_case` for functions, variables, module attributes, and atoms.\n  \u003csup\u003e[[link](#snake-case-atoms-funs-vars-attrs)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  :\"no match\"\n  :Error\n  :badReturn\n\n  fileName = \"sample.txt\"\n\n  @_VERSION \"0.0.1\"\n\n  def readFile(path) do\n    # ...\n  end\n\n  # Good\n  :no_match\n  :error\n  :bad_return\n\n  file_name = \"sample.txt\"\n\n  @version \"0.0.1\"\n\n  def read_file(path) do\n    # ...\n  end\n  ```\n\n* \u003ca name=\"camelcase-modules\"\u003e\u003c/a\u003e\n  Use `CamelCase` for module names. Keep uppercase acronyms as uppercase.\n  \u003csup\u003e[[link](#camelcase-modules)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  defmodule :appStack do\n    # ...\n  end\n\n  defmodule App_Stack do\n    # ...\n  end\n\n  defmodule Appstack do\n    # ...\n  end\n\n  defmodule Html do\n    # ...\n  end\n\n  # Good\n  defmodule AppStack do\n    # ...\n  end\n\n  defmodule HTML do\n    # ...\n  end\n  ```\n\n* \u003ca name=\"predicate-funs-name\"\u003e\u003c/a\u003e\n  The names of predicate functions (functions that return a boolean value) should have a trailing question mark `?` rather than a leading `has_` or similar.\n  \u003csup\u003e[[link](#predicate-funs-name)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  def is_leap(year) do\n    # ...\n  end\n\n  # Good\n  def leap?(year) do\n    # ...\n  end\n  ```\n\n  Always use a leading `is_` when naming guard-safe predicate macros.\n\n  ```elixir\n  defmacro is_date(month, day) do\n    # ...\n  end\n  ```\n\n* \u003ca name=\"snake-case-dirs-files\"\u003e\u003c/a\u003e\n  Use `snake_case` for naming directories and files, for example `lib/my_app/task_server.ex`.\n  \u003csup\u003e[[link](#snake-case-dirs-files)]\u003c/sup\u003e\n\n* \u003ca name=\"one-letter-var\"\u003e\u003c/a\u003e\n  Avoid using one-letter variable names.\n  \u003csup\u003e[[link](#one-letter-var)]\u003c/sup\u003e\n\n### Comments\n\n\u003e Remember, good code is like a good joke: It needs no explanation.\n\u003e\n\u003e — \u003ccite\u003eRuss Olsen\u003c/cite\u003e\n\n* \u003ca name=\"critical-comments\"\u003e\u003c/a\u003e\n  Use code comments only to communicate important details to another person reading the code.\n  For example, a high-level description of the algorithm being implemented or why certain\n  critical decisions, such as optimization or business rules, were made.\n  \u003csup\u003e[[link](#critical-comments)]\u003c/sup\u003e\n\n* \u003ca name=\"no-superfluous-comments\"\u003e\u003c/a\u003e\n  Avoid superfluous comments.\n  \u003csup\u003e[[link](#no-superfluous-comments)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  String.first(input) # Get first grapheme.\n  ```\n\n### Modules\n\n* \u003ca name=\"module-layout\"\u003e\u003c/a\u003e\n  Use a consistent structure when calling `use`/`import`/`alias`/`require`: call them in this order and group multiple calls to each of them.\n  \u003csup\u003e[[link](#module-layout)]\u003c/sup\u003e\n\n  ```elixir\n  use GenServer\n\n  import Bitwise\n  import Kernel, except: [length: 1]\n\n  alias Mix.Utils\n  alias MapSet, as: Set\n\n  require Logger\n  ```\n\n* \u003ca name=\"current-module-reference\"\u003e\u003c/a\u003e\n  Use the `__MODULE__` pseudo-variable to reference the current module.\n  \u003csup\u003e[[link](#current-module-reference)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  :ets.new(Kernel.LexicalTracker, [:named_table])\n  GenServer.start_link(Module.LocalsTracker, nil, [])\n\n  # Good\n  :ets.new(__MODULE__, [:named_table])\n  GenServer.start_link(__MODULE__, nil, [])\n  ```\n\n### Regular Expressions\n\n* \u003ca name=\"pattern-matching-over-regexp\"\u003e\u003c/a\u003e\n  Regular expressions are the last resort. Pattern matching and the `String` module are things to start with.\n  \u003csup\u003e[[link](#pattern-matching-over-regexp)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  Regex.run(~r/#(\\d{2})(\\d{2})(\\d{2})/, color)\n  Regex.match?(~r/(email|password)/, input)\n\n  # Good\n  \u003c\u003c?#, p1::2-bytes, p2::2-bytes, p3::2-bytes\u003e\u003e = color\n  String.contains?(input, [\"email\", \"password\"])\n  ```\n\n* \u003ca name=\"non-capturing-regexp\"\u003e\u003c/a\u003e\n  Use non-capturing groups when you don't use the captured result.\n  \u003csup\u003e[[link](#non-capturing-regexp)]\u003c/sup\u003e\n\n  ```elixir\n  ~r/(?:post|zip )code: (\\d+)/\n  ```\n\n* \u003ca name=\"caret-and-dollar-regexp\"\u003e\u003c/a\u003e\n  Be careful with `^` and `$` as they match start and end of the __line__ respectively. If you want to match the __whole__ string use: `\\A` and `\\z` (not to be confused with `\\Z` which is the equivalent of `\\n?\\z`).\n  \u003csup\u003e[[link](#caret-and-dollar-regexp)]\u003c/sup\u003e\n\n### Structs\n\n* \u003ca name=\"defstruct-fields-default\"\u003e\u003c/a\u003e\n  When calling `defstruct/1`, don't explicitly specify `nil` for fields that default to `nil`.\n  \u003csup\u003e[[link](#defstruct-fields-default)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  defstruct first_name: nil, last_name: nil, admin?: false\n\n  # Good\n  defstruct [:first_name, :last_name, admin?: false]\n  ```\n\n### Exceptions\n\n* \u003ca name=\"exception-naming\"\u003e\u003c/a\u003e\n  Make exception names end with a trailing `Error`.\n  \u003csup\u003e[[link](#exception-naming)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  BadResponse\n  ResponseException\n\n  # Good\n  ResponseError\n  ```\n\n* \u003ca name=\"exception-message\"\u003e\u003c/a\u003e\n  Use non-capitalized error messages when raising exceptions, with no trailing punctuation.\n  \u003csup\u003e[[link](#exception-message)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  raise ArgumentError, \"Malformed payload.\"\n\n  # Good\n  raise ArgumentError, \"malformed payload\"\n  ```\n\n  There is one exception to the rule - always capitalize Mix error messages.\n\n  ```elixir\n  Mix.raise(\"Could not find dependency\")\n  ```\n\n### ExUnit\n\n* \u003ca name=\"exunit-assertion-side\"\u003e\u003c/a\u003e\n  When asserting (or refuting) something with comparison operators (such as `==`, `\u003c`, `\u003e=`, and similar), put the expression being tested on the left-hand side of the operator and the value you're testing against on the right-hand side.\n  \u003csup\u003e[[link](#exunit-assertion-side)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  assert \"héllo\" == Atom.to_string(:\"héllo\")\n\n  # Good\n  assert Atom.to_string(:\"héllo\") == \"héllo\"\n  ```\n\n  When using the match operator `=`, put the pattern on the left-hand side (as it won't work otherwise).\n\n  ```elixir\n  assert {:error, _reason} = File.stat(\"./non_existent_file\")\n  ```\n\n## Formatting\n\nThe rules below are automatically applied by the code formatter in Elixir v1.6.\nThey are provided here for documentation purposes and for those maintaining older codebases.\n\n### Whitespace\n\n\u003e  Whitespace might be (mostly) irrelevant to the Elixir compiler, but its proper use is the key to writing easily readable code.\n\n* \u003ca name=\"no-trailing-whitespaces\"\u003e\u003c/a\u003e\n  Avoid trailing whitespaces.\n  \u003csup\u003e[[link](#no-trailing-whitespaces)]\u003c/sup\u003e\n\n* \u003ca name=\"newline-eof\"\u003e\u003c/a\u003e\n  End each file with a newline.\n  \u003csup\u003e[[link](#newline-eof)]\u003c/sup\u003e\n\n* \u003ca name=\"spaces-indentation\"\u003e\u003c/a\u003e\n  Use two __spaces__ per indentation level. No hard tabs.\n  \u003csup\u003e[[link](#spaces-indentation)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  def register_attribute(name, opts) do\n      register_attribute(__MODULE__, name, opts)\n  end\n\n  # Good\n  def register_attribute(name, opts) do\n    register_attribute(__MODULE__, name, opts)\n  end\n  ```\n\n* \u003ca name=\"spaces-in-code\"\u003e\u003c/a\u003e\n  Use a space before and after binary operators. Use a space after commas `,`, colons `:`, and semicolons `;`. Do not put spaces around matched pairs like brackets `[]`, braces `{}`, and so on.\n  \u003csup\u003e[[link](#spaces-in-code)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  sum = 1+1\n  [first|rest] = 'three'\n  {a1,a2} = {2 ,3}\n  Enum.join( [ \"one\" , \u003c\u003c \"two\" \u003e\u003e, sum ])\n\n  # Good\n  sum = 1 + 2\n  [first | rest] = 'three'\n  {a1, a2} = {2, 3}\n  Enum.join([\"one\", \u003c\u003c\"two\"\u003e\u003e, sum])\n  ```\n\n* \u003ca name=\"no-spaces-in-code\"\u003e\u003c/a\u003e\n  Use no spaces after unary operators and inside range literals. The only exception is the `not` operator: use a space after it.\n  \u003csup\u003e[[link](#no-spaces-in-code)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  angle = - 45\n  ^ result = Float.parse(\"42.01\")\n\n  # Good\n  angle = -45\n  ^result = Float.parse(\"42.01\")\n  2 in 1..5\n  not File.exists?(path)\n  ```\n\n* \u003ca name=\"default-arguments\"\u003e\u003c/a\u003e\n  Use spaces around default arguments `\\\\` definition.\n  \u003csup\u003e[[link](#default-arguments)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  def start_link(fun, options\\\\[])\n\n  # Good\n  def start_link(fun, options \\\\ [])\n  ```\n\n* \u003ca name=\"bitstring-segment-options\"\u003e\u003c/a\u003e\n  Do not put spaces around segment options definition in bitstrings.\n  \u003csup\u003e[[link](#bitstring-segment-options)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  \u003c\u003c102 :: unsigned-big-integer, rest :: binary\u003e\u003e\n  \u003c\u003c102::unsigned - big - integer, rest::binary\u003e\u003e\n\n  # Good\n  \u003c\u003c102::unsigned-big-integer, rest::binary\u003e\u003e\n  ```\n\n* \u003ca name=\"leading-space-comment\"\u003e\u003c/a\u003e\n  Use one space between the leading `#` character of the comment and the text of the comment.\n  \u003csup\u003e[[link](#leading-space-comment)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  #Amount to take is greater than the number of elements\n\n  # Good\n  # Amount to take is greater than the number of elements\n  ```\n\n* \u003ca name=\"space-before-anonymous-fun-arrow\"\u003e\u003c/a\u003e\n  Always use a space before `-\u003e` in 0-arity anonymous functions.\n  \u003csup\u003e[[link](#space-before-anonymous-fun-arrow)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  Task.async(fn-\u003e\n    ExUnit.Diff.script(left, right)\n  end)\n\n  # Good\n  Task.async(fn -\u003e\n    ExUnit.Diff.script(left, right)\n  end)\n  ```\n\n### Indentation\n\n* \u003ca name=\"binary-ops-indentation\"\u003e\u003c/a\u003e\n  \u003ca name=\"guard-clauses\"\u003e\u003c/a\u003e\n  Indent the right-hand side of a binary operator one level more than the left-hand side if left-hand side and right-hand side are on different lines. The only exceptions are `when` in guards and `|\u003e`, which go on the beginning of the line and should be indented at the same level as their left-hand side. Do this also for binary operators when assigning.\n  \u003csup\u003e[[link](#binary-ops-indentation)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n\n  \"No matching message.\\n\" \u003c\u003e\n  \"Process mailbox:\\n\" \u003c\u003e\n  mailbox\n\n  message =\n    \"No matching message.\\n\" \u003c\u003e\n    \"Process mailbox:\\n\" \u003c\u003e\n    mailbox\n\n  input\n    |\u003e String.strip()\n    |\u003e String.downcase()\n\n  defp valid_identifier_char?(char)\n    when char in ?a..?z\n      when char in ?A..?Z\n      when char in ?0..?9\n      when char == ?_ do\n    true\n  end\n\n  defp parenless_capture?({op, _meta, _args})\n       when is_atom(op) and\n       atom not in @unary_ops and\n       atom not in @binary_ops do\n    true\n  end\n\n  # Good\n\n  \"No matching message.\\n\" \u003c\u003e\n    \"Process mailbox:\\n\" \u003c\u003e\n    mailbox\n\n  message =\n    \"No matching message.\\n\" \u003c\u003e\n      \"Process mailbox:\\n\" \u003c\u003e\n      mailbox\n\n  input\n  |\u003e String.strip()\n  |\u003e String.downcase()\n\n  defp valid_identifier_char?(char)\n       when char in ?a..?z\n       when char in ?A..?Z\n       when char in ?0..?9\n       when char == ?_ do\n    true\n  end\n\n  defp parenless_capture?({op, _meta, _args})\n       when is_atom(op) and\n              atom not in @unary_ops and\n              atom not in @binary_ops do\n    true\n  end\n  ```\n\n* \u003ca name=\"with-indentation\"\u003e\u003c/a\u003e\n  Use the indentation shown below for the `with` special form:\n  \u003csup\u003e[[link](#with-indentation)]\u003c/sup\u003e\n\n  ```elixir\n  with {year, \"\"} \u003c- Integer.parse(year),\n       {month, \"\"} \u003c- Integer.parse(month),\n       {day, \"\"} \u003c- Integer.parse(day) do\n    new(year, month, day)\n  else\n    _ -\u003e\n      {:error, :invalid_format}\n  end\n  ```\n\n  Always use the indentation above if there's an `else` option. If there isn't, the following indentation works as well:\n\n  ```elixir\n  with {:ok, date} \u003c- Calendar.ISO.date(year, month, day),\n       {:ok, time} \u003c- Time.new(hour, minute, second, microsecond),\n       do: new(date, time)\n  ```\n\n* \u003ca name=\"for-indentation\"\u003e\u003c/a\u003e\n  Use the indentation shown below for the `for` special form:\n  \u003csup\u003e[[link](#for-indentation)]\u003c/sup\u003e\n\n  ```elixir\n  for {alias, _module} \u003c- aliases_from_env(server),\n      [name] = Module.split(alias),\n      starts_with?(name, hint),\n      into: [] do\n    %{kind: :module, type: :alias, name: name}\n  end\n  ```\n\n  If the body of the `do` block is short, the following indentation works as well:\n\n  ```elixir\n  for partition \u003c- 0..(partitions - 1),\n      pair \u003c- safe_lookup(registry, partition, key),\n      into: [],\n      do: pair\n  ```\n\n* \u003ca name=\"expression-group-alignment\"\u003e\u003c/a\u003e\n  Avoid aligning expression groups:\n  \u003csup\u003e[[link](#expression-group-alignment)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  module = env.module\n  arity  = length(args)\n\n  def inspect(false), do: \"false\"\n  def inspect(true),  do: \"true\"\n  def inspect(nil),   do: \"nil\"\n\n  # Good\n  module = env.module\n  arity = length(args)\n\n  def inspect(false), do: \"false\"\n  def inspect(true), do: \"true\"\n  def inspect(nil), do: \"nil\"\n  ```\n\n  The same non-alignment rule applies to `\u003c-` and `-\u003e` clauses as well.\n\n* \u003ca name=\"pipeline-indentation\"\u003e\u003c/a\u003e\n  Use a single level of indentation for multi-line pipelines.\n  \u003csup\u003e[[link](#pipeline-indentation)]\u003c/sup\u003e\n\n  ```elixir\n  input\n  |\u003e String.strip()\n  |\u003e String.downcase()\n  |\u003e String.slice(1, 3)\n  ```\n\n### Term representation\n\n* \u003ca name=\"underscores-in-numerics\"\u003e\u003c/a\u003e\n  Add underscores to decimal literals that have six or more digits.\n  \u003csup\u003e[[link](#underscores-in-numerics)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  num = 1000000\n  num = 1_500\n\n  # Good\n  num = 1_000_000\n  num = 1500\n  ```\n\n* \u003ca name=\"hex-literals\"\u003e\u003c/a\u003e\n  Use uppercase letters when using hex literals.\n  \u003csup\u003e[[link](#hex-literals)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  \u003c\u003c0xef, 0xbb, 0xbf\u003e\u003e\n\n  # Good\n  \u003c\u003c0xEF, 0xBB, 0xBF\u003e\u003e\n  ```\n\n* \u003ca name=\"quotes-around-atoms\"\u003e\u003c/a\u003e\n  When using atom literals that need to be quoted because they contain characters that are invalid in atoms (such as `:\"foo-bar\"`), use double quotes around the atom name:\n  \u003csup\u003e[[link](#quotes-around-atoms)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  :'foo-bar'\n  :'atom number #{index}'\n\n  # Good\n  :\"foo-bar\"\n  :\"atom number #{index}\"\n  ```\n\n* \u003ca name=\"trailing-comma\"\u003e\u003c/a\u003e\n  When dealing with lists, maps, structs, or tuples whose elements span over multiple lines and are on separate lines with regard to the enclosing brackets, it's advised to *not* use a trailing comma on the last element:\n  \u003csup\u003e[[link](#trailing-comma)]\u003c/sup\u003e\n\n  ```elixir\n  [\n    :foo,\n    :bar,\n    :baz\n  ]\n  ```\n\n### Parentheses\n\n* \u003ca name=\"zero-arity-parens\"\u003e\u003c/a\u003e\n  Parentheses are a must for __local__ or __imported__ zero-arity function calls.\n  \u003csup\u003e[[link](#zero-arity-parens)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  pid = self\n  import System, only: [schedulers_online: 0]\n  schedulers_online\n\n  # Good\n  pid = self()\n  import System, only: [schedulers_online: 0]\n  schedulers_online()\n  ```\n\n  The same should be done for __remote__ zero-arity function calls:\n\n  ```elixir\n  # Bad\n  Mix.env\n\n  # Good\n  Mix.env()\n  ```\n\n  This rule also applies to one-arity function calls (both local and remote) in pipelines:\n\n  ```elixir\n  # Bad\n  input\n  |\u003e String.strip\n  |\u003e decode\n\n  # Good\n  input\n  |\u003e String.strip()\n  |\u003e decode()\n  ```\n\n* \u003ca name=\"anonymous-fun-parens\"\u003e\u003c/a\u003e\n  Never wrap the arguments of anonymous functions in parentheses.\n  \u003csup\u003e[[link](#anonymous-fun-parens)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  Agent.get(pid, fn(state) -\u003e state end)\n  Enum.reduce(numbers, fn(number, acc) -\u003e\n    acc + number\n  end)\n\n  # Good\n  Agent.get(pid, fn state -\u003e state end)\n  Enum.reduce(numbers, fn number, acc -\u003e\n    acc + number\n  end)\n  ```\n\n* \u003ca name=\"fun-parens\"\u003e\u003c/a\u003e\n  Always use parentheses around arguments to definitions (such as `def`, `defp`, `defmacro`, `defmacrop`, `defdelegate`). Don't omit them even when a function has no arguments.\n  \u003csup\u003e[[link](#fun-parens)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  def main arg1, arg2 do\n    # ...\n  end\n\n  defmacro env do\n    # ...\n  end\n\n  # Good\n  def main(arg1, arg2) do\n    # ...\n  end\n\n  defmacro env() do\n    # ...\n  end\n  ```\n\n* \u003ca name=\"parens-in-zero-arity-types\"\u003e\u003c/a\u003e\n  Always use parens on zero-arity types.\n  \u003csup\u003e[[link](#parens-in-zero-arity-types)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  @spec start_link(module, term, Keyword.t) :: on_start\n\n  # Good\n  @spec start_link(module(), term(), Keyword.t()) :: on_start()\n  ```\n\n### Layout\n\n* \u003ca name=\"no-semicolon\"\u003e\u003c/a\u003e\n  Use one expression per line. Don't use semicolons (`;`) to separate statements and expressions.\n  \u003csup\u003e[[link](#no-semicolon)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  stacktrace = System.stacktrace(); fun.(stacktrace)\n\n  # Good\n  stacktrace = System.stacktrace()\n  fun.(stacktrace)\n  ```\n\n* \u003ca name=\"multi-line-expr-assignment\"\u003e\u003c/a\u003e\n  When assigning the result of a multi-line expression, begin the expression on a new line.\n  \u003csup\u003e[[link](#multi-line-expr-assignment)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n  {found, not_found} = files\n                       |\u003e Enum.map(\u0026Path.expand(\u00261, path))\n                       |\u003e Enum.partition(\u0026File.exists?/1)\n\n  prefix = case base do\n             :binary -\u003e \"0b\"\n             :octal -\u003e \"0o\"\n             :hex -\u003e \"0x\"\n           end\n\n  # Good\n  {found, not_found} =\n    files\n    |\u003e Enum.map(\u0026Path.expand(\u00261, path))\n    |\u003e Enum.partition(\u0026File.exists?/1)\n\n  prefix =\n    case base do\n      :binary -\u003e \"0b\"\n      :octal -\u003e \"0o\"\n      :hex -\u003e \"0x\"\n    end\n  ```\n\n* \u003ca name=\"binary-operators-at-eols\"\u003e\u003c/a\u003e\n  When writing a multi-line expression, keep binary operators at the end of each line. The only exception is the `|\u003e` operator (which goes at the beginning of the line).\n  \u003csup\u003e[[link](#binary-operators-at-eols)]\u003c/sup\u003e\n\n  ```elixir\n  # Bad\n\n  \"No matching message.\\n\"\n    \u003c\u003e \"Process mailbox:\\n\"\n    \u003c\u003e mailbox\n\n  input |\u003e\n    String.strip() |\u003e\n    decode()\n\n  # Good\n  \"No matching message.\\n\" \u003c\u003e\n    \"Process mailbox:\\n\" \u003c\u003e\n    mailbox\n\n  input\n  |\u003e String.strip()\n  |\u003e decode()\n  ```\n\n## License\n\nThis work was created by Aleksei Magusev and is licensed under [the CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0).\n\n![Creative Commons License](http://i.creativecommons.org/l/by/4.0/88x31.png)\n\n## Credits\n\nThe structure of the guide and some points that are applicable to Elixir were taken from [the community-driven Ruby coding style guide](https://github.com/bbatsov/ruby-style-guide).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexmag%2Felixir-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flexmag%2Felixir-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexmag%2Felixir-style-guide/lists"}