środa, 8 października 2025

Domain Model cz.2

Dotarłem do miejsca w którym powstał kod. Oczywiście jak to jest w tych czasach korzystałem z pomocy Copilota. 

Do rzeczy, na warsztat został wzięty agregat Zmiana Grupy Startowej przez Zawodnika.

Widoczny pod tym adresem:

Generowanie grupy startowej

Wyszedł prawie idealnie, powstał prosty agregat jeden command jeden event, kilka reguł. Tu należy się uwaga, ten ES powstał jakieś cztery lata temu, razem z kolegami szkoliliśmy się w event stormingu padło na maraton, akurat ten temat był mi dobrze znany.

Kod jest polsko angielski, cóż tak uznałem, że będzie wygodniej na tę chwilę.

Opis:

Do zmiany grupy dochodzi na pewien czas przed startem maratonu, z reguły było to około miesiąca przed dniem startu. Następuje wtedy wygenerowanie grup startowych, które składają się docelowo z 15 zawodników. Istotnym faktem, który nie jest poruszany w tym kontekście ale należy go nadmienić jest to, że zawodnik który rejestruje się w danej edycji maratonu nie jest nazywany zawodnikiem a uczestnikiem.

Dlaczego to jest istotne? Uczestnik staje się zawodnikiem w momencie opłacenia startu, wtedy też uczestnik otrzymuje numer startowy, który uprawnia go do startu w zawodach oraz dzięki nie mu przynależy do jakieś grupy. Czyli jedną z reguł jest to, że do grupy startowej należą tylko zawodnicy.

Dlaczego to nie jest istotne dla tego agregatu? Dlatego że ten agregat umiejscowiony jest po fakcie wygenerowania grup. Dla niego fakt ten nie jest istotny, a są istotne inne reguły ale sama informacja jest ważna dla całego kontekstu zarządzania grupami startowymi i zrozumienia całego procesu.

Reguły

  1. grupy startowe muszą być wygenerowane - ta reguła w tym kontekście to typ "must be", bez wygenerowanych grup nie może odbyć się zmiana grupy, czyli brak spełnienia tej reguły eliminuje całość, nie da się jej nagiąc,
  2. nie przekroczono terminu zmian grupy - tu sprawa nie jest oczywista, termin jest płynny w zależności od edycji maratonu ale nie zmienia to faktu, że tylko w tym terminie można zmienić grupę *.
  3. Grupa docelowa jest z tego samego dystansu - to jest ważna reguła, której nie da się ominąć, czyli mamy kolejne "must be", dlaczego? grupy na danym dystansie startują o wyznaczonych porach, zapomniałem nadmienić że to maraton 24H, ta reguła została stworzona z przyczyn organizacyjnych, 
  4. Zawodnik nie zmieniał wcześniej grupy - reguła, ograniczenie ilości zmian, czy zawsze musi być spełniona? no to już zależy ale bardziej od reguł dotyczących danej edycji zawodów *.
  5. Grupa docelowa musi mieć miejsce - to dość logiczna reguła, która musi być spełniona, gdyż grupy mają narzuconą ilość zawodników, która ma tam być ale czy nie ma odstępstw? *.


Kod dostępny jest w tym miejscu


 public class ZmianaGrupyApplicationService
 {
     private readonly IGrupaRepository _grupaRepo;
     private readonly IZawodnikRepository _zawodnikRepo;
    
     public ZmianaGrupyApplicationService(
     IGrupaRepository grupaRepo,
     IZawodnikRepository zawodnikRepo)
     {
         _grupaRepo = grupaRepo;
         _zawodnikRepo = zawodnikRepo;
     }

     public void ZmienGrupe(ZmianaGrupyCommand command)
     {
         // 1. Pobierz dane
         var zawodnik = _zawodnikRepo.GetById(command.ZawodnikId);
         var grupaWyjsciowa = _grupaRepo.GetById(command.GrupaWyjsciowaId);
         var grupaDocelowa = _grupaRepo.GetById(command.GrupaDocelowaId);

         // 2. Utwórz agregat domenowy
         var zmiana = new ZmianaGrupyStartowej(
             command.TerminGrupy,
             zawodnik,
             grupaWyjsciowa,
             grupaDocelowa
         );
         // 3. Wykonaj operację domenową
         try
         {
             zmiana.ZmienGrupe(); 
         }
         catch (Exception ex)
         {
             //save to log
             throw;
         }

         // 4. Zapisz zmiany
         _zawodnikRepo.Save(zawodnik);
         _grupaRepo.Save(grupaWyjsciowa);
         _grupaRepo.Save(grupaDocelowa);
     }
 }

Nie będę ukrywał, copilot przyszedł mi z pomocą w tworzeniu tego serwisu, mój prototyp był nie co mniej "ładny". 

Agregat sprawdza reguły

 public void ZmienGrupe()
 {
     ValidateTermin();
     ValidateDystanse();
     ValidateZawodnik();
     ValidateIloscMiejsc();

     // Wykonaj zmianę na encjach
     _zawodnik.ZmienGrupe(_grupaDocelowa);
     _grupaWyjsciowa.UsunZawodnika(_zawodnik);
     _grupaDocelowa.DodajZawodnika(_zawodnik);

 }
Sprawdzenie reguł:
  • Nie przekroczono terminu zmian grupy - mogła zaistnieć sytuacja, pojedyncze przypadki, że tuż przed startem jakaś osoba mogła być przeniesiona z jednej grupy do drugiej, tak więc ta reguła może zostać podważona, ale to zawsze musiała być zgoda sędziego zawodów. Ciekawe jak to przedstawić w kodzie? (mamy rolę sędziego, to może być ciekawe)
  •  Zawodnik nie zmieniał wcześniej grupy - ta reguła mogła by być nagięta w sytuacji gdy zawodnik przed startem zgłasza że zmienia dystans, rezygnuje z jednego i pojedzie na innym dystansie,  dzieje się to po wygenerowaniu i zatwierdzeniu grup, sądzę, że ten proces jest inny i zasługuje na osobny agregat, reguły będą musiały być zbadane w szerszym zakresie, albo przypadek taki że kierownik zawodów ma jakąś znajomą osobę która jednak chciał by zmienić grupę, bo zapisała się już po zmianie grup i co odmówisz?
  • Grupa docelowa musi mieć miejsce - ta reguła może został "złamana" w przypadku gdy na danym dystansie mamy grupę, która osiągnęła limit zawodników i kolejną grupę która ma jednego zawodnika. Takie rzeczy się zdarzały i robiło się wtedy tak, że puszczało się jednego zawodnika z grupą wcześniejszą i czas startu jego grupy pokrywał się z czasem startu grupy poprzedniej,
Podsumowanie

Nagle nam się warunki zaczynają zmieniać, to chyba czas na zmianę agregatu i ponowne jego rozpisanie, a na razie cieszmy się tym co mamy.
Reszta kodu w repo.

Jak wspominałem event storming z maratonu ma już swoje lata, patrząc teraz na ten agregat widzę, że część reguł można nagiąć, a to sugeruje że, trzeba przejrzeć proces i sprawdzić ten kontekst.  Będzie szansa na to, bo jest opcja zrobienia warsztatów w tym temacie na żywo (zdalnie wyszły słabo). 

Na koniec powrót do przeszłości Historia wersji maratonu

Brak komentarzy:

Prześlij komentarz

Domain Model cz4

 Kolejny raz bez kodu, kolejny raz z Cluade-m w roli analityka. Głównym tematem dziś będą Pivotal Events i bounded contexty. Na sesji Event ...