Java – pytania o architekturę.

0

Na początek krótki wstęp historyczny: od przeszło dwóch lat jestem Java Backend deweloperem. Na początek trafiłem do projektu którego architektura była opisana wzorcem: CSR – czyli Controller/Service/Repository in one object, znana szerzej jako „architektura studencka”. Niestety wzorzec ten trudno było modyfikować i utrzymywać stąd też następnym krokiem było przepisanie aplikacji na architekturę warstwową. Szczęście moje nie trwało długo ponieważ po pewnym czasie projekt dramatycznie zaczął puchnąć w związku z nowymi funkcjonalnościami. Jako rozwiązanie postanowiłem połączyć podejście DDD (w związku z tym że proces biznesowe były coraz to trudniejsze do zrozumienia gdy były opisane przez gettery i settery i po jakimś czasie trudno było w łatwy sposób je rozszyfrować co robią) oraz architekturę heksagonalną która, wydaje mi się, ładnie pakuje moduł (bounded context) aplikacji. Jak postanowiłem tak zrobiłem czego rezultatem jest poniższy projekt przykładowy:

https://github.com/matadini/sysmusic

Podczas jego pisania pojawiło się kilka pytań na które, mam nadzieje :) udzielicie mi odpowiedzi:
• Czy obiekty domenowe tj. dane + metody biznesowe – w prostym rozumieniu można rozumieć jako encje JPA bez getterów i setterów, którego stan zmieniamy za pomocą dedykowanych metod biznesowych?
• Czy w przypadku bounded contextów tylko agregat posiada swoje repozytorium (połączenie do bazy) a wszelkie inne relacje są wstawiane do bazy kaskadowo?
• Czy to normalna sytuacja w której to w dwóch kontekstach mam dwie encje odnoszące się do tej samej tabeli w bazie? I czy może być ich więcej? Jak sobie radzić z not nullami jeżeli możemy mieć kilka encji do jednej tabeli.
• Czy w przypadku bounded contextu / modułu testujemy tylko serwis aplikacyjny który wystawiamy na świat zewnętrzny?
• Czy utrzymujecie w swoich projektach commona który przechowuje wszystkie DTO latające po HTTP / interfejsy RMI i klasy przesyłowe, które są kontraktem?
• Czy pisząc RESTowy serwis praktykujecie pisanie do nich dedykowanych klientów które trafiają na waszego firmowego nexusa mavenowego/gradlowego? Widziałem takie podejście w przypadku korzystania GCP i chciałbym u siebie w firmie to przeforsować.
• Jak wyglądają u was testy integracyjne? Pisząc serwis restowy + klienta nie widzę sensu pchania mojego serwera do innych testów skoro przetestowałem serwis i klienta po którym inni będą się ze mną integrować.
• Wracając do obiektów domenowych i modułów z heksagonu: w którymś Microsoftowym podręczniku czytałem że warstwie domeny nie powinno być absolutnie żadnej informacji na temat infrastruktury/frameworka ORM – a w moim podejściu jest, jak to się robi w waszych projektach?
• Jak wygląda u was testowanie z użyciem bazy w pamięci? Mockujecie repozytoria czy tak jak u mnie, stawiacie na każdy test czystą bazę H2? Niestety moje podejście wydłuża czas testów przez co chciałbym się dowiedzieć jak robi to szybciej.

Będę niezmiernie wdzięczny za wszelkie wskazówki i odpowiedzi dotyczące powyższego projektu. Wspomnę jedynie że tylko moduł BAND można uznać za względnie skończony.

0
MrMadMatt napisał(a):

Podczas jego pisania pojawiło się kilka pytań na które, mam nadzieje :) udzielicie mi odpowiedzi:
• Czy obiekty domenowe tj. dane + metody biznesowe – w prostym rozumieniu można rozumieć jako encje JPA bez getterów i setterów, którego stan zmieniamy za pomocą dedykowanych metod biznesowych?

W architekturze heksagonalnej twoje obiekty domenowe nie powinny mieć nic wspólnego z Hibernate / Spring / innym frameworkiem. Powinien istnieć tylko interfejs Repository, a implementacja w całkowicie innym module. I niestety tutaj mamy zgrzyt, bo ciężko jest to zrobić Hibernate z adnotacjami.

• Czy w przypadku bounded contextów tylko agregat posiada swoje repozytorium (połączenie do bazy) a wszelkie inne relacje są wstawiane do bazy kaskadowo?

Według mnie tak agregat to integralna rzecz.

