Praktyczne zastosowanie strażników w Elixirze
Trwa przerwa od JUnita. Wybaczcie, ale muszę odpocząć kilka dni od tego tematu. W zamian trochę Elixira i mały praktyczny przykładzik jak można zastosować strażników. Z samym mechanizmem strażników zapoznaliśmy się już wcześniej. Dziś coś, co robiłem przy okazji peselxa, a co finalnie zostało „ostrażnikowane”.
Problem
Z numeru PESEL możemy wyciągnąć informacje o dacie urodzenia. By to zrobić, musimy odpowiednio zinterpretować pierwszą cyfrę miesiąca, zgodnie ze schematem:
- Jeżeli jest to 0 lub 1, to osoba urodziła się pomiędzy 1900, a 1999 rokiem.
- Jeżeli jest to 2 lub 3, to osoba urodziła się pomiędzy 2000, a 2099 rokiem.
- Jeżeli jest to 4 lub 5, to osoba urodziła się pomiędzy 2100, a 2199 rokiem.
- Jeżeli jest to 6 lub 7, to osoba urodziła się pomiędzy 2200, a 2299 rokiem.
- Jeżeli jest to 8 lub 9, to osoba urodziła się pomiędzy 1800, a 1899 rokiem.
Piękna ifologia. Piękna. Przykładowo, żeby określić, w którym roku urodziła się dana osoba, możemy napisać:
Listing 1. Wyciąganie roku urodzenia z PESEL
defp calculate_year({[d|u], [f|_], _}) do
u = to_integer(u)
cond do
f == 0 || f == 1 -> 1900 + 10 * d + u
f == 2 || f == 3 -> 2000 + 10 * d + u
f == 4 || f == 5 -> 2100 + 10 * d + u
f == 6 || f == 7 -> 2200 + 10 * d + u
f == 8 || f == 9 -> 1800 + 10 * d + u
end
end
Za pomocą cond mogę zdefiniować zestaw if-elseif. Podobnie będzie wyglądać to dla miesiąca, ale tu musimy w razie czego odjąć odpowiednią liczbę, by „znormalizować” numer. Problem z tym kodem polega na tym, że credo, czyli checkstyle dla Elixira, będzie marudziło. Funkcja ma za dużą złożoność. Trudno się z tym nie zgodzić, ponieważ mamy tutaj zaszyte wiele instrukcji warunkowych.
Refaktoryzacja do strażników
Poprawmy kod, przerzucając odpowiedzialność za wybór odpowiedniej ścieżki na maszynę wirtualną. Dzięki czemu nasza funkcja będzie bardzo prosta. W tym celu wykorzystamy strażników, którzy będą opisywać warunki, które musi spełnić cyfra dziesiątek w miesiącu, aby wywołać odpowiednią logikę:
Listing 2. Kod po refaktoryzacji do strażników
defp calculate_year({[d|u], [f|_], _}) when f == 0 or f == 1, do: c_y(1900, d , u)
defp calculate_year({[d|u], [f|_], _}) when f == 2 or f == 3, do: c_y(2000, d , u)
defp calculate_year({[d|u], [f|_], _}) when f == 4 or f == 5, do: c_y(2100, d , u)
defp calculate_year({[d|u], [f|_], _}) when f == 6 or f == 7, do: c_y(2200, d , u)
defp calculate_year({[d|u], [f|_], _}) when f == 8 or f == 9, do: c_y(1800, d , u)
defp c_y(cent, d, u), do: cent + 10 * d + to_integer u
Jak widać, kod stał się znacznie przyjemniejszy. Ponadto strażnicy pilnują nam pokrycia wszystkich gałęzi. Jeżeli ktoś poda parametr, który nie jest obsługiwany…