Clean architecture, CQRS, RDMS, Spring IOC - pierwsze podejście

Clean architecture, CQRS, RDMS, Spring IOC - pierwsze podejście
EZ
  • Rejestracja:około 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:32
0

Cześć napisałem prostą aplikację komunikacyjną typu Messenger udostępniającą
REST api stosując Clean architecture i CQRS. Na razie żeby sobie uprościć
wykorzystuje RDMS jako bazę zarówno do zapisu jak i odczytu ale nic nie stoi
na przeszkodzie aby podpiąć np. Elasticsearch.

Byłoby fajnie dostać feedback od kogoś kto stosował któreś z wymienionych rozwiązań.

Repozytorium: messenger-backend

edytowany 1x, ostatnio: eziomou
semicolon
  • Rejestracja:ponad 5 lat
  • Ostatnio:prawie 5 lat
  • Postów:114
2

NUDA.. To jest kod, który nic nie robi. Skakałem po projekcie oglądając niemal puste klasy.., ale poza tym to dwie rzeczy zwróciły moją uwagę:

Klasa AbstractEntity jest trochę dziwna narzuca jeden rodzaj ID, który w dodatku można go zmieniać. Przez co porównanie może z czasem zaskoczyć.

Hash liczysz na danych, które mogą się zmienić np. NotificationCreateCommand taki hash, który się zmienia w czasie więc też może zaskoczyć :-)

Część klas tylko przetrzymuje dane, i służą tylko do podawania dalej. W przypadku takich klas kod byłby prostszy jakby te klasy operowały niemodyfikowalnymi wartościami, ale nie wiem czy to byłoby proste do spięcia z JPA.

EZ
  • Rejestracja:około 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:32
0

Dzięki za przejrzenie kodu, to moje pierwsze podejście z clean architecture
i cqrs więc na razie chciałem sprawdzić jak będzie to funkcjonowało w ramach
całego projektu.

Kopiuj
Hash liczysz na danych, które mogą się zmienić np. NotificationCreateCommand taki hash, który się zmienia w czasie więc też może zaskoczyć :-)

Możesz doprecyzować, co w tej klasie się zmienia w czasie?

Kopiuj
Część klas tylko przetrzymuje dane, i służą tylko do podawania dalej. W przypadku takich klas kod byłby prostszy jakby te klasy operowały niemodyfikowalnymi wartościami, ale nie wiem czy to byłoby proste do spięcia z JPA.

Jakie dokładnie klasy masz na myśli? Klasy domeny są niezmienne, chodzi Ci o DTO?

edytowany 1x, ostatnio: eziomou
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
0
eziomou napisał(a):
Kopiuj
Hash liczysz na danych, które mogą się zmienić np. NotificationCreateCommand taki hash, który się zmienia w czasie więc też może zaskoczyć :-)

Możesz doprecyzować?

Hash nie może się zmieniać podczas życia obiektu. Jeśli się zmieni wiele kolekcji może przestać działać, np HashMap i HashSet


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
EZ
  • Rejestracja:około 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:32
0
KamilAdam napisał(a):
eziomou napisał(a):
Kopiuj
Hash liczysz na danych, które mogą się zmienić np. NotificationCreateCommand taki hash, który się zmienia w czasie więc też może zaskoczyć :-)

Możesz doprecyzować?

Hash nie może się zmieniać podczas życia obiektu. Jeśli się zmieni wiele kolekcji może przestać działać, np HashMap i HashSet

Jasne, chodzi o to że przekazuje set i nie robię kopii? Jeśli tak to oczywiście błąd z mojej strony dzięki za uwagę.

