41
EVENT SOURCING (W PHP) PIOTR KACAŁA

Event sourcing w PHP (by Piotr Kacała)

Embed Size (px)

Citation preview

EVENT SOURCING (W PHP)PIOTR KACAŁA

EVENT SOURCING

ZBUDUJMY SOBIE KOSZYK!

POBIERANIE ZAWARTOŚCI KOSZYKA

mysql> select * from cart_products; +---------+------------+ | cart_id | product_id | +---------+------------+ | 1 | 124 | | 1 | 89 | +---------+------------+

DODANIE PRODUKTU DO KOSZYKA

POST /CARTS/{CID}/PRODUCTS

INSERT INTO CART_PRODUCTS (…)

USUNIĘCIE PRODUKTU Z KOSZYKA

DELETE /CARTS/{CID}/PRODUCTS/{PID}

DELETE FROM CART_PRODUCTS (…)

DOBRA, MAMY KOSZYK.

PRZYPOMNIJMY

mysql> select * from cart_products;

+---------+------------+

| cart_id | product_id |

+---------+------------+

| 1 | 124 |

| 1 | 89 |

+---------+------------+

POROZMAWIAJMY O PIENIĄDZACH

A CO JEŚLI?

select * from salda_bankowe; +---------------------+----------------+ | rachunek | ile_pieniazkow | +---------------------+----------------+ | 4444 3333 2222 1111 | 1000 | +---------------------+----------------+

PRZECIEŻ PISZE, ŻE 1000.

TRUDNO SIĘ KŁÓCIĆ

+---------------------+----------------+ | rachunek | ile_pieniazkow | +---------------------+----------------+ | 4444 3333 2222 1111 | 1000 | +---------------------+----------------+

CZYM JEST EVENT SOURCING?

EVENT STORE

Cart #1 Was Created

Product #B Added

To The Cart

Product #A Removed

From The Cart

Product #A Added

To The CartCart #1 Was Checked Out

EVENT STORE

Cart #1 Was Created

Product #B Added

To The Cart

Product #A Removed

From The Cart

Product #A Added

To The CartCart #1 Was Checked Out

JAK UPRAWIAĆ EVENT SOURCING (W PHP)?

TRADYCYJNY KOSZYK

class Cart { private $id; private $products = []; public function add($productId) { // changing the state of the cart $this->products[] = $productId; } }

KOSZYK PRODUKUJĄCY EVENTY

class Cart { private $id; private $products = []; private $raisedEvents = []; public function add($productId) { // changing the state of the cart $this->products[] = $productId; // let's raise an event $this->raisedEvents[] = new ProductAddedToCart($this->id, $productId); } }

CartRepository::add(cart)

EVENT STORE

Cart Was Created

Product #2 Added

To The Cart

Product #1 Added

To The CartCart Was

Checked OutProduct #1 Removed

From The Cart

EVENT STORE

mysql> select * from event_store; +----+--------------+-------------------------------------------+ | id | aggregate_id | event | +----+--------------+-------------------------------------------+ | 1 | 1 | CartWasCreated({"cartId":"1"}) | | 2 | 1 | ProductAddedToCart({"productId":"A"}) | | 3 | 1 | ProductRemovedFromCart({"productId":"A"}) | | 4 | 1 | ProductAddedToCart({"productId":"B"}) | +----+--------------+-------------------------------------------+

ODTWARZANIE AGREGATU KOSZYKA W REPOZYTORIUM

class EventSourcedCartRepository implements CartRepository { public function find($aggregateId) { $events = $this->eventStore->findEvents($aggregateId); $cart = new Cart(); // inicjalizacja pustego agregatu // "nagrywanie" eventów na agregacie cartu foreach($events as $event) { // metoda apply() woła odpowiednie metody prywatne // na podstawie nazwy przekazywanego eventu, np. // ProductWasAddedToCart => applyProductWasAddedToCart $cart->apply($event); } } }

ENCJA

class Cart{ // this method is called by event store to replay event on the cart protected function applyProductAddedToCart(ProductAddedToCart $event) { $this->products[] = $event->getProductId(); } }

OBIE METODY

class Cart { public function add($productId) { if ($this->products > 2) { throw new CartLimitExceeded(); } // raise the event $event = new ProductAddedToCart($this->id, $productId); $this->raisedEvents[] = $event; // change the state $this->applyProductAddedToCart($event); } // change the state, this is called by Event Store public function applyProductAddedToCart(ProductAddedToCart $event) { $this->products[] = $event->getProductId(); } }

CO Z WYDAJNOŚCIĄ?

JAK ROBIĆ ZAPYTANIA?

EVENT STORE

mysql> select * from event_store; +----+--------------+-------------------------------------------+ | id | aggregate_id | event | +----+--------------+-------------------------------------------+ | 1 | 1 | CartWasCreated({"cartId":"1"}) | | 2 | 1 | ProductAddedToCart({"productId":"A"}) | | 3 | 1 | ProductRemovedFromCart({"productId":"A"}) | | 4 | 1 | ProductAddedToCart({"productId":"B"}) | +----+--------------+-------------------------------------------+

CQRS! READ MODEL

MAŁY RECAP

Obiekt domeny

Event Store

Listenery

Eventy

TRAFIAJĄ DO

ZAPISYWANE W

PRODUKUJE

PROJEKCJE

class CurrentCartProductsProjector { public function applyProductAddedToCart(ProductAddedToCart $event) { $this->connection->query('insert into cart_products ...'); } public function applyProductRemovedFromCart(ProductRemovedFromCart $event) { $this->connection->query('delete from cart_products ...'); } }

POBIERANIE ZAWARTOŚCI KOSZYKA

mysql> select * from cart_products; +---------+------------+ | cart_id | product_id | +---------+------------+ | 1 | 124 | | 1 | 89 | +---------+------------+

CQRS W PEŁNI SWOJEJ CHWAŁY

Cart::add

Zapis w Event Store

Product Was Added To Cart

Cart State Projector

SQL

Redis

CO Z ZADANIEM OD PANI MAŁGOSI?

PODSUMOWANIE

PLUSY EVENT SOURCINGU

- HISTORYCZNY STAN APLIKACJI

- DEBUGOWANIE

- PROSTY MODEL ZAPISU

- ODPORNOŚĆ NA KREATYWNOŚĆ BIZNESU

- ŁATWA SKALOWALNOŚĆ

- WSPÓŁGRA Z MIKROSERWISAMI

MINUSY EVENT SOURCINGU

- PRÓG WEJŚCIA (ZMIANA PRZYZWYCZAJEŃ)

- KONIECZNOŚĆ SHARDOWANIA EVENT STORE’U*

- DŁUŻSZY ŁADOWANIE OBIEKTÓW DOMENOWYCH**

- ZWIĘKSZA ZŁOŻONOŚĆ APLIKACJI (VS CRUD)

* NIE DOTYCZY WSZYSTKICH APLIKACJI

** ROZWIĄZANY PRZEZ SNAPSHOTY

/QANDIDATE-LABS/BROADWAY

CIEKAWOSTKA

PYTANIA?

DZIĘKI! d:-)

/WORK