Wpis z mikrobloga

Piszę apkę przy użyciu webflux, jednocześnie stosując DDD i mam zagwozdkę, mianowicie, w warstwie domenowej mam UserRepository, który później jest implementowane w warstwie infrastructure. Z racji tego, że webflux zakłada, że mamy posługiwać się Mono ~~i Flux ~~zastanawiam się czy UserRepository jako argument w metodach powinien przyjmować podstawowy obiekt czy może już na tym poziomie powinien przyjmować Mono~~. Dla przykładu:

public interface UserRepository {

Mono save(Mono user);
Mono findByUsername(Mono username);
Mono findById(Mono id);
}
czy
public interface UserRepository {

Mono save(User user);
Mono findByUsername(String username);
Mono findById(Long id);
}.

Co sądzicie?
#programowanie #java #springboot~~~~~~
  • 19
@FalscheFreunde: Interfejs powinien przyjmować obiekt domenowy, ten powinien być zmieniony na mono dalej. Do tego implementacja nie powinna się odbywać w infrastructure tylko w portach/adapterache. U mnie ten pakiet nazywa adaptera. A w infractructure są konfiguracje raczej
@happy3dprints narazie to czysty poc ale wiem, że nie powinno się przekazywać czystego stringa tylko wrapper na niego. Mniemam, że analogicznie, w sytuacji gdzie mam interface UserService:
public interface UserService {

Mono registerUser(CreateUserDto createUserDto);

Mono getUserById(Long id);

}
argumenty też powinny być domenowe/nie owrappowane Mono/Flux, zgadza się?
@FalscheFreunde: Zależy jak bardzo chcesz się posunąć. DTO niby powinny być w warstwie adapterów i wchodzić jakimś restem czy czymś tam, a registerUser powinna przyjąć jakaś komendę. U mnie w pracy dto siedzą w adapterach i maja metody .toDomain()
Jak chcesz szybko zrobić poc i zapomnieć o tym kodzie to przepychanie mono wydaje sie być mądre (bo oszczędza czas), ale jak z tego poca wyjdzie produkcja to zapewne lepiej sie postarać
@Saly wcześniej nie miałem do czynienia z DDD więc nie miałem rozeznania czy przyniesie to jakieś korzyści ale jak jednoznacznie orzekliście, że to zły pattern to nie ma tematu. Upewnię się @Saly, @jaca_66, analogicznie dla UserService też powinienem stosować obiekt domenowy i w innym miejscu dokonywać jego transformacji, tak?
@FalscheFreunde: Jeżeli używasz architektury hexagonalnej (a wiele wskazuje, ze używasz) plus chcesz się zabawić w czystość to tak.
(Opisuje sytuacje idealna i wzorcowa, ciężka to uzyskać w praktyce w dużej aplikacji) Robisz pakiet domain, ports oraz infrastructure (niektórzy robią moduły maveowe ale dla mnie to za dużo).
W pakiecie domain umieszczasz tylko i wyłącznie kod domenowy, biznesowy, te wszystkie swoje ify i klaski. 0 kodu frameworkow, 0 springa. Nawet adnotacji springa
W pakiecie domain umieszczasz tylko i wyłącznie kod domenowy, biznesowy, te wszystkie swoje ify i klaski. 0 kodu frameworkow, 0 springa. Nawet adnotacji springa unikasz


@happy3dprints: nie programuję w javie, ale pytanie: jak mapujesz agregaty na bazę? Inny typ mapowania niż adnotacje czy robisz dodatkową warstwę translacji?

Mógłbyś dać screena z hierarchią katalogową, którą opisałeś w swoim poście?
@masterix: To dosłownie 3 foldery, adapters, domain oraz architecture. Wewnątrz nich już po bożemu masz katalogi per feature.
Tutaj jest giga problem z tym co piszesz, czysto to robisz tak, ze inne obiekty zapisujesz do bazy, a na innych operujesz domenowo. Ale niestety w praktyce często jest tak, ze te 2 obiekty są identyczne, dlatego wiele osób (w tym ja) akceptuje, ze używasz jakiś adnotacji bazodanowych na obiektach z domeny. Ale
tak, są mapery, klasa bazodanowa posiada metodę .from(DomainClass)


@happy3dprints: i mapujesz przez refleksję tak? Czy robisz gettery na każde pole tylko pod kątem mapowania?

Ale natomiast jeżeli projekt nie jest chamskim crudem, jeżeli jest event soursing czy coś takiego bardziej gdzie jest logika a nie crud to miodzio i bajka takie podejście.


@happy3dprints: No i jak wtedy byś to zrobił? Bo taki obiekt domeny musisz odtworzyć aby móc przeprowadzić na
@masterix: Wiele zależy. Jak masz serio ddd, serio masz wystawione tylko zachowania bez geterow to można wystawić metodę ,snapshot() która zwróci jakiś obiekt gotowy do serializacji oraz metodę restoreFrom(snapshot) która wczyta obiekt.
Jeżeli masz „ddd” to jest cała masa frameworkow co refleksja czy innymi mechanizmami przekopiuja. „Ddd” czyli setName(…) i getNane(), masz changeName(…) bez gettera.
Jak masz event soursing to jeszcze inaczej.
Jak ma cruda to „encja na twarz i pchasz”
Ty masz jakieś crud z cqrs chyba czy coś takiego.


@happy3dprints: częściowo CRUD (np zapisy konfiguracji), ale też są zachowania i operacje biznesowe, zmiany ustawień obowiązują od kolejnego okresu rozliczeniowego, opłaty są naliczane na różne sposoby itd. Idealnie nie jest, ale lepiej niż encja na twarz i pchasz :)