LoginSignup
18

More than 5 years have passed since last update.

[翻訳] The Elixir Style Guide 

Last updated at Posted at 2016-12-02

lexmagさん(Elixirコミッター)の The Elixir Style Guide を翻訳しました。

Elixir Style Guide

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

Table of Contents

コードレイアウト

  • インデントはスペース2つ。ハードタブは使わないこと。[link]

  • 一行につき式は一つ。命令や式を区切るのに;を使ってはいけない。[link]

  • - バイナリオペレータの前後、カンマ、コロン、セミコロンの後にはスペースを入れてください。

    • []{}の間にはスペースを入れないでください。
    • Elixirの処理系にとって空白にほとんど意味はありませんが、コードを読みやすくするためには重要です。 [link]
  sum = 1 + 2
  [first | rest] = 'three'
  {a1, a2} = {2, 3}
  Enum.join(["one", <<"two">>, sum])
  • 単項演算子やレンジリテラルの後にスペースを入れていはいけない。ただしnot演算子だけは例外とする。 [link]
  angle = -45
  ^result = Float.parse("42.01")
  2 in 1..5
  not File.exists?(path)
  • デフォルト引数\\の前後にスペースを入れること。[link]

  • バイナリ列の範囲指定オプションにスペースを入れてはいけない。[link]

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

  # 良い例
  <<102::unsigned-big-integer, rest::binary>>
  • whenガード節は関数、マクロ宣言と同じレベルにインデントすること。 これはwhenガードが関数宣言と同じ行に収まらない場合のみ適用します。 [link]
  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
  • 複数行の式の結果を受け取るときは右辺で整列させないでください。[link]
  # 悪い例
  {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
  • 大きい桁の整数には_を入れて読みやすくしましょう。 [link]
  num = 1_000_000
  • :"foo-bar"のようにアトムに無効な文字が含まれている場合はダブルクォートで囲うこと。 [link]
  # 悪い例
  :'foo-bar'
  :'atom number #{index}'

  # 良い例
  :"foo-bar"
  :"atom number #{index}"
  • 行末に不要な空白を入れないこと[link]

  • ファイルの終わりには空行をいれること。[link]

  • リスト、マップ、構造体、タプルなどが各要素ごとに改行されている場合は、最後の要素の末尾にもカンマを使用することをお勧めします。[link]

  [
    :foo,
    :bar,
    :baz,
  ]

シンタックス

  • def の引数は括弧で囲うこと。引数がない場合も省略しないこと。 [link]
  # 悪い例
  def main arg1, arg2 do
    #...
  end

  def main do
    #...
  end

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

  def main() do
    #...
  end
  • ローカルの関数宣言や呼び出しは引数がない場合も括弧を使うこと [link]
  # 悪い例
  pid = self
  def new, do: %MapSet{}

  # 良い例
  pid = self()
  def new(), do: %MapSet{}
  config = IEx.Config.new

同じことがパイプライン演算子内のローカル関数呼び出しにも当てはまります。

  String.strip(input) |> decode()
  • 関数のチェインにはパイプライン演算子|>を使ってください。[link]
  # 悪い例
  String.downcase(String.strip(input))

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

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

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

無意味にパイプライン演算子を使わないこと。 [link]

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

  # 良い例
  result = String.strip(input)
  • 複数行の式の場合は、行末にバイナリ連結演算子 を書きます(唯一の例外は |>演算子) [link]
  # 悪い例
  "No matching message.\n"
  <> "Process mailbox:\n"
  <> mailbox

  # 良い例
  "No matching message.\n" <>
  "Process mailbox:\n" <>
  mailbox
  • unlesselseを使ってはいけない。 正常系が最初に来るように書き直してください。[link]
  # 悪い例
  unless Enum.empty?(coll) do
    :ok
  else
    :error
  end

  # 良い例
  if Enum.empty?(coll) do
    :error
  else
    :ok
  end
  • もし nilを返すならifunless節にelseオプションを指定しないでください。 [link]
  # 悪い例
  if byte_size(data) > 0, do: data, else: nil

  # 良い例
  if byte_size(data) > 0, do: data
  • cond構文の最後の条件は常にtrueを使うこと。 [link]
  # 悪い例
  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
  • 厳密な真偽値チェックには ||&&を使わないでください。いずれかの引数が真偽値でない場合にのみ、これらの演算子を使用します。 [link]
  # 悪い例
  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"
  • バイナリのパターンマッチにはビット文字列構文よりもバイナリ連結演算子 <>を使うようにする。 [link]
  # 悪い例
  <<"http://", _rest::bytes>> = input
  <<first::utf8, rest::bytes>> = input

  # 良い例
  "http://" <> _rest = input
  <<first::utf8>> <> rest = input
  • 16進数の定義には大文字を使うこと。 [link]
  # 悪い例
  <<0xef, 0xbb, 0xbf>>

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

命名

  • アトム、関数、変数、モジュール属性には snake_case を使うこと。 [link]
  # 悪い例
  :"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
  • モジュール名はCamelCaseを使うこと。 [link]
  # 悪い例
  defmodule :appStack do
    #...
  end

  defmodule App_Stack do
    #...
  end

  defmodule Appstack do
    #...
  end

  # 良い例
  defmodule AppStack do
    #...
  end
  • 述語関数(ブール値を返す関数)の名前は、接頭辞 has_またはそれに類するものではなく、疑問符「?」をつけなければなりません。[link]
  def leap?(year) do
    #...
  end

ガード節で使う述語マクロにはis_接頭辞をつけること。

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

  • ディレクトリやファイルの名前には snake_caseを使います。 lib / my_app / task_server.exなど。[link]


  • 一文字の変数名を使ってはいけない。[link]

コメント

良いコードはいいジョークみたいなものだ。なんの説明もいらない。
— Russ Olsen

  • 自己説明的で、コメントのいらないコードを書いてこのセクションの残りは無視してください(本気です!) [link]

  • # とコメントの間にスペースを一つ入れること。[link]

  • 不要なコメントは書かない。 [link]

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

モジュール

  • use /import / alias /requireを呼び出すときは一貫した構造を用います:この順番で呼び出し、それぞれをグループにします。 [link]
  use GenServer

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

  alias Mix.Utils
  alias MapSet, as: Set

  require Logger
  • モジュールが自身を参照するには__MODULE__疑似変数を使用すること。 [link]
  # 悪い例
  :ets.new(Kernel.LexicalTracker, [:named_table])
  GenServer.start_link(Module.LocalsTracker, nil, [])

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

正規表現

  • 正規表現は最後の手段です。まずはパターンマッチングと Stringモジュールを試しましょう。 [link]
  # 悪い例
  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"])
  • キャプチャの結果が必要がないならキャプチャしないグループを使うこと。 [link]
  ~r/(?:post|zip )code: (\d+)/
  • ^$は行の開始と終了にそれぞれマッチするので注意してください。 全ての文字列にマッチさせたい場合は、 \ A\ z\ n?\ zと等価な\Zと混同しないでください)を使います。 [link]

例外

  • 例外の名前はErrorで終わるようにすること。 [link]
  # 悪い例
  ResponseException

  # 良い例
  ResponseError
  • エラーメッセージは全て小文字で句読点を省いてください [link]
  # 悪い例
  raise ArgumentError, "Malformed payload."

  # 良い例
  raise ArgumentError, "malformed payload"

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

  Mix.raise "Could not find dependency"

License

This work was created by Aleksei Magusev and is licensed under the CC BY 4.0 license.

Creative Commons License

Credits

The structure of the guide and some points that are applicable to Elixir were taken from the community-driven Ruby coding style guide.

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18