Ostatnio u nas w firmie pojawił się temat technicznego retro, zgłosiłem się na ochotnika, cóż w końcu trzeba się nauczyć występować.
Prezentowałem nietypowe podejście do pewnej funkcjonalności w naszym systemie. Nie będę tu zagłębiał się w szczegóły, ale w dużym skrócie, chodziło o relacje i podejście rekordowe w bazie danych. Było też trochę o normalizacji.
Pomyślałem, że to dobry pretekst do napisania jakiegoś krótkiego posta. Przez te kilka lat wyszedłem z wprawy. W między czasie szykuje się model z poprzedniego posta o DDD.
Do brzegu
Nie sposób przy tej okazji nie wspomnieć o tym, że podobny problem, opierający się na rozwiązaniu z wieloma kolumnami miałem w aplikacji do zarządzania maratonem rowerowym. Ten problem mogę tu przybliżyć, koncept jest podobny (zresztą na tym blogu kilka lat temu już o nim pisałem).
Problem
W aplikacji do maratonu rowerowego jedna z funkcjonalności, właściwie główna opierała się na pomiarze czasu, pomiarze czasu zawodników. Zawodnicy mieli karty RFID i odbijali się na poszczególnych checkpointach na 100 km-etrowych pętlach.
Ilość checkpointów była zależna od dystansu na który zawodnik się zapisał, dystansów było kilka jak zaczynałem to były 100, 200, 300, 400, 500, 600 i 650 km, w kolejnych edycjach doszedł dystans 50 i 700. Zawodnicy startowali o różnych porach tak żeby zmieścić się w 24h, zapomniałem wspomnieć że to był maraton 24 godzinny.
Rozwiązanie - pierwsze
Jak to wtedy zamodelowałem?
Jako, że jestem fanem (mam nadzieje że już nie długo) techniki rozpoczęcia projektowania od stworzenia bazy, to zacząłem od zbudowania tabeli, która pozwoli mi na prosty i łatwy dostęp do czasu danego zawodnika. Oczywistym było zrobienie tabeli, która ma ilość kolumn równą ilości checkpointów, maksymalnej ilości checkpointów.
Problemy napotkałem w drugiej edycji, dotyczące tego rozwiązania, jeżeli ktoś się odbił dwa razy to drugi czas przechodził do kolejnego checkpointa - kolumny, jak ktoś zapomniał to znowu brakowało czasu. W tym miejscu trzeba nadmienić, że np dla jednego dystansu mieliśmy trzy checkpointy jak jednego brakło odbicia to mieliśmy przekłamanie.
Kolejny problem jest bardziej złożony, w którejś edycji dołożyliśmy checkpoint w takim modelu kolumnowym dołożenie kolejnych kolumn wiąże się ze zmianą modelu w backendzie i masą "logiku", szczególnie, że w pierwszych edycjach nie używałem entity frameworka a czystego ADO. Dodanie kolejnych wpisów musiało trafić w odpowiednią kolumnę, co też sprawiało problem.
Więcej problemów nie pamiętam.
Link do posta opisującego te rozwiązanie
Rozwiązanie - drugie, właściwe
W ostatniej edycji maratonu 2018/2019, maraton zaczynał się we wrześniu 2018 a konczył w czerwcu 2019, wpadłem na lepszy pomysł.
Tabela rekordowa zamiast kolumnowej, prosta zmiana dojście do tego zajeło mi 5 lat (pięć edycji).
Taka tabela jest znacznie prostrza, nie ma tyle kolumn, a cała logika zapisu polega na wierszach w takiej formie nie potrzebujemy kolumn na kolejne checkpointy, bo wystarczy nam jedna kolumna prezentująca czas.
Rozwiązanie jest zaprezentowane w w tym poście. Jakie są jeszcze zalety?
Przy takiej formie tabeli, nie muszę dbać o czasy pośrednie, bo tak naprawdę liczy się dla mnie tylko czas pierwszy i ostatni ich różnica da mi czas który jest tak naprawdę istotny czyli czas przejazdu całego dystansu. Owszem mogę liczyć checkpointy i odbicia ale czy ich będzie 1 czy 10 nie ma to różnicy w tym podejściu. Samo wyliczanie przejechanych checkpointów odbywa się po stronie aplikacji. Ilość checkpointów nie gra roli.
Wnioski
Warto czasem rozważyć, czy tabela kolumnowa w dłuższej perspektywie czasu będzie dobrym rozwiązaniem? Czy przyniesie więcej korzyści przekształcenie jej w tabele wierszową?
To też w dużej mierze zależy od problemu, w aplikacji z maratonu rowerowego, pomiar czasu i związane z tym problemy przy rozwiązaniu kolumnowym otworzyły mnie na głębsze zastanawianie się nad zastosowaniem właśnie podejścia rekordowego, co też teraz często stosuje.
Ale rozwiązanie wierszowe jest trudniejsze na start, opiera się też między innymi o relacje.
Przykład inny, spotykam się często zrobieniem list danych, ograniczonych zbiorów na kolumnach tabeli co jest dla mnie sygnałem że takie rozwiązanie może się szybko zemścić, gdy nagle się okaże że listę danych trzeba rozszerzyć.
A co do wpisywania list do tabel rekordowych? Dla mnie jest to oczywiste ale wiąże się z tym ze daną tabele z taką listą trzeba wpiąć przez relacje do głównej tabeli która tę listę zawiera, potrzebuje.
Jeżeli mamy relacje to przy zapytaniu potrzebujemy joina, co wpływa na wydajność, rozwiązanie kolumnowe jest szybsze, nie ma joina (chyba że są setki kolumn).
Kolejna "słabość", to transakcje. Bardzo możliwe że będziemy potrzebowali użycia transakcji do obsłużenia wielu tabel wchodzących w skład tabeli głównej.
Czy to jest zawsze opłacalne? To pytanie jest otwarte, warto sobie je zadać przy projektowaniu i podejmowaniu decyzji, bo za niewłaściwe zapłata przychodzi często z opóźnieniem.
Brak komentarzy:
Prześlij komentarz