まるでジャズみたいに一緒に即興で演奏するんだ。 私が何かを作って、彼らも何かを作ることで答える
-フランク・ゲーリー
スタイルは重要です。 Elixir には実に様々なスタイルがありますが、他の言語と同じように無視されがちです。 スタイルを尊重しましょう。
これは、プログラミング言語 Elixir のコミュニティスタイルガイドを作ろうという試みです。気軽にプルリクエストを送ってください。 実際より5倍も長生きしている言語のようにElixirのコミュニティを活発にしましょう。
もし他に貢献できるプロジェクトを探しているならHex package manager siteを見てみてください。
-
[link]
# 悪い例 - スペースが4つ def some_function do do_something end # 良い例 def some_function do do_something end
-
Unixスタイルの改行コードを使うこと (*BSD/Solaris/Linux/OSX ではこれがデフォルトです。Windowsを使っている場合は気をつけてください) [link]
-
Gitを使っている場合はWindowsの改行コードであなたのプロジェクトがめちゃくちゃになるのを防ぐために、このように設定してください。 [link]
git config --global core.autocrlf true
-
- オペレータの前後、カンマ、コロン、セミコロンの後にはスペースを入れてください。
- ()や[]の間にはスペースを入れないでください。
- Elixirの処理系にとって空白にほとんど意味はありませんが、コードを読みやすくするためには重要です。 [link]
sum = 1 + 2 {a, b} = {2, 3} Enum.map(["one", <<"two">>, "three"], fn num -> IO.puts num end)
-
def
の間や関数内のロジックの区切りに空白行を入れてください。 [link]def some_function(some_data) do altered_data = Module.function(data) end def some_function do result end def some_other_function do another_result end def a_longer_function do one two three four end
-
関数節に一行の
def
があるならまとめて定義してしまってもよい。 [link]def some_function(nil), do: {:err, "No Value"} def some_function([]), do: :ok def some_function([first|rest]) do some_function(rest) end
-
do:
を使った関数定義が長くなった場合は、改行後インデントしてからdo:
を入れてください。 [link]def some_function(args), do: Enum.map(args, fn(arg) -> arg <> " is on a very long line!" end)
上記の規約を使用した関数節があり、かつ他にdo:
を使った関数節がある場合は
すべての関数節で改行してから do:
を入れてください:
# 悪い例
def some_function([]), do: :empty
def some_function(_),
do: :very_long_line_here
# 良い例
def some_function([]),
do: :empty
def some_function(_),
do: :very_long_line_here
-
複数行の関数節が一つ以上ある場合は一行の
def
を使わないこと。 [link]def some_function(nil) do {:err, "No Value"} end def some_function([]) do :ok end def some_function([first|rest]) do some_function(rest) end def some_function([first|rest], opts) do some_function(rest, opts) end
-
関数のチェインにはパイプライン演算子を使ってください。 [link]
# 悪い例 String.strip(String.downcase(some_string)) # 良い例 some_string |> String.downcase |> String.strip # 複数行のパイプラインはインデントしないこと。 some_string |> String.downcase |> String.strip # パターンマッチの右辺として複数行のパイプラインを使う場合は改行してから書くこと。 sanitized_string = some_string |> String.downcase |> String.strip
これは好ましい書き方ですが少し注意が必要です。 IExが次の行にパイプラインがあることを認識せずに最初の行を評価するため、複数行のパイプラインをIExにコピーすると構文エラーが発生する可能性があります。
-
パイプライン演算子を一度だけ使うのをやめましょう。 [link]
# 悪い例 some_string |> String.downcase # 良い例 String.downcase(some_string)
-
関数チェインの最初の値は関数の戻り値ではなく、通常の変数を使ってください。 [link]
# これは最悪! # String.strip("nope" |> String.downcase).にパースされます String.strip "nope" |> String.downcase # 悪い例 String.strip(some_string) |> String.downcase |> String.codepoints # 良い例 some_string |> String.strip |> String.downcase |> String.codepoints
-
行末に余分な空白を入れないこと。 [link]
-
ファイルの終わりには空行を入れること。 [link]
-
def
が引数をとる場合は括弧を使うこと。引数がない場合は省略すること。 [link]# 悪い例 def some_function arg1, arg2 do # body omitted end def some_function() do # body omitted end # 良い例 def some_function(arg1, arg2) do # body omitted end def some_function do # body omitted end
-
複数行の
if/unless
にdo:
を使ってはいけない。 [link]# 悪い例 if some_condition, do: # a line of code # another line of code # note no end in this block # 良い例 if some_condition do # some # lines # of code end
-
一行の
if/unless
にはdo:
を使うこと。 [link]# 良い例 if some_condition, do: # some_stuff
-
unless
にelse
を使ってはいけない。 正常系が最初に来るように書き直してください。 [link]# 悪い例 unless success? do IO.puts 'failure' else IO.puts 'success' end # 良い例 if success? do IO.puts 'success' else IO.puts 'failure' end
-
cond
構文の最後の条件は常にtrue
を使うこと。 [link]cond do 1 + 2 == 5 -> "Nope" 1 + 3 == 5 -> "Uh, uh" true -> "OK" end
-
関数名と括弧の間にはスペースを入れないこと。 [link]
# 悪い例 f (3 + 2) + 1 # 良い例 f(3 + 2) + 1
-
関数呼び出しには括弧を使うこと。特にパイプライン演算子の中では必ず使うこと。 [link]
# 悪い例 f 3 # 良い例 f(3) # 悪い例. rem(2, (3 |> g)) にパースされてしまう 2 |> rem 3 |> g # 良い例 2 |> rem(3) |> g
-
do
ブロックをとるマクロの呼び出しでは括弧を省略すること。 [link]# 悪い例 quote(do foo end) # 良い例 quote do foo end
-
引数の最後が関数の場合は括弧を省略してもよい。 [link]
# 良い例 Enum.reduce(1..10, 0, fn x, acc -> x + acc end) # これも良い例 Enum.reduce 1..10, 0, fn x, acc -> x + acc end
-
変数と区別するため引数がない関数呼び出しでも括弧を使うこと。 (Elixir 1.4からは、このようなあいまいな記述があった場合には警告を出すようになりました) [link]
defp do_stuff, do: ... # 悪い例 def my_func do do_stuff # 関数呼び出しなのか変数なのかわからない end # 良い例 def my_func do do_stuff() # 間違いなく関数呼び出し end
-
連続した
with
節はインデントを揃え、引数のdo:
を新しい行に入れてください。 [link]with {:ok, foo} <- fetch(opts, :foo), {:ok, bar} <- fetch(opts, :bar), do: {:ok, foo, bar}
-
with
に 複数行のdo
ブロックがある場合や、else
オプションがある場合は複数行の構文を使用してください。 [link]with {:ok, foo} <- fetch(opts, :foo), {:ok, bar} <- fetch(opts, :bar) do {:ok, foo, bar} else :error -> {:error, :bad_arg} end
-
アトム、関数、変数には
snake_case
を使うこと。 [link]# 悪い例 :"some atom" :SomeAtom :someAtom someVar = 5 def someFunction do ... end def SomeFunction do ... end # 良い例 :some_atom some_var = 5 def some_function do ... end
-
モジュール名は
CamelCase
を使うこと(HTTP, RFC, XMLなどの頭字語はそのままでよい) [link]# 悪い例 defmodule Somemodule do ... end defmodule Some_Module do ... end defmodule SomeXml do ... end # 良い例 defmodule SomeModule do ... end defmodule SomeXML do ... end
-
ガード内で使用できる述語マクロ(コンパイル時にbooleanを返す関数になるもの)には
is_
接頭辞をつけること。 ガード内で使用できる式については Expressions in Guard Clausesを参照してください。 [link]defmacro is_cool(var) do quote do: unquote(var) == "cool" end
-
ガード内で使わない述語関数は
is_
接頭辞ではなく末尾に?
をつけること。 [link]def cool?(var) do # Complex check if var is cool not possible in a pure function. end
-
パブリック関数と同名のプライベート関数を定義したい場合は
do_
を頭につけること。 [link]def sum(list), do: do_sum(list, 0) # private functions defp do_sum([], total), do: total defp do_sum([head|tail], total), do: do_sum(tail, head + total)
-
表現力豊かなコードを書いてください。 制御フロー、構造、命名を通じてプログラムの意図を伝えてください。 [link]
-
#
とコメントの間にスペースを一つ入れること。 [link] -
一語以上のコメントは先頭を大文字にして句読点を使うこと。 ピリオドの後にはスペースを一つ入れること。 [link]
# 悪い例 String.upcase(some_string) # Capitalize string.
-
注釈は関連するコードのすぐ上に書くこと。 [link]
-
注釈キーワードの後には: とスペースを入れてから本文を書いてください。 [link]
-
もし問題の説明が複数行になる場合は#の後にスペースを2つ入れてください。 [link]
-
もし問題が明らかな場合は注釈キーワードだけを該当行の最後に入れてください。 これは強制ではありません。 [link]
-
未実装や、将来の機能追加のための注釈には
TODO
を使ってください。 [link] -
壊れたコードの注釈には
FIXME
を使ってください。 [link] -
遅かったり、非効率的なコードの注釈には
OPTIMIZE
を使ってください。 [link] -
コードの書き方に疑問の残る箇所の注釈には
HACK
を使ってください。 [link] -
正しく動くか確認する必要があるコードの注釈には
REVIEW
を使ってください。 例:REVIEW: Are we sure this is how the client does X currently?
[link] -
もし必要があるようなら独自の注釈キーワードを使ってもかまいませんが、それらはプロジェクトの
README
などに書かれるべきでしょう。 [link]
-
モジュールは一つのファイルに一つだけ定義すること。 ただし内部的にのみ使用しているモジュール(テストなど) の場合はこの限りではない。 [link]
-
キャメルケースのモジュール名をアンダースコア化したファイル名にすること。 [link]
# file is called some_module.ex defmodule SomeModule do end
-
モジュール名のネストはディレクトリ構造を反映させること。 [link]
# file is called parser/core/xml_parser.ex defmodule Parser.Core.XMLParser do end
-
defmodule
の後に空行を入れてはいけない。 [link] -
モジュールレベルのコードブロックの後には空行を入れること。 [link]
-
モジュール内の定義順は下記のようにする。 [link]
@moduledoc
@behaviour
use
import
alias
require
defstruct
@type
@module_attribute
それぞれのグループの間には空白行を入れ、アルファベット順でソートしてください。 モジュール定義の例を以下に記します。
defmodule MyModule do @moduledoc """ An example module """ @behaviour MyBehaviour use GenServer import Something import SomethingElse alias My.Long.Module.Name alias My.Other.Module.Name require Integer defstruct name: nil, params: [] @type params :: [{binary, binary}] @module_attribute :foo @other_attribute 100 ... end
-
モジュールが自身を参照するには
__MODULE__
疑似変数を使用すること。 これならモジュール名が変更されてもコードの変更が要りません。 [link]defmodule SomeProject.SomeModule do defstruct [:name] def name(%__MODULE__{name: name}), do: name end
-
もしモジュール自身の参照にもっとわかりやすい名前を使いたければaliasを使うことができます。 [link]
defmodule SomeProject.SomeModule do alias __MODULE__, as: SomeModule defstruct [:name] def name(%SomeModule{name: name}), do: name end
Elixrのドキュメント(iex
の中でh
を入力するか、ExDocで作られたもの) はモジュールアトリビュートである @moduledoc
と @doc
を使います。
-
@moduledoc
は必ずdefmodule
の次の行に書くこと。 [link]# 悪い例 defmodule SomeModule do @moduledoc """ About the module """ ... end defmodule AnotherModule do use SomeModule @moduledoc """ About the module """ ... end # 良い例 defmodule SomeModule do @moduledoc """ About the module """ ... end
-
モジュールについてのドキュメントを書かない場合は
@moduledoc false
を使ってください。 [link]defmodule SomeModule do @moduledoc false ... end
-
@moduledoc
の後には空白行を入れてください。 [link]# 悪い例 defmodule SomeModule do @moduledoc """ About the module """ use AnotherModule end # 良い例 defmodule SomeModule do @moduledoc """ About the module """ use AnotherModule end
-
ドキュメントのため、複数行コメント内ではmarkdownを使いましょう。 [link]
# 悪い例 defmodule SomeModule do @moduledoc "About the module" end defmodule SomeModule do @moduledoc """ About the module Examples: iex> SomeModule.some_function :result """ end # 良い例 defmodule SomeModule do @moduledoc """ About the module ## Examples iex> SomeModule.some_function :result """ end
typespecsは、型と仕様を宣言するための表記法です。 ドキュメント、または静的解析ツールDialyzerに使用されます。 カスタムタイプは、モジュール上部に他のタイプと一緒に定義する必要があります。 (モジュールをみてください)
-
@typedoc
と@type
の定義は一緒に書き、それぞれのペア間には空白行を入れてください。 [link]defmodule SomeModule do @moduledoc false @typedoc "The name" @type name :: atom @typedoc "The result" @type result :: {:ok, term} | {:error, term} ... end
-
直和型の定義が長過ぎる場合は改行して戻り値の型で整列するようにインデントしてください。 [link]
# 悪い例 - インデントしていない @type long_union_type :: some_type | another_type | some_other_type | a_final_type # 良い例 @type long_union_type :: some_type | another_type | some_other_type | a_final_type # これも良い例 - 一行ごとに型一つ @type long_union_type :: some_type | another_type | some_other_type | a_final_type
-
モジュール内で定義された構造体などの型定義は
t
としてください。 [link]defstruct name: nil, params: [] @type t :: %__MODULE__{ name: String.t, params: Keyword.t }
-
型定義は関数のすぐ上に空白行無しで書いてください。 [link]
@spec some_function(term) :: result def some_function(some_data) do {:ok, some_data} end
-
もし構造体のフィールドのデフォルト値が全てnilならアトムのリストとしてください。 [link]
# 悪い例 defstruct name: nil, params: nil # 良い例 defstruct [:name, :params]
-
複数行に渡る構造体の定義の場合は、最初のキーの位置に合わせてインデントしてください。 [link]
defstruct foo: "test", bar: true, baz: false, qux: false, quux: nil
-
例外の名前は
Error
で終わること。 [link]# 悪い例 defmodule BadHTTPCode do defexception [:message] end defmodule BadHTTPCodeException do defexception [:message] end # 良い例 defmodule BadHTTPCodeError do defexception [:message] end
-
エラーメッセージは小文字で句読点を省いてください。 [link]
# 悪い例 raise ArgumentError, "This is not valid." # 良い例 raise ArgumentError, "this is not valid"
-
キーワードリストに対して常に特別な構文を使うこと。 [link]
# 悪い例 some_value = [{:a, "baz"}, {:b, "qux"}] # 良い例 some_value = [a: "baz", b: "qux"]
-
マップのキーがすべてアトムの場合は短く書けるキーバリュー構文を使うこと。 [link]
# 悪い例 %{:a => 1, :b => 2, :c => 0} # 良い例 %{a: 1, b: 2, c: 3}
-
マップのキーにアトムではないものがある場合は冗長なキーバリュー構文を使うこと。 [link]
# 悪い例 %{"c" => 0, a: 1, b: 2} # 良い例 %{:a => 1, :b => 2, "c" => 0}
-
文字列のパターンマッチはバイナリではなく、文字列結合演算子を使用してください。 [link]
# 悪い例 <<"my"::utf8, _rest>> = "my string" # 良い例 "my" <> _rest = "my string"
正規表現に関するガイドラインは今のところありません
- 不要なメタプログラミングをしてはいけない。 [link]
あまり一般的ではないスタイルですが役立つ場合があるかもしれません。
-
アトムは
true
として評価されるのでcond
の最後に入れるすべてにマッチする節として使うことができます。:else
か:otherwise
を使うと良いでしょう。 [link]cond do 1 + 2 == 5 -> "Nope" 1 + 3 == 5 -> "Uh, uh" :else -> "OK" end # is the same as cond do 1 + 2 == 5 -> "Nope" 1 + 3 == 5 -> "Uh, uh" true -> "OK" end
他のスタイルガイドについては Awesome Elixir を見てください。
Awesome Elixir にコードの静的解析とlintのためのツールがあります。
私達はここがElixirのベストプラクティスに関する議論の中心になることを願っています。 気軽にイシューを書いたりプルリクエストを送ってください。 contributing guidelinesと code of conduct を確認してください。
コミュニティスタイルガイドは、コミュニティのサポートなしでは無意味です。 ツイートしたり、スターをつけたり、Elixirプログラマに広めてください。
本翻訳のライセンスはCreative Commons Attribution 3.0 Unported Licenseです。
このドキュメントの作成にあたり、ガイドの章立てやコード例の一部、そして原案の多くをRuby community style guideから拝借しました。 それらの多くのことがElixirにも応用でき、また私達が議論するために 一部の ドキュメントを引くことが早くにできました。
ここに、このプロジェクトに対して親切にもコントリビュートして頂いた方々のリストを記します。