edytowany 5x, ostatnio: eziomou
semicolon
Chodzi o podstawy. Spróbuj pierw zrozumieć na jakich założeniach HashSet bądź HashMap pozwala szybciej wyszukać obiekt w kolekcji.
semicolon
A potem dodaj do tego fakt, że jak mutowalny obiekt zmienia wartość to jednocześnie zmienia się jego hash - zadaj sobie pytanie, jak taka rzecz wpływa na szukanie?
EZ
@semicolon: Sory, nie widziałem wcześniej Twojego komentarza. Tak, wiem jak działa HashSet i HashMap ale z tego co pamiętam to w tym projekcie nie ma akurat przykładu Setu operującego na obiektach posiadających własną implementację hashCode. A mutowalny obiekt może mieć niezmienny hash np. final id jako hash i reszta mutowalna jak w niektórych obiektach biznesowych z ddd.
KA
KA
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 5 lat
  • Lokalizacja:Warszawa
  • Postów:1683
5

Sprawdziłam tylko kilka klas - wszystkiego mi się nie chciało. Odnośnie ID obejrzyj to a będziesz wiedzieć co robisz tam źle:

  1. stosujesz przestarzałego mavena
  2. mnóstwo boilerplate'u - niepotrzebnie wydzielasz tyle osobnych modułów - zastosuj monolit i pakiety javowe. tutaj podział na takie moduły jak zrobiłeś nie dał Ci żadnej przewagi
  3. nie dziel za pomocą warstw typu persistance, core itd.. a funkcji biznesowych
  4. AbstractEntity - może nazwij badziej UuidEntity - przede wszystkim Id zmień na UUID i nadawaj to od razu, setterów do id nie rób - id niech się nie zmienia albo masz je z bazy albo od razu nadajesz UUID, stosuj więcej final
  5. nie stosuj sekwencji z bazy ani hibernetowych - to są zjeb*** mechanizmy
  6. poco postfix "Model" na encjach?
  7. gettery i settery -> lombok albo najlepiej zmień język na Kotlin
  8. @Column(nullable = false) - czy jak to zastosujesz to jak tworzy Ci się schemat z encji to robi constraint not null na tym polu?
  9. mapper spoko, ale nie rozumiem czemu nadużywasz @Component - stosuj hexagonala
  10. @Repository spoko, ale możesz nawet wydzielić fajniejszy interfejs dla repozytoriów swoich aby za każdym razem dla encji, które dziedziczą po AbstractEntity i mają zawsze ID typu Long aby nie musieć powtarzać tego extends JpaRepository<UserDataModel, Long>, będziesz mieć łatwiej, zerknij na dział "Repozytorium dla encji" https://4programmers.net/Forum/Java/281698-uuid_version_i_spring_data_na_co_trzeba_uwazac
  11. Optionale w repo - najs
  12. boolean existsByUsername(String username); - jeżeli będziesz przed jakimś zapisem korzystać z tej metody i gdzieś sprawdzać najpierw czy exists aby nie poleciał Ci wyjątek to jest to błąd check-then-act
  13. UserJpaReadonlyRepository - a adnotacja to @Component? dodaj lomboka, klasa trochę widmuszka
  14. UserJpaRepository - najs, że robisz takie nazwy klas (lepsze to niż Impl)
  15. UserMapper - prosta fuinkcja od razu @Componenet - nadużywasz springa, pisz czysto w javie a w springu rejestruj fasady całych modułów większych
  16. NotificationTypeDataModelProvider orElseGet i te type.setName(s); słabo to wygląda

ogółem 7/10 więc w miarę spoko


PROGRAMY NA ZAMÓWIENIE, ZALICZENIA STUDENCKIE, KONFIGURACJA SERWERÓW, SYSTEMÓW I BAZ DANYCH, STRONY INTERNETOWE, POMOC W PROGRAMOWANIU, POPRAWIENIE I OPTYMALIZACJA APLIKACJI
JAVA, C++, LINUX, WWW, SQL, PYTHON
POSIADAM KOMERCYJNE DOŚWIADCZENIE
TANIO, SZYBKO I PORZĄDNIE
Z KOMENTARZAMI OBJAŚNIAJĄCYMI KOD
PISZ NA PRYWATNĄ WIADOMOŚĆ
CENY JUŻ OD 49,99ZŁ ZA PROGRAM
ZAJMIJ SIĘ TYM CO CIĘ NAPRAWDĘ INTERESUJE!
Charles_Ray
Nie rozumiem z tym uuidem. Możesz mieć klucz generowany przez sekwencje z bazy, natomiast to equals/hashcode stosować własny UUID. Moim zdaniem to są komplementarne mechanizmy. Po drugie nie jest fanem Lomboka. Oprócz tego podpisuje się obiema rękami, bdb code review :) (nie zaglądałem w ten kod, odnoszę się do komentarza)
KA
nie wiem ja tam nie uznaje innego id niż UUID. reszta dla mnie to jakieś mechanizmy protezy. po prostu dla mnie UUID to najlepsze ID i jest bezkolizyjne - dla mnie to mechanizm genialny na równi jak blokchain. lombok - nie wiem jak można bez tego w javie, - pisać po pythonowemu bez getterów i setterów? dlatego zawsze stosuje lomboka (mniej kodu do czytania masz) albo kotlina
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