• Czy to normalna sytuacja w której to w dwóch kontekstach mam dwie encje odnoszące się do tej samej tabeli w bazie? I czy może być ich więcej? Jak sobie radzić z not nullami jeżeli możemy mieć kilka encji do jednej tabeli.

Bounded context właściciel powinien odczytywać encję z bazy, a bounded context client przez dedykowany publiczny interfejs.

• Czy w przypadku bounded contextu / modułu testujemy tylko serwis aplikacyjny który wystawiamy na świat zewnętrzny? 

Według mnie mając bounded context powinieneś testować z poziomu tego bounded context, Czyli prawdopodobnie tak jak mówisz z poziomu, który użytkownik używa. Zapomnij o mokowaniu włąsnych klas. Mokować można np. zewnętrzne API lub system plików etc.

• Czy utrzymujecie w swoich projektach commona który przechowuje wszystkie DTO latające po HTTP / interfejsy RMI i klasy przesyłowe, które są kontraktem? 

Ten common to według mnie powinien być moduł domain. Gdzie tylko odpowiednie klasy . interfejsy powinny mieć dostęp publiczny.

• Czy pisząc RESTowy serwis praktykujecie pisanie do nich dedykowanych klientów które trafiają na waszego firmowego nexusa mavenowego/gradlowego? Widziałem takie podejście w przypadku korzystania GCP i chciałbym u siebie w firmie to przeforsować.

Czyli Twoi koledzy nie umieją napisać w Javie klienta REST? Przecież to 2 linijki... Co jak któryś system będzie chciał być reaktywny?

• Jak wyglądają u was testy integracyjne? Pisząc serwis restowy + klienta nie widzę sensu pchania mojego serwera do innych testów skoro przetestowałem serwis i klienta po którym inni będą się ze mną integrować.

Zawsze test integracyjny powinien istnieć. Zawsze coś pomiędzy może nawalić.

• Wracając do obiektów domenowych i modułów z heksagonu: w którymś Microsoftowym podręczniku czytałem że warstwie domeny nie powinno być absolutnie żadnej informacji na temat infrastruktury/frameworka ORM – a w moim podejściu jest, jak to się robi w waszych projektach? 

Czyli łamiesz zasadę architektury heksagonalnej.

• Jak wygląda u was testowanie z użyciem bazy w pamięci? Mockujecie repozytoria czy tak jak u mnie, stawiacie na każdy test czystą bazę H2? Niestety moje podejście wydłuża czas testów przez co chciałbym się dowiedzieć jak robi to szybciej.

Osobiście wolę mieć wszystkie testy napisane do publicznej fasady z bazą H2. Mockuję tylko zewnętrzne API. Taki test jest stabilny i nie muszę pisać testóœ dla Szcepana Fabera :)

0
nie100sowny napisał(a):
MrMadMatt napisał(a):

Podczas jego pisania pojawiło się kilka pytań na które, mam nadzieje :) udzielicie mi odpowiedzi:
• Czy obiekty domenowe tj. dane + metody biznesowe – w prostym rozumieniu można rozumieć jako encje JPA bez getterów i setterów, którego stan zmieniamy za pomocą dedykowanych metod biznesowych?

W architekturze heksagonalnej twoje obiekty domenowe nie powinny mieć nic wspólnego z Hibernate / Spring / innym frameworkiem. Powinien istnieć tylko interfejs Repository, a implementacja w całkowicie innym module. I niestety tutaj mamy zgrzyt, bo ciężko jest to zrobić Hibernate z adnotacjami.

• Czy w przypadku bounded contextów tylko agregat posiada swoje repozytorium (połączenie do bazy) a wszelkie inne relacje są wstawiane do bazy kaskadowo?

Według mnie tak agregat to integralna rzecz.

• Czy to normalna sytuacja w której to w dwóch kontekstach mam dwie encje odnoszące się do tej samej tabeli w bazie? I czy może być ich więcej? Jak sobie radzić z not nullami jeżeli możemy mieć kilka encji do jednej tabeli.

Bounded context właściciel powinien odczytywać encję z bazy, a bounded context client przez dedykowany publiczny interfejs.

Nie wiem czy dobrze się zrozumieliśmy. W projekcie mam BandRecord i PublisherRecord, obie fizycznie w założeniach mają się odnosić do jednej tabeli w bazie i tu stawiam pytanie, bo nie wiem: czy to normalne że w dwóch bounded contextach mam dwie encje do jednej tabeli? A jeżeli tak można to jak sobie radzić ze spójnością not null etc.

