Non-anemic entities

Odpowiedz Nowy wątek
2018-01-14 16:55
0

Cześć, ostatnio gdzieś tu na forum znalazłem sprzeczną z moim ostatniem podejściem, które stosujemy w pracy problematyką. Chodzi o NIEANEMICZNE encje. W pracy spotkałem się po raz pierwszy z tym i architekci wprowadzili taką zasadę u nas- podobno źródłem tego jest książka o DDD - aby encje hibernatowe posiadały również metody biznesowe.

Tutaj jednak czytałem, że to jest złe. Mi się z tym dobrze pracuje.
Ktoś mógłby ruszyć bardziej ten problem ?

Pozostało 580 znaków

2018-10-31 11:14
0

@hcubyc:

Bo ogólnie jestem na etapie projektowania architektury do gierki przeglądarkowej w styu Ogame. Use case'y mam już w miarę rozpisane. Przyszła pora na jakieś rozrysowanie modułów i ich relacji. Oczywiście moje pierwsze podejście do schematu to wydzielenie rzeczowników i tak też zrobiłem przez co pojawiło się moje pytanie wyżej o rozbijanie modułów. No bo tak: gracz posiada kilka baz militarnych, każda baza ma swoje budynki, surowce i stacjonującą flotą. Na 1 rzut oka wydaje się, że agregatem jest user z listą baz, każda z baz z listą budynków, surowcami i flotą. No, ale nie wydaje mi się, żeby to było dobre bo coś za duże jest :D. W następnym kroku jednak rozbiłem ten 1 wielki moduł na kilka mniejszych (per rzeczownik) .. ale to chyba nadal nie jest dobry pomysł, bo jak będę chciał wyciągnąć dane o całej bazie to odpytam moduł bazy, potem po id bazy odpytam surowce i jeszcze budynki i flotę - chyba już za dużo tych zależności i łatwiej wyciągnąć jeden agregat. Z drugiej jednak stron - to jest ta część 'query', prezentacyjna, mniej ważna - bez reguł biznesowych. Popisałem z J. Nabrdalikiem i zasugerował, że źle kombinuję myśląc rzeczownikami, żebym zrobił model c4, wypisał use casy i starał się je przejść za pomocą diagramów sekwencji - jeszcze nie do końca wiem jak to mnie naprowadzi na wydzielenie agregatów/modułów, ale spróbuję. Może tak naprawdę nie muszę mieć modułów jakie wydzieliłem do tej pory tylko zupełnie inne.

No mam ogólnie mind fucka, ale nie daje mi to spać po nocach :D

Pozostało 580 znaków

2018-10-31 19:31
0

Generalnie za pierwszym razem nie zrobisz tego dobrze, nawet jak już będziesz miał w tym doświadczenie to i tak będziesz dalej popełniać błędy, choćby ze względu na nieznajomośc domeny. Jeżeli chodzi o agregaty to pamiętaj też żeby mieć 1 transakcję per agregat, tzn staraj się unikać takich sytacji gdzie żeby wykonać 1 akcję użytkownika musisz zapisać w jednej transkacji 3 różne agregaty. Generalnie myslenie czasownikami IMHO jest spoko, bo wtedy w miare bedziesz widzieć jakie są interakcje - jeżeli coś ze soba często gada/wymaga cyklicznej zależności to zazwyczaj jest to jedna i ta sama rzecz. Zastanawiam się właśnie czy baza by nie była agregatem z referencją do użytkownika jako ID. Pytanie czy budynki nie będą częścią bazy? I surowce osobno tez per użyktownik? Musiałbys więcej napisać to z pewnością ktoś pomoże, bo nie grałem nigdy w ogame. Czy baza produkuje i konsumuje surowce? Surowce są per baza czy per gracz? Jakie są podstawowe akcje? Bez tego cięzko doradzać


Limitations are limitless

> ##### Ola Nordmann napisał(a)
> Moim językiem ojczystym jest C++ i proszę uszanować to, że piszę po polsku.

Pozostało 580 znaków

2018-11-01 11:10
0

