Więc czego mi brakuje?
Zgaduję.
Pierwszą rzeczą, której możesz brakować, jest to, że wystarczy przeładować zdarzenia dla stanu, który odbudowujesz. Jeśli możesz dokładnie modelować granice transakcji, każdy obiekt może zapisywać zdarzenia oznaczone własnym identyfikatorem, a następnie odczytywać tylko te zdarzenia. Używając relacyjnej bazy danych do przechowywania zdarzeń, indeksowana kolumna identyfikatora przyspieszyłaby to zapytanie. Za pomocą EventStore każdy obiekt miałby swój własny strumień.
W twoim modelu zachowanie tego wymaga pewnej staranności, ponieważ chcesz mieć pewność, że modyfikujesz tylko jeden obiekt w każdej transakcji, i dlatego musisz zadbać o to, aby prawidłowo izolować każdy niezmiennik, który próbujesz egzekwować.
W przypadkach, gdy nie jest to wystarczająco szybkie, nadal masz możliwość tworzenia migawek swojego stanu (zapamiętywania) i utrzymywania tego w „tradycyjnym magazynie”. Każda migawka jest oznaczana numerem sekwencji ostatniego zdarzenia użytego do zbudowania migawki; po przeładowaniu repozytorium najpierw pobiera tę migawkę, a następnie stosuje do niej nowsze zdarzenia. (To sugeruje jakiś rozsądny sposób na przechwycenie najnowszych migawek - albo zdarzenia są również oznaczone numerem sekwencyjnym, albo masz jakiś skuteczny sposób na odczytanie strumienia zdarzeń wstecz, aż dojdziesz do punktu początkowego.)
Nadal istnieje przewaga nad zwykłym podejściem, ponieważ migawki można budować równolegle do zapisów, a nie łączyć się z nimi: wystarczy umieścić detektor zdarzeń w innym wątku / procesie i pozwolić mu wesoło pisać do sklepu z migawkami według dowolnego harmonogramu, który wydaje się rozsądny. W końcu migawka nie musi być przeprowadzana w odpowiednim czasie - wystarczy, że praca nad ponownym zastosowaniem nowszych zdarzeń nie zniszczy Twojej umowy SLA.
(Migawka komplikuje migrację; wszelkie zmiany serializacji modelu unieważnią pamięć podręczną migawek. Oczywiście można odbudować migawki przy użyciu nowej serializacji jako części migracji, a następnie „nadrobić zaległości”, gdy zmiany zostaną wprowadzone w życie.)
Czy przywracanie stanu ze strumienia zdarzeń jest nawet często wykonywane?
Tak to jest. W przykładach CQRS zwykle pokazano, że warstwa aplikacji, po upewnieniu się, że przesłane polecenie jest poprawnie sformułowane, warstwa aplikacji załaduje obiekt domeny z repozytorium, w którym ładunek jest domyślnym konstruktorem, a następnie odtworzony strumień zdarzeń (lub równoważnie połączenie z fabryką z listą zdarzeń).
Dwie inne sprzeczne myśli.
- Za interfejsem repozytorium może znajdować się pamięć podręczna
- Unieważnienie pamięci podręcznej jest jednym z dwóch trudnych problemów.