引き続き、Elixir アンチパターンを読んでみます。
今日は、primitive-obsessionです。
住所を処理するプログラムで、住所を文字列型に入れておいて、郵便番号や国名などを必要に応じて取得したり、書き換えたりする例です。
defmodule MyApp do
def extract_postal_code(address) when is_binary(address) do
# Extract postal code with address...
end
def fill_in_country(address) when is_binary(address) do
# Fill in missing country...
end
end
住所の文字列データをそのまま使うのはアンチパターン。構造化されたデータで保存してそれを扱うのがよいという話でした。
お勧めの例では、Addressというstructを作って:street, :city, :state, :postal_code, :countryを入れるようにしています。
defmodule Address do
defstruct [:street, :city, :state, :postal_code, :country]
end
defmodule MyApp do
def parse(address) when is_binary(address) do
# Returns %Address{}
end
def extract_postal_code(%Address{} = address) do
# Extract postal code with address...
end
def fill_in_country(%Address{} = address) do
# Fill in missing country...
end
end
この住所の例は、文字列だと扱いずらいので、さすがに、パースして構造化したデータで保存しますよね。
そもそも、構造化した状態で入力してもらうだろう。
まあ、これは例なので、特殊な想定ですが、実際には、文字列のまま最初の1文字目がXXXで、2文字目以降が
YYYなどと決まりを作って、文字列のまま処理するとかありそう。
map,tuple,structを適切に使いましょう。
mapとstructはほぼ同じですが、structは、
- あらかじめ指定したキーしか使えない。
- 指定したキーは必ず存在する。
という違いがあります。
structは、moduleを作って宣言しないといけないので、ちょっと面倒なんですが、キーがなにか明確なので、好んで私は、好んで使ってます。
以前、Axonのソースコードを読んだらStruct効率的に使われていて、読んでみて使い方の勉強になりました。
どんなプログラミング言語でも同じだと思いますが、処理対象のデータを適切なデータ型に保存して取り扱う事は大事ですね。
以前、次の記事で、defstructを使った記事をかいてるので、興味ある方はどうぞ。