@hcubyc:
To jest tak, że każdy user po założeniu konta dostaje pierwszą swoją bazę (w dalszej części gry może utworzyć kolejne jak ogarnie potrzebne technologie ale to nieważne). Każda baza ma swoje budynki, które są jej częścią. Czyli załóżmy w swojej bazie nr 1 możesz mieć kopalnie złota poziom 5 i stocznie poziom 3 a w bazie 2 kopalnie złota poziom 7 i stocznie poziom 3. Surowce są per baza, a nie user, czyli jeśli chcesz mocno rozwijać jedną bazę to możesz sobie transportować surowce z innych baz do tej głównej.

Kolejne co mnie zastanawiało - jak ogarnąć system przyrostu surowców. Czyli załóżmy, że kliknąłeś na ulepszanie kopalni złota na poziom 10 i trwa to 5h. Wzięło Ci surowce i na froncie widzisz odliczanie tego czasu. No ale teraz tak - trzeba jakoś zaimplementować sposób naliczania tych surowców. Załóżmy, że na kopalnia na poziomie 9 wydobywała 10j. złota na sekunde, a na poziomie 10 wydobywa 12j / s. Na pewno nie chce mieć żadnego chodzącego joba, który będzie updatował surowce, bardziej preferuję sposób, że surowce będą się updatowały w przypadku odpytania o nie w jakiejkolwiek sytuacji - np. chcesz coś zbudować, musi iść odpytanie o ich stan, przy okazji jest naliczony ich nowy stan na podstawie poziomu jakiejś tam kopalni i czasie ostatniego ich updatu. Gorzej tylko w sytuacji, kiedy akurat jakaś kopalnia będzie w trakcie budowania. Bo jeśli w czasie, kiedy user nic nie zrobił zakończy się ulepszanie to przecież przy najbliższym odświeżaniu powinno naliczyć surowce z niższym wydobyciem do czasu ulepszenia i potem już z nowym wydobyciem - może muszę zapisywać jakieś akcje w bazie i sprawdzać stan.

Pozostało 580 znaków

2018-11-01 11:26
0

Ciężki masz przypadek, bo gry rzadza sie troche innymi prawami, ja np jako gracz chciałbym widzieć jak mi złoto rośnie na koncie ;) nie wiem czy jeden mega wielki agregat/modul baza by nie był odpowiedni, bo wszystko musi być spójne - nie możesz utworzyc budynku, wysłać event, a baza sobie go skonsumuje i doda budynek po jakimś czasie, tak samo z surowcami - wiesz np. że w tej minucie powinieneś mieć złota na nowy budynek, a tu kleks bo się nie przeprocesowało ;) z drugiej strony duże agregaty to nie jest dobra praktyka, więc na twoim miejscu bym próbował zrobić pierwszą implementację, popatrzył potestował i najwyzej refaktorował dalej.


Limitations are limitless

> ##### Ola Nordmann napisał(a)
> Moim językiem ojczystym jest C++ i proszę uszanować to, że piszę po polsku.

Pozostało 580 znaków

2018-11-01 16:43
0

@hcubyc:

To jak Ci złoto rośnie mogę rozwiązać tym, że na front wyślę info o stanie + przyroście i już front będzie updatował wartość co 1s czy tam ile chce.

Kurde no też mi się wydaje, że baza tu jest 1 agregatem, bo chociażby patrząc na tą zasadę z transakcjami - jeśli wybuduję budynek i miałbym dwa agregaty - Budynki i Surowce to oba agregaty zapisuję w transakcji czyli źle ..

No i na budowanie mam taki pomysł, że po kliknięciu buduj jest taki flow:

  1. Sprawdzanie stanu surowców i tego czy już dany budynek nie jest budowany
  2. Odjęcie surowców, zmiana stanu budynku na "w budowie" i ustawienie czasu wybudowania na te załóżmy +5h od teraz.
  3. Przy odpytywaniu o surowce dla jakiejkolwiek potrzebującej tego operacji sprawdzę czy budynek odpowiedzialny za przyrost surowców ma ustawiony czas ukończenia budowy - jeśli tak i jest już po nim to odpowiednio przeliczę przyrost, podniosę level budynku, ustawię datę ukończenia budowy na null.

