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…

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax