Witam wszystkich,
Mam kilka pytań dotyczących CQRS + ES + DDD.
Co do CQRS jego założenie jest proste chodzi o podział zapytań na Commandy który zmieniają stan i nic nie zwracają oraz Query które nie zmieniają stanu i zwracają rezultat. Ponad to dzielimy model danych na model Write i model Read (logicznie i fizycznie), gdzię model Read może być oczywiście znacznie uproszczony architektonicznie.
-
Jak się zachować w sytuacji kiedy MUSIMY zwrócić wartość do klienta po wykonaniu Commanda. Oczywiście wiem, że zawsze da się tak zaprojektować system aby Command nie musial nic zwracać... ale założmy czysto teoretycznie że chciałbym taką operacje wykonać, jak to zrobić w sensowny sposób? (Do głowy przychodzi mi jeden spobób. Przypadek dodawania usera i zwracania jego identyfikatora. Zamiast generować identyfikator w logice biznesowej moglibyśmy go przekazać w Commandzie (GUID) a następnie zwrócić na poziomie controllera. Jednak ten sposób nie wydaje się elegancki bo w pewnym sensie i tak łamiemy założenie nie zwracania rezultatu...)
-
Parametryzowanie zapytań.
W wielu żródłach widziałem poniższy sposób implementowania części Query:
interface QueryResult {
}
interface QueryHandler<T extends QueryResult> {
T handle();
}
A co jeżeli chce dodac filtry lub paging do warunków zapytania? .Jak w powyższym przykładzie ten przypadek jest obsługiwany? Czy nie można zrobić po prostu:
interface QueryHandler<T extends QueryResult, K extens QueryParam> {
T handle(K filters);
}
- Aktualizacja modelu Read.
Założmy że mamy przypadek rejestracji usera w systemie. Po przechwyceniu Commanda przez odpowiedni handler wykonujemy operacje stworzenia nowego usera (User jest agregatem). Rozumiem, że po wykonaniu akcji powinniśmy opublikować event który zostanie złapany przez odpowiedni handler służący do aktualizacji modelu read?
RegisterUserCommand implements Command {
String login;
char[] password;
}
UserRegisteredEvent implements Event {
UserId userId;
String login;
char[] password;
}
RegisterCommandHandler implements CommandHandler<RegisterUserCommand> {
UserRepository userRepo;
IdGenerator generator;
DomainEventPublisherFactory domainEventPublisherFactory
void handle(RegisterUserCommand cmd) {
UserId userId = UserID.createFrom(generator.generate());
User user = new User(userId, new UserData(cmd.getLogin, cmd.getPassword()));
userRepo.save(user);
domainEventPublisherFactory.instance().publish(new UserRegisteredEvent(userId, user.getLogi(), user.getPassworD()) //mozemy tez opublikowac event w konstruktorze
}
}
UserRegisteredHandler implements EventHandler<UserRegisteredEvent > {
void handle(UserRegisterdEvent event) {
//update read model.
}
}
- Odnosząc się do powyższego pseudo kodu. Załóżmy że chciałbym go rozszerzyć o event sourcing, czy w takim wypadku muszę stworzyć nową "tabele" która przechowuję całą historię zdarzeń (wszystkie eventy) aplikacji? Czyli oprócz modelu Read i Write mamy jeszcze historie stanu naszego agregatu oraz dodatkowe handlery służące do zapisu eventów w EventStory? Wychodzi na to, że każdy event powinien mieć przynajmniej 2 EventHandlery?
UserRegisteredHandler implements EventHandler<UserRegisteredEvent > {
void handle(UserRegisterdEvent event) {
//update read model.
}
}
UserRegisteredEventStoreHandler implements EventHandler<UserRegisteredEvent > {
void handle(UserRegisterdEvent event) {
//update event store
}
}
tdudzik