Chociaż jak tak o tym piszę to w sumie trochę słabo z tym ustawianiem nulla i robieniem budynków stanowych. Klaruję mi się tu encja "Modyfikacje", która by zawierała info o tym co jest budowane i kiedy jest plan ukończenia. Hmm to DDD to serio ciężki temat :D

pamiętaj, że zasada o zapisywaniu dwoch i wiecej agregatów to tylko zasada - czasem trzeba zrobić wyjątek - hcubyc 2018-11-01 18:35
@hcubyc: A gdybyś sam miał zaprojektować coś takiego to jaka architektura rzuca Ci się pierwsza w oczy ? Z tego co zrozumiałem również wydzieliłbyś po prostu agregat jako bazę. Jeszcze zastanawiam się nad klasą "modyfikacja". Faktycznie chyba zacznę pisać i zobaczymy co z tego wyjdzie. - Bambo 2018-11-02 08:46
Zamiast modyfikacji mógłbyś zrobić też budynek stanowy - każdy stan ma swoje zachowania i wtedy nulle będą tylko w bazie, ale kto by się nimi przejmował. Powiem ci, że myślałem chwilę nad tym i nie wymyśliłem nic czego bym był pewny. Tak też myślalem o jednej bazie, ale zacząłbym chyba prawilnie implementację od malych agregatów mimo wszystko tylko po to żeby spróbować, a jak by byly problemy to wtedy bym łączył agregaty. Jeżeli chodzi o architekturę to bym stosował hexagonal - hcubyc 2018-11-02 09:55

Pozostało 580 znaków

2018-11-02 18:19
eL
0

Przeczytałem cały temat i sobie go zapiasłem bo naprawdę dużo ciekawych info można tu znaleźć. Dzięki @Bambo że chce Ci się go też odświeżać po kilku miesiącach braku aktywności ;)
Przy okazji mam pytanie.
Obejrzałem film Jakuba Nabrdalika który tu linkowaliście. Generalnie super, mega chwalę i nawet mam trochę swoich kodów więc dla sportu zrobiłem refaktor żeby zobaczyć jak to się sprawdza i mam 2 wątpliwości:

  1. Przy niewielu klasach w pakiecie jest okej ale jeśli taki pakiet odzwierciedla jakąś domene a ta jest bardziej złożona to czy nie jest tak że w jednym pakiecie mamy naciapane kilkadziesiąt klas w których ciężko się połapać? Ja zrobiłem około 20 i już czuję że jest to mało intuicyjne.
  2. Weźmy przykład Jakuba z filmami i wypożyczaniem. Jeśli rozdzielimy te domeny do dwóch pakietów i encje zrobimy prywatne (z tego co zrozumiałem tylko fasady i dto ma public) to wówczas nie mamy jak powiązać ze sobą w bazie tabeli wypożyczenie z kluczem obcym na film. Jakub robi to na MongoDB ale załóżmy że mamy zwykłego SQLa. Jak w takim razie to powiązać? Można zrobić jakiś UUID filmu i w tabeli wypożyczenie trzymać go, natomiast nie mamy żadnej gwarancji że te dane są spójne (np. taki film zostanie usunięty). Jak to sensownie obsłużyć?

EDIT.
Naszło mnie na jeszcze trzecie pytanie:

  1. Jaki sens ma używanie IoC razem z takim podejściem żeby wszystko było prywadne i wystawiać tylko fasadę? Wszelkie serwisy, komponenty itp jeśli będą zarządzane przez Springa to nawet jeśli będą package scope to i tak można to w dowolne miejsce wstrzyknąć. O ile jeszcze wyobrażam sobie żeby serwisy ręcznie tworzyć przez new i przekazać to do fasady przez konstruktor tak jak robi to Jakub, o tyle nie jest to już możliwe w przypadku np. springowych kontrolerów lub interfejsów repository od Spring Data JPA.