nie dziel za pomocą warstw typu persistance, core itd.. a funkcji biznesowych

Argument bez sensu kiedy masz taki mikro projekt który realizuje jakąś jedną małą funkcje biznesową. Zresztą jest to dodatkowo bez sensu, bo o ile nie zrobisz tego z głową (tzn nie wydzielisz interfejsów dla interakcji np. z repozytoriami i do komunikacji z innymi serwisami) to spora szansa ze zrobisz potworka gdzie logika domenowa jest pomieszana ze szczegółami implementacji takich rzeczy jak persystencja czy komunikacja z innymi serwisami.
Więc spoko, jak masz monolit to ma to sens. Tutaj, nie ma.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
KA
Argument bez sensu kiedy masz taki mikro projekt który realizuje jakąś jedną małą funkcje biznesową - no tak też myślę, ale nie wiem po co taki mały projekt aż tak dzielić na trzy projekty
EZ
  • Rejestracja:około 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:32
0

@karolinaa
Wielke dzięki za przejrzenie kodu i uwagi.

    1. Rzeczywiście w przypadku takiego malutkiego projektu jest to przerost formy nad treścią jednak tak jak w tytule tematu, chciałem wypróbować jak najwięcej z Clean Architecture i CQRS.
    1. Jak wyżej w przypadku małego projektu tego nie widać, ale dzięki podziale na moduły w przypadku większego projektu osobne zespoły mogą je osobnie kompilować, wersjonować itd.
    1. 5, 10 Dzięki za uwagę, już zastanawiałem się nad UUID tylko nie wiem czy jako klucz główny i we wszystkich tabelach, jednak 16 bajtów a 4 lub 8 robi różnicę.
    1. W celu konsekwentego nazewnictwa - mam XQueryModel dla modeli widoku więc modele bazonadowe to XDataModel, poza tym wydaje mi się, że taka nazwa mówi więcej niż np. XData.
    1. 13 Szczerze mówiąc nie przepadam za Lombokiem, może Kotlin.
    1. Tak
    1. 15 OCP, nastawiam się, że powstawie więcej klas domeny więc i więcej klas mapujących, musiałbym wtedy za każdym razem dodawać je do fasady. Skoro moduł persistence-jpa jest już i tak zależny od Springa więc czemu sobie nie ułatwić?
    1. Repozytoria XReadonlyRepository wykorzystywane są tylko przez warstwę aplikacji, ale w klasie UserDataModel rzeczywiscie brakowało wymuszenia unikalności (@Column(unique = true))
edytowany 1x, ostatnio: eziomou
KA
‚XData” data to wgle fajnie brzmi ale nic nie mówi możesz to wyrzucić te słówko data. Data w teorii to nawet ja jestem i mój kod dna
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4706
1
semicolon napisał(a):

NUDA.. To jest kod, który nic nie robi. Skakałem po projekcie oglądając niemal puste klasy.., ale poza tym to dwie rzeczy zwróciły moją uwagę:

Im więcej buzzwordów i technologii tym mniej program robi
George Stanley McGovern


jeden i pół terabajta powinno wystarczyć każdemu
semicolon
Niezłe
AK
Pewnie bym nie zajrzał w wątek bez tego "Clean Architecture" :) Miałem dobrą intuicję (przed zajrzeniem)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)