• Czy w przypadku bounded contextu / modułu testujemy tylko serwis aplikacyjny który wystawiamy na świat zewnętrzny? 

Według mnie mając bounded context powinieneś testować z poziomu tego bounded context, Czyli prawdopodobnie tak jak mówisz z poziomu, który użytkownik używa. Zapomnij o mokowaniu włąsnych klas. Mokować można np. zewnętrzne API lub system plików etc.

• Czy utrzymujecie w swoich projektach commona który przechowuje wszystkie DTO latające po HTTP / interfejsy RMI i klasy przesyłowe, które są kontraktem? 

Ten common to według mnie powinien być moduł domain. Gdzie tylko odpowiednie klasy . interfejsy powinny mieć dostęp publiczny.

• Czy pisząc RESTowy serwis praktykujecie pisanie do nich dedykowanych klientów które trafiają na waszego firmowego nexusa mavenowego/gradlowego? Widziałem takie podejście w przypadku korzystania GCP i chciałbym u siebie w firmie to przeforsować.

Czyli Twoi koledzy nie umieją napisać w Javie klienta REST? Przecież to 2 linijki... Co jak któryś system będzie chciał być reaktywny?

Nie zaglądam kolegom w kompetencję aczkolwiek wydaje mi się sensownym rozwiązaniem aby autor resta pisał do niego klienta, patrz: GCP. I pytam o wasze doświadczenia forumowicze ;)

• Jak wyglądają u was testy integracyjne? Pisząc serwis restowy + klienta nie widzę sensu pchania mojego serwera do innych testów skoro przetestowałem serwis i klienta po którym inni będą się ze mną integrować.

Zawsze test integracyjny powinien istnieć. Zawsze coś pomiędzy może nawalić.

Pytanie: czy wystarczy mi mój jeden test integracyjny w sysmusic-integration czy jest sens pchać mój projekt jeszcze gdzieś do innych projektów z testami integracyjnymi?

• Wracając do obiektów domenowych i modułów z heksagonu: w którymś Microsoftowym podręczniku czytałem że warstwie domeny nie powinno być absolutnie żadnej informacji na temat infrastruktury/frameworka ORM – a w moim podejściu jest, jak to się robi w waszych projektach? 

Czyli łamiesz zasadę architektury heksagonalnej.

No wiem, aczkolwiek w materiałach Bottegi i Sławka Sobótki też widziałem że obiekty domenowe są oznaczane jako @Entity i teraz jak to pogodzić aby napisać system łatwy do utrzymania i żeby nie nawalić guana na green fieldzie ;)

• Jak wygląda u was testowanie z użyciem bazy w pamięci? Mockujecie repozytoria czy tak jak u mnie, stawiacie na każdy test czystą bazę H2? Niestety moje podejście wydłuża czas testów przez co chciałbym się dowiedzieć jak robi to szybciej.

Osobiście wolę mieć wszystkie testy napisane do publicznej fasady z bazą H2. Mockuję tylko zewnętrzne API. Taki test jest stabilny i nie muszę pisać testóœ dla Szcepana Fabera :)

Dla każdego testu stawiasz od zera bazę H2 czy jedziesz na raz wygenerowanej dla wszystkich?

0
  1. A propos bounded context: Tabela Publisher powinna mieć klucz obcy do Band. To nie jest jedno i to samo. W przypadku twojego podejścia nie da się stworzyć band, który nie jest publisherem.

  2. A propos pisania klienta. Czyli teraz będziesz ludziom w firmie pisał klienty? Jeden zachce blokującego klienta, drugi reaktywnego, trzeci z logowaniem, piąty z service discovery etc. Później zmienisz REST na GraphQL i zabawa zacznie się od początku. Co gdy drugi zespół zechce pisać swoje kodziki w Go albo C#? Też im napiszesz? Polecam: https://codeburst.io/so-there-are-two-paths-to-be-considered-here-1d1aef6007e9 Podejrzewam, że GCP tak robi, ponieważ nie zalezy im na luźnym powiązaniu miedzy Tobą a ich systemami (jak to ma miejsce w mikroserwisach), a bardziej na zapewnieniu kompatybilności w czytelny (i kosztowny z drugiej strony) sposób.

  3. A propos Entity i Bottegi. Najlepiej spróbować czegoś lżejszego niż Hibernate co Ci nie grzebie w klasach. JOOQ, QueryDSL przykładowo

  4. Raz wygenerowana. W @Before tylko robię deleteAll

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