Już od dłuższego czasu przymierzam się do spełnienia obietnicy z początku cyklu o Domain Driven Design jaką jest zademonstrowanie przykładowej aplikacji napisanej w metodyce DDD. W ciągu tych trzech miesięcy jakie minęły od pierwszego wpisu wielokrotnie podejmowałem próby napisania czegoś. Jednak nigdy nie było ani jakiegoś konkretnego tematu na taką aplikację ani za bardzo czasu na ruszenie z developmentem (magisterka, wakacje etc). Natomiast od kilku dni czuję, że nadszedł właściwy czas i temat.
Temat
Jaki więc będzie cel działania naszej aplikacji? Jej tematem jest system relacji meczowych. Cóż to w ogóle jest ? Aby odpowiedzieć na to pytanie trzeba najpierw wyjaśnić skąd wzięła się motywacja.
Motywacja
Jednym z projektów, którym ostatnio się zajmowałem był CMS dla pewnego klubu sportowego. Oprócz standardowych funkcji, klient zażyczył sobie, by mógł przeprowadzać relację na żywo w internecie. Ficzer miał powstać na wzór tych, które funkcjonują na interii czy onecie. W zasadzie prosta sprawa – mamy mecz pomiędzy drużynami, obie drużyny mają jakiś skład, a jak już grają, to na boisku odbywają się różnego rodzaju wydarzenia – padają gole, sędzia pokazuje kartki etc. Jak na prostą sprawę przystało, długo się nie zastanawiałem. Zaprojektowałem bazę danych z odpowiednimi relacjami. Stworzyłem jedną ładną klasę która wszystko obsługiwała (w zasadzie można było to napisać jako zestaw pojedynczych funkcji) i po robocie. Działało ładnie, szybko i sprawnie. Do czasu. Do czasu gdy okazało się, że potrzeba jeszcze kilka rzeczy – tabelę ligową, podsumowania spotkań, że istnieją gole samobójcze, a potem jeszcze kilku zmian.
W zasadzie przyznam się szczerze, że się skompromitowałem w pewnym sensie – gram na różnych szczeblach klubowej piłki już kilka lat i temat znam nie od dziś. Niestety informacje jakie do mnie spływały w ogóle nie zapowiadały takiego obrotu spraw. Tak jak mówiłem miała to być prosta sprawa i tak zostało to zaimplementowane. Moim najpoważniejszym błędem było to, że w porę nie zaświeciła mi się w głowie taka mała czerwona lampka, że coś jest tutaj nie tak.
Motywacją jest więc chęć zrobienia TEGO dobrze. Żeby zrobić coś dobrze, trzeba wiedzieć najpierw jednak co poszło nie tak ?
Co poszło nie tak ?
Jak pamiętamy z poprzednich wpisów, metodyka DDD zakłada, że osoba projektująca software ma dostęp do eksperta domeny. Niestety w tym przypadku tak nie było. Informacje na temat funkcjonalności nie trafiały do mnie bezpośrednio. Fakt ten pewnie przyczynił się do ich zniekształcenia w drodze przekazu. Sądzę jednak, że nie było to największym problemem. Mam wrażenie, że gdybym osobiście mógł rozmawiać z tym ekspertem domeny to w mógłbym ogarnąć całą jego wizje. Sądzę również, że rozmawiając z ekspertem osobiście, czerwona lampka o której mówiłem, zapaliła by się na samym początku i mógłbym to zaprojektować w lepszy sposób. Największym problemem braku żywego kontaktu z ekspertem domenowym jest to, że wszelkie informacje docierają do nas w postaci „strzępków”. Rozmawiając na żywo czy na telekonferencji z kimś, możemy na bieżąco zadawać pytania i weryfikować nasze wątpliwości.
Z powodu tej dezinformacji rozpocząłem projektowanie modułu meczowego od strony bazy danych. Ten sposób projektowania software’u ma jednak jedną podstawową wadę – utrudnia przeprowadzanie zmian. Wprowadzenie zmian w bazie danych jest trudniejsze z perspektywy utrzymania spójności danych. Mając już zrobione relacje w bazie danych wszelkie zmiany muszą je uwzględniać, nie można sobie tak ot zmienić nagle relacji w ustalonym schemacie. Poza tym zauważyłem (przynajmniej u mnie), że projektowanie od strony bazy skłania raczej do dodawania nowych pól w tabelach niż tworzeniu nowych. Przykładem niech będą zdarzenia meczowe (Event). Załóżmy, że na początku zaprojektowaliśmy zdarzenie meczowe jako tabele z polami (id, time, content, type)
gdzie time to minuta meczu, content to opis akcji, a type to rodzaj zdarzenia (gol, kartka etc) potrzebny do wyświetlenia odpowiedniej ikonki przy zdarzeniu. Dla celów statystyk postanawiamy dodać pole player_id
, będzie mówiło nam który zawodnik dostał kartkę czy strzelił gola, oczywiście dla zwykłych eventów to pole nie jest do niczego potrzebne. Kolejną rzeczą, która potrzebujemy do statystyk będzie pole player2_id
, potrzebne ono będzie do tego by wiedzieć którzy zawodnicy uczestniczyli w zmianie. Tak jak wcześniej pole to pozostałym rodzajom eventów nie jest do niczego potrzebne. Tak się dzieje z każdym kolejnym przypadkiem. W przypadku projektowania obiektowego każdy rodzaj eventu będzie kolejną klasą.
Podsumowanie
Pewnie w tej chwili część osób czytających ten tekst myśli sobie „…no tak nie zrobił tego obiektowo teraz mu nie działa…”. Jak na złość muszę powiedzieć, że to nieładne rozwiązanie mimo wszystko działa. Problemem jest tylko rozwijanie tego kodu. Szczęście, że nie jest go dużo, ale sądzę, że gdyby to zaczęło się rozrastać to w końcu doszlibyśmy do stanu zwanego Big Ball Of Mudd . Na szczęście, pisząc tą przykładową aplikację będę w razie czego przygotowany gdyby praca z tamtym kodem stała się już nie możliwa.
Wpis zrobił się już dość długi, więc go w tym momencie zakończę i zapraszam na kolejną część, która opublikuje za kilka dni. Na pewno będzie to już coś bardziej konkretnego