引き続き、Elixir アンチパターンを読んでみます。
今日は、unrelated-multi-clause-functionです。
Elixirでは同じ関数名の関数を定義して、パターンマッチでマッチどれが実行されるか選択する事ができます。
このアンチパターンの例は、update という名前の関数だけど、引き数がProductだったら、Productの更新をして、Animalだったら、Animalの更新をするというものです。
@doc """
Updates a struct.
If given a "sharp" product (metal or glass with empty count),
it will...
If given a blunt product, it will...
If given an animal, it will...
"""
def update(%Product{count: nil, material: material})
when material in ["metal", "glass"] do
# ...
end
def update(%Product{count: count, material: material})
when count > 0 and material not in ["metal", "glass"] do
# ...
end
def update(%Animal{count: 1, skin: skin})
when skin in ["fur", "hairy"] do
# ...
end
こんな事する奴いないだろう。という例なんですが、知らず知らずのうちにやってるかもしれないです。
お勧めのコードは、update_sharp_product/1とupdate_animal/1の二つの関数に分ける事です。
@doc """
Updates a "sharp" product.
It will...
"""
def update_sharp_product(%Product{count: nil, material: material})
when material in ["metal", "glass"] do
# ...
end
@doc """
Updates a "blunt" product.
It will...
"""
def update_blunt_product(%Product{count: count, material: material})
when count > 0 and material not in ["metal", "glass"] do
# ...
end
@doc """
Updates an animal.
It will...
"""
def update_animal(%Animal{count: 1, skin: skin})
when skin in ["fur", "hairy"] do
# ...
end
updateという名前から、更新するものは何でもupdateにまとめよう。と思ったのかもしれませんが、何を更新するのかが、関数名を見ただけではわからないものになってしまっています。
関数にはわかりやすい名前をつけましょう。
関数名の大切さはいろいろ語られてますが、クリーンコードという本、お勧めです。