edytowany 1x, ostatnio: eL, 2018-11-02 18:34
Mógłbyś skrócić co się można dowiedzieć albo lepiej które posty warto przeczytać? - Visual Code 2018-11-02 20:28
1. To podejście daje Ci bardzo dużo w momencie, w którym analizujesz co się dzieje w danym module - odpalasz fasadę i już wiesz do czego służy 3. W tym podejściu powinniśmy testować tylko fasadę, a dzięki temu, że mamy metodę która ją wystawia i przyjmuje wszystkie zależności z zewnątrz, bardzo prosto można ją stworzyć do testów. Druga rzecz to refactoring wewnątrz modułu. Przez to, że mamy fasadę, która wystawia pewien kontrakt, możemy modyfikować wszystko co jest w środku, dopóki jesteśmy zgodni z tym kontraktem - nie wymaga to zmian w klasach, które korzystają z fasady. - Aleksander Brzozowski 2018-11-03 18:21
@Aleksander Brzozowski: Napisałeś sporo ale nie odpowiedziałeś w ogóle na moje pytania. Rozumiem sens istnienia takie podziału, wiem gdzie są korzyści itp ale ja w swoich pytaniach poruszam kwestie intuicyjności takiego rozwiązania, sensu korzystania z IoC razem z takim podejściem itp itd... Generalnie problemy które rodzi. Nie pytam co mogę zyskać bo ja to wiem, szukam odpowiedzi czy to co mogę stracić na rzecz tego co mogę zyskać ma sens. - eL 2018-11-05 07:31

Pozostało 580 znaków

2018-11-02 18:34
0

Ad.1 No cóż, wyjścia masz dwa: podzielić domenę albo zrezygnować z Javy na rzecz innego języka JVM(Scala etc.)
Ad.2 Zastanawiałem się jakiś czas temu nad tym problemem i ostatecznie zrezygnowaliśmy z relacji. Nie wydaje mi się, aby było inne wyjście niż umożliwienie dostępu między encjami. Niestety Hibernate, zreszta jak wiele innych frameworków i libek, nie był tworzony z myślą o package private

Dodałem jeszcze jedno pytanie. Co do drugiego to w takim razie jak to zamodelujesz żeby mieć informację o tym jakie filmy były wypożyczone w ramach danego wypożyczenia? Encje masz public czy inaczej to rozwiązujesz? Chodzi mi o konkretne rozwiązanie którego ja póki co nie widzę. - eL 2018-11-02 18:37
Rozwiązałem ten problem relacjami nie na poziomie bazy danych albo relacji między domenami. Przykładowo w jednej domenie przechowujesz dane o samych wypożyczeniach, w innej o samych filmach. W encji Film masz pole id wypożyczenia. Następnie możesz zapytać domenę o filmy wypożyczone z danym id. Tak to zaimplementowaliśmy. Pytanie tylko czy to jest najlepsze i poprawne rozwiązanie:) - lordbobstein 2018-11-02 18:48
No i to jest jedyne rozwiązanie które ja widzę, oczywiście przy okazji trzeba pozbyć się hibernate'a, chyba że wyłączy mu się całkowicie zarządzanie schematem bazy danych i wówczas encja film może trzymać samo id wypożyczenia... Mimo wszystko osobiście czuję że to słabe rozwiązanie chociaż nie widzę lepszego. Może wypowie się jeszcze ktoś mądry ;) - eL 2018-11-02 18:54

Pozostało 580 znaków

2018-11-03 12:28
1

@eL:

To nie tak, że mi się chce go odświeżać :). Interesuję się dość mocno architekturą apek, DDD itd. Pracuję w banku, często gadam z analitykami i biznesem, wprowadzam building blocki z DDD, staram się unikać, a jak zastanę to refaktoryzować 8tysięczniki. Po prostu przy moich kolejnych priv projektach chcę pisać coraz lepiej, stosować nowe technologie i ogólnie rozwijać się, a że większość moich zagwostek tyczy się architektury to wolę nie zakładać kolejnych tematów tylko korzystam z tego :D

