[翻訳] The Elixir Style Guide　

lexmagさん（Elixirコミッター)の [The Elixir Style Guide](https://github.com/lexmag/elixir-style-guide) を翻訳しました。 



# Elixir Style Guide

> プログラマの仕事はコードを書くことよりも、むしろ問題解決の方法について別のプログラマに伝えることです。これが技術者としての成熟の最終段階です。
> — <cite>What a Programmer Does, 1967</cite>


## Table of Contents

* [コードレイアウト](#source-code-layout)
* [シンタックス](#syntax)
* [命名](#naming)
* [コメント](#comments)
* [モジュール](#modules)
* [正規表現](#regular-expressions)
* [例外](#exceptions)

### コードレイアウト

* <a name="spaces-indentation"></a>インデントはスペース2つ。ハードタブは使わないこと。<sup>[[link](#spaces-indentation)]</sup>

* <a name="no-semicolon"></a>一行につき式は一つ。命令や式を区切るのに`;`を使ってはいけない。<sup>[[link](#no-semicolon)]</sup>

* <a name="spaces-in-code"></a> - バイナリオペレータの前後、カンマ、コロン、セミコロンの後にはスペースを入れてください。
  - `[]`の`{}`の間にはスペースを入れないでください。
  - Elixirの処理系にとって空白にほとんど意味はありませんが、コードを読みやすくするためには重要です。
  <sup>[[link](#spaces-in-code)]</sup>

  ```elixir
  sum = 1 + 2
  [first | rest] = 'three'
  {a1, a2} = {2, 3}
  Enum.join(["one", <<"two">>, sum])
  ```

* <a name="no-spaces-in-code"></a> 単項演算子やレンジリテラルの後にスペースを入れていはいけない。ただし`not`演算子だけは例外とする。
  <sup>[[link](#no-spaces-in-code)]</sup>

  ```elixir
  angle = -45
  ^result = Float.parse("42.01")
  2 in 1..5
  not File.exists?(path)
  ```

* <a name="default-arguments"></a>デフォルト引数`\\`の前後にスペースを入れること。<sup>[[link](#default-arguments)]</sup>

* <a name="bitstring-segment-options"></a> バイナリ列の範囲指定オプションにスペースを入れてはいけない。<sup>[[link](#bitstring-segment-options)]</sup>

  ```elixir
  # 悪い例
  <<102 :: unsigned-big-integer, rest :: binary>>
  <<102::unsigned - big - integer, rest::binary>>

  # 良い例
  <<102::unsigned-big-integer, rest::binary>>
  ```

* <a name="guard-clauses"></a>`when`ガード節は関数、マクロ宣言と同じレベルにインデントすること。
これは`when`ガードが関数宣言と同じ行に収まらない場合のみ適用します。 <sup>[[link](#guard-clauses)]</sup>

  ```elixir
  def format_error({exception, stacktrace})
      when is_list(stacktrace) and stacktrace != [] do
    # ...
  end

  defmacro dngettext(domain, msgid, msgid_plural, count)
           when is_binary(msgid) and is_binary(msgid_plural) do
    # ...
  end
  ```

* <a name="multi-line-expr-assignment"></a>複数行の式の結果を受け取るときは右辺で整列させないでください。<sup>[[link](#multi-line-expr-assignment)]</sup>

  ```elixir
  # 悪い例
  {found, not_found} = Enum.map(files, &Path.expand(&1, path))
                       |> Enum.partition(&File.exists?/1)

  prefix = case base do
             :binary -> "0b"
             :octal  -> "0o"
             :hex    -> "0x"
           end

  # 良い例
  {found, not_found} =
    Enum.map(files, &Path.expand(&1, path))
    |> Enum.partition(&File.exists?/1)

  prefix = case base do
    :binary -> "0b"
    :octal  -> "0o"
    :hex    -> "0x"
  end
  ```

* <a name="underscores-in-numerics"></a>
大きい桁の整数には`_`を入れて読みやすくしましょう。
  <sup>[[link](#underscores-in-numerics)]</sup>

  ```elixir
  num = 1_000_000
  ```

* <a name="quotes-around-atoms"></a>
`:"foo-bar"`のようにアトムに無効な文字が含まれている場合はダブルクォートで囲うこと。 
  <sup>[[link](#quotes-around-atoms)]</sup>

  ```elixir
  # 悪い例
  :'foo-bar'
  :'atom number #{index}'

  # 良い例
  :"foo-bar"
  :"atom number #{index}"
  ```

* <a name="no-trailing-whitespaces"></a>行末に不要な空白を入れないこと<sup>[[link](#no-trailing-whitespaces)]</sup>

* <a name="newline-eof"></a>ファイルの終わりには空行をいれること。<sup>[[link](#newline-eof)]</sup>

* <a name="trailing-comma"></a>リスト、マップ、構造体、タプルなどが各要素ごとに改行されている場合は、最後の要素の末尾にもカンマを使用することをお勧めします。<sup>[[link](#trailing-comma)]</sup>

  ```elixir
  [
    :foo,
    :bar,
    :baz,
  ]
  ```

### シンタックス

* <a name="fun-parens"></a>
`def` の引数は括弧で囲うこと。引数がない場合も省略しないこと。
  <sup>[[link](#fun-parens)]</sup>

  ```elixir
  # 悪い例
  def main arg1, arg2 do
    #...
  end

  def main do
    #...
  end

  # 良い例
  def main(arg1, arg2) do
    #...
  end

  def main() do
    #...
  end
  ```

* <a name="zero-arity-parens"></a>
__ローカル__の関数宣言や呼び出しは引数がない場合も括弧を使うこと
  <sup>[[link](#zero-arity-parens)]</sup>

  ```elixir
  # 悪い例
  pid = self
  def new, do: %MapSet{}

  # 良い例
  pid = self()
  def new(), do: %MapSet{}
  config = IEx.Config.new
  ```
同じことがパイプライン演算子内の__ローカル__関数呼び出しにも当てはまります。

  ```elixir
  String.strip(input) |> decode()
  ```

* <a name="pipeline-operator"></a>関数のチェインにはパイプライン演算子`|>`を使ってください。<sup>[[link](#pipeline-operator)]</sup>

  ```elixir
  # 悪い例
  String.downcase(String.strip(input))

  # 良い例
  input |> String.strip |> String.downcase
  String.strip(input) |> String.downcase
  ```

複数行のパイプラインはインデント一つで揃えます。

  ```elixir
  String.strip(input)
  |> String.downcase
  |> String.slice(1, 3)
  ```

  <a name="needless-pipeline"></a>無意味にパイプライン演算子を使わないこと。 <sup>[[link](#needless-pipeline)]</sup>

  ```elixir
  # 悪い例
  result = input |> String.strip

  # 良い例
  result = String.strip(input)
  ```

* <a name="binary-operators-at-eols"></a>
  複数行の式の場合は、行末にバイナリ連結演算子 を書きます（唯一の例外は `|>`演算子）
  <sup>[[link](#binary-operators-at-eols)]</sup>

  ```elixir
  # 悪い例
  "No matching message.\n"
  <> "Process mailbox:\n"
  <> mailbox

  # 良い例
  "No matching message.\n" <>
  "Process mailbox:\n" <>
  mailbox
  ```

* <a name="no-else-with-unless"></a>
`unless` に `else`を使ってはいけない。 正常系が最初に来るように書き直してください。<sup>[[link](#no-else-with-unless)]</sup>

  ```elixir
  # 悪い例
  unless Enum.empty?(coll) do
    :ok
  else
    :error
  end

  # 良い例
  if Enum.empty?(coll) do
    :error
  else
    :ok
  end
  ```

* <a name="no-nil-else"></a>
もし `nil`を返すなら` if`と `unless`節に` else`オプションを指定しないでください。
  <sup>[[link](#no-nil-else)]</sup>

  ```elixir
  # 悪い例
  if byte_size(data) > 0, do: data, else: nil

  # 良い例
  if byte_size(data) > 0, do: data
  ```

* <a name="true-in-cond"></a>
`cond`構文の最後の条件は常に`true`を使うこと。
  <sup>[[link](#true-in-cond)]</sup>

  ```elixir
  # 悪い例
  cond do
    char in ?0..?9 -> char - ?0
    char in ?A..?Z -> char - ?A + 10
    :else          -> char - ?a + 10
  end

  # 良い例
  cond do
    char in ?0..?9 -> char - ?0
    char in ?A..?Z -> char - ?A + 10
    true           -> char - ?a + 10
  end
  ```

* <a name="boolean-operators"></a>
  厳密な真偽値チェックには `||`、 `&&`、 `！`を使わないでください。いずれかの引数が真偽値でない場合にのみ、これらの演算子を使用します。
  <sup>[[link](#boolean-operators)]</sup>

  ```elixir
  # 悪い例
  is_atom(name) && name != nil
  is_binary(task) || is_atom(task)

  # 良い例
  is_atom(name) and name != nil
  is_binary(task) or is_atom(task)
  line && line != 0
  file || "sample.exs"
  ```

* <a name="patterns-matching-binaries"></a>
バイナリのパターンマッチにはビット文字列構文よりもバイナリ連結演算子 `<>`を使うようにする。
  <sup>[[link](#patterns-matching-binaries)]</sup>

  ```elixir
  # 悪い例
  <<"http://", _rest::bytes>> = input
  <<first::utf8, rest::bytes>> = input

  # 良い例
  "http://" <> _rest = input
  <<first::utf8>> <> rest = input
  ```

* <a name="hex-literals"></a>
16進数の定義には大文字を使うこと。
  <sup>[[link](#hex-literals)]</sup>

  ```elixir
  # 悪い例
  <<0xef, 0xbb, 0xbf>>

  # 良い例
  <<0xEF, 0xBB, 0xBF>>
  ```

### 命名

* <a name="snake-case-atoms-funs-vars-attrs"></a>
アトム、関数、変数、モジュール属性には `snake_case` を使うこと。
  <sup>[[link](#snake-case-atoms-funs-vars-attrs)]</sup>

  ```elixir
  # 悪い例
  :"no match"
  :Error
  :badReturn

  fileName = "sample.txt"

  @_VERSION "0.0.1"

  def readFile(path) do
    #...
  end

  # 良い例
  :no_match
  :error
  :bad_return

  file_name = "sample.txt"

  @version "0.0.1"

  def read_file(path) do
    #...
  end
  ```

* <a name="camelcase-modules"></a>
モジュール名は`CamelCase`を使うこと。
  <sup>[[link](#camelcase-modules)]</sup>

  ```elixir
  # 悪い例
  defmodule :appStack do
    #...
  end

  defmodule App_Stack do
    #...
  end

  defmodule Appstack do
    #...
  end

  # 良い例
  defmodule AppStack do
    #...
  end
  ```

* <a name="predicate-funs-name"></a>
述語関数（ブール値を返す関数）の名前は、接頭辞 `has_`またはそれに類するものではなく、疑問符「？」をつけなければなりません。<sup>[[link](#predicate-funs-name)]</sup>

  ```elixir
  def leap?(year) do
    #...
  end
  ```
ガード節で使う述語マクロには`is_`接頭辞をつけること。

  ```elixir
  defmacro is_date(month, day) do
    #...
  end
  ```

* <a name="snake-case-dirs-files"></a>
ディレクトリやファイルの名前には `snake_case`を使います。 `lib / my_app / task_server.ex`など。<sup>[[link](#snake-case-dirs-files)]</sup>

* <a name="one-letter-var"></a>
一文字の変数名を使ってはいけない。<sup>[[link](#one-letter-var)]</sup>

### コメント
> 良いコードはいいジョークみたいなものだ。なんの説明もいらない。
> — <cite>Russ Olsen</cite>

* <a name="no-need-for-comments"></a> 自己説明的で、コメントのいらないコードを書いてこのセクションの残りは無視してください(本気です！) <sup>[[link](#no-need-for-comments)]</sup>

* <a name="leading-space-comment"></a> `#` とコメントの間にスペースを一つ入れること。<sup>[[link](#leading-space-comment)]</sup>

* <a name="no-superfluous-comments"></a> 不要なコメントは書かない。 <sup>[[link](#no-superfluous-comments)]</sup>

  ```elixir
  # 悪い例
  String.first(input) # 最初の文字を取り出す.
  ```

### モジュール

* <a name="module-layout"></a> `use` /` import` / `alias` /` require`を呼び出すときは一貫した構造を用います：この順番で呼び出し、それぞれをグループにします。
  <sup>[[link](#module-layout)]</sup>

  ```elixir
  use GenServer

  import Bitwise
  import Kernel, except: [length: 1]

  alias Mix.Utils
  alias MapSet, as: Set

  require Logger
  ```

* <a name="current-module-reference"></a> モジュールが自身を参照するには`__MODULE__`疑似変数を使用すること。
  <sup>[[link](#current-module-reference)]</sup>

  ```elixir
  # 悪い例
  :ets.new(Kernel.LexicalTracker, [:named_table])
  GenServer.start_link(Module.LocalsTracker, nil, [])

  # 良い例
  :ets.new(__MODULE__, [:named_table])
  GenServer.start_link(__MODULE__, nil, [])
  ```

### 正規表現

* <a name="pattern-matching-over-regexp"></a> 正規表現は最後の手段です。まずはパターンマッチングと `String`モジュールを試しましょう。
  <sup>[[link](#pattern-matching-over-regexp)]</sup>


  ```elixir
  # 悪い例
  Regex.run(~r/#(\d{2})(\d{2})(\d{2})/, color)
  Regex.match?(~r/(email|password)/, input)

  # 良い例
  <<?#, p1::2-bytes, p2::2-bytes, p3::2-bytes>> = color
  String.contains?(input, ["email", "password"])
  ```

* <a name="non-capturing-regexp"></a>キャプチャの結果が必要がないならキャプチャしないグループを使うこと。
  <sup>[[link](#non-capturing-regexp)]</sup>

  ```elixir
  ~r/(?:post|zip )code: (\d+)/
  ```

* <a name="caret-and-dollar-regexp"></a>`^`と `$`は行の開始と終了にそれぞれマッチするので注意してください。 全ての文字列にマッチさせたい場合は、 `\ A`と` \ z`（ `\ n？\ z`と等価な` \Z`と混同しないでください）を使います。
  <sup>[[link](#caret-and-dollar-regexp)]</sup>

### 例外

* <a name="exception-naming"></a> 例外の名前は`Error`で終わるようにすること。
  <sup>[[link](#exception-naming)]</sup>

  ```elixir
  # 悪い例
  ResponseException

  # 良い例
  ResponseError
  ```

* <a name="exception-message"></a> エラーメッセージは全て小文字で句読点を省いてください
  <sup>[[link](#exception-message)]</sup>

  ```elixir
  # 悪い例
  raise ArgumentError, "Malformed payload."

  # 良い例
  raise ArgumentError, "malformed payload"
  ```

例外として、Mixのエラーメッセージだけは常に大文字から始めます。

  ```elixir
  Mix.raise "Could not find dependency"
  ```

## License

This work was created by Aleksei Magusev and is licensed under [the CC BY 4.0 license](https://creativecommons.org/licenses/by/4.0).

![Creative Commons License](http://i.creativecommons.org/l/by/4.0/88x31.png)

## Credits

The 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).