Sam osobiście porzuciłem springa mvc, javę i hibernata. Czas na kotlina, jakiś funkcyjny serwer (pewnie spring reaktywny) i jooq.

Czasami nie ma co porzucać hibernate czy tam spring data jpa. Miałem taki projekt, gdzie zapytania do bazy czy też modyfikowanie jej stanu było na tyle proste, że pchanie tam jooq'a spowodowałoby, że robilibyśmy to pewnie trochę dłużej, a nic by to nie dało. Co do kotlina to się w pełni zgadzam - jeżeli masz możliwość wybrania języka do projektu. Jeżeli jesteś jeszcze większym hipsterem, to polecam obserwować jak rozwija się ten projekt: https://github.com/spring-projects/spring-fu. - Aleksander Brzozowski 2018-11-03 18:09
@Aleksander Brzozowski: priv projekty piszę głównie po to, aby popraktykować alternatywy i pobawić się (a nuz zarobie). Mainstreamowy stos mam w pracy :) - Bambo 2018-11-04 17:49
@Bambo: a nie myślałeś o przeniesieniu się np. na Mongo? DTO możesz wówczas wyciągać bez żadnej konwersji plus nie masz relacji więc żadne joiny, constrainy itp Cię nie interesują. Przy okazji dzięki temu możesz zostać przy Spring Data i sam żadnych query (przynajmniej nic co jest mega złożone) pisać nie musisz. - eL 2018-11-07 10:05

Pozostało 580 znaków

2018-11-09 15:31
0

@hcubyc: :DD Mam nadzieję, że nie przeszkadza Ci, że od czasu do czasu Cię tu popinguję.

Mam dla Ciebie kolejny case:

Jak testujesz metodę fasady, która coś zapisuje, ale nigdzie w systemie nie masz potrzeby wyciągania zapisanej encji po id ? Robienie metody loadById() dla fasady tylko na potrzeby testów jest imho głupie.

Rozwiązanie, które obgadałem z kumplem w robocie to wstrzyknięcie do fasady InMemoryRepository dopiero w testach, aby mieć do tego referencje i dorobienie do tej InMemory implementacji metod na potrzeby testów - sprawdzających po id itd. Wiem, że to takie trochę wyciąganie bebechów na stół i grzebanie tam gdzie się nie powinno, ale chyba z dwojga złego lepsze to niż sztuczne dorabianie metod do fasady ?

Pozostało 580 znaków

2018-11-09 18:02
0

Nie ma problemu ;)
Ja generalnie stosuje takie właśnie podejście - czyli do fasady leci interfejs i fasada na nim operuje, a w testach stawiam inMemory implementację i operuje na klasie konkretnej czyli inMemory i tam własnie dorabiam sobie metody do sprawdzenia. W testach z infrą jest łatwiej, bo zawsze możesz zapytac baze czy posiada taki obiekt. Staram się tego unikać tak jak tylko mogę i testować zachowanie, więc zazwyczaj jeżeli coś zapisujesz w bazie to potem chcesz na tym wykonać jakąś operację, wiec można dać jeden test, gdzie np. tworzysz nowe konto użytkownika, a nastepnie użytkownik moze się zalogować - przykład trochę z d**y, ale jeżeli masz wymaganie biznesowe żeby coś włożyć do bazy/stworzyć to zazwyczaj coś dalej się z tym dzieje, a takie przykłady gdzie faktycznie tylko coś wkładasz i nic dalej z tym nie robisz to zazwyczaj jakieś raporty/dane techniczne, więc wtedy nie mam oporów sprawdzać na implementacji inMemory czy się zapisało. Inny sposób jeżeli wolisz to można też sprawdzić to na mocku - czyli sprawdzasz czy do repo faktycznie poszedł strzał żeby coś zapisać i jeżeli tak to zakładasz, że implementacja to ogarnie.


Limitations are limitless

> ##### Ola Nordmann napisał(a)
> Moim językiem ojczystym jest C++ i proszę uszanować to, że piszę po polsku.
edytowany 1x, ostatnio: hcubyc, 2018-11-09 18:03

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 0, botów: 1

Robot: Bingbot