developing functional domain models with event sourcing
play

Developing functional domain models with event sourcing Chris - PowerPoint PPT Presentation

Developing functional domain models with event sourcing Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io


  1. Developing functional domain models with event sourcing Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson chris@chrisrichardson.net http://plainoldobjects.com http://microservices.io @crichardson

  2. Presentation goal How to develop functional domain models based on event sourcing @crichardson

  3. About Chris Consultant & Founder of Eventuate.IO @crichardson

  4. For more information http://microservices.io http://github.com/cer/microservices-examples/ https://github.com/cer/event-sourcing-examples http://plainoldobjects.com/ https://twitter.com/crichardson http://eventuate.io/ @crichardson

  5. Agenda Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing @crichardson

  6. Traditional monolithic architecture WAR/EAR ACID Spring MVC Banking UI HTML REST/JSON Accounts Browser/ Load RDBMS Client balancer Spring Transfers Hibernate Customers Simple ... develop test Tomcat deploy scale @crichardson

  7. But large and/or complex monolithic applications = Trouble! @crichardson

  8. Using a single RDBMS has its limitations @crichardson

  9. Apply the scale cube Y axis - functional decomposition Scale by Z axis - data partitioning splitting Scale by splitting similar different things things X axis - horizontal duplication @crichardson

  10. Today: use a microservice, polyglot architecture Standalone services Banking UI MoneyTransfer Management Account Management Service Service Account MoneyTransfer Database Database NoSQL DB Sharded SQL @crichardson

  11. But now we have distributed data management problems @crichardson

  12. Example: Money transfer Account Management MoneyTransfer Service Management Service SQL NoSQL MoneyTransfer Account Database Database Money Transfer Account #1 No ACID Account #2 No 2PC @crichardson

  13. Use an event-driven architecture Services publish events when state changes Services subscribe to events and update their state Maintain eventual consistency across multiple aggregates (in multiple datastores) Synchronize replicated data @crichardson

  14. Eventually consistent money transfer transferMoney() MoneyTransferService AccountService MoneyTransfer MoneyTransfer MoneyTransfer Account Account Account Account fromAccountId = 101 fromAccountId = 101 fromAccountId = 101 id = 101 id = 101 id = 202 id = 202 toAccountId = 202 toAccountId = 202 toAccountId = 202 balance = 250 balance = 195 balance = 125 balance = 180 amount = 55 amount = 55 amount = 55 state = INITIAL state = DEBITED state = COMPLETED Subscribes to: Publishes: AccountDebitedEvent Subscribes to: publishes: AccountCreditedEvent AccountDebitedEvent MoneyTransferCreatedEvent MoneyTransferCreatedEvent AccountCreditedEvent DebitRecordedEvent DebitRecordedEvent Message Bus @crichardson

  15. How to atomically update the database and publish an event without 2PC? (dual write problem) @crichardson

  16. Event sourcing For each aggregate: Identify (state-changing) domain events Define Event classes For example, Account: AccountOpenedEvent, AccountDebitedEvent, AccountCreditedEvent ShoppingCart: ItemAddedEvent, ItemRemovedEvent, OrderPlacedEvent @crichardson

  17. Persists events X NOT current state Account table 101 450 Account Event table balance 101 901 AccountOpened 500 open(initial) debit(amount) 101 902 AccountCredited 250 credit(amount) 101 903 AccountDebited 300 @crichardson

  18. Replay events to recreate state Events AccountOpenedEvent(balance) AccountDebitedEvent(amount) AccountCreditedEvent(amount) Account balance @crichardson

  19. Two actions that must be atomic Before: update state + publish events Now: persist (and publish) events Single action that can be done atomically @crichardson

  20. Optimizing using snapshots Most aggregates have relatively few events BUT consider a 10-year old Account ⇒ many transactions Therefore, use snapshots: Periodically save snapshot of aggregate state Typically serialize a memento of the aggregate Load latest snapshot + subsequent events @crichardson

  21. Request handling in an event-sourced application Microservice A pastEvents = findEvents(entityId) new() applyEvents(pastEvents) HTTP Event Account Handler Store newEvents = processCmd(SomeCmd) saveEvents(newEvents) (optimistic locking) @crichardson

  22. Event Store publishes events - consumed by other services Microservice B update() subscribe(EventTypes) Aggregate publish(event) Event Event Subscriber Store update() publish(event) NoSQL materialized view @crichardson

  23. About the event store Hybrid database and message broker Retrieve events for an aggregate Append to an aggregates events Subscribe to events Event store implementations: Home-grown/DIY geteventstore.com by Greg Young My event store - bit.ly/trialeventuate @crichardson

  24. Business benefits of event sourcing Built-in, reliable audit log Enables temporal queries Publishes events needed by big data/predictive analytics etc. Preserved history ⇒ More easily implement future requirements @crichardson

  25. Technical benefits of event sourcing Solves data consistency issues in a Microservice/NoSQL-based architecture: Atomically save and publish events Event subscribers update other aggregates ensuring eventual consistency Event subscribers update materialized views in SQL and NoSQL databases (more on that later) Eliminates O/R mapping problem @crichardson

  26. Drawbacks of event sourcing Weird and unfamiliar Events = a historical record of your bad design decisions Handling duplicate events can be tricky Application must handle eventually consistent data Event store only directly supports PK-based lookup (more on that later) @crichardson

  27. Agenda Why event sourcing? Designing a domain model based on event sourcing Event sourcing and service design Microservices and event sourcing @crichardson

  28. Use the familiar building blocks of DDD Entity Value object With some Services differences Repositories Aggregates @crichardson

  29. Partition the domain model into Aggregates @crichardson

  30. Aggregate design Order Graph consisting of a root entity and one or more other entities and value objects customerId Each core business entity = Aggregate: e.g. customer, Account, Order, Product, …. OrderLine Reference other aggregate Address Item roots via primary key street Often contains partial copy quantity city of other aggregates’ data productId … productName productPrice

  31. Aggregate granularity is important Transaction = processing one command by one aggregate No opportunity to update multiple aggregates within a transaction If an update must be atomic (i.e. no compensating transaction) then it must be handled by a single aggregate e.g. scanning boarding pass at security checkpoint or when entering jetway @crichardson

  32. Aggregate granularity Forum Forum Forum moderator moderator moderator User User User author author author Post Post Post Scalability/ Consistency User experience @crichardson

  33. ES-based Aggregate design class Account { Classic, var balance : Money; mutable def debit(amount : Money) { balance = balance - amount domain model } } Event centric, immutable case class Account(balance : Money) { def processCommand(cmd : Command) : Seq[Event] = ??? def applyEvent(event : Event) : Account = … } case class DebitCommand(amount : Money) case class AccountDebitedEvent(amount : Money) @crichardson

  34. Designing domain events Record state changes for an aggregate Part of the public API of the domain model ProductAddedToCart Required by id : TimeUUID productId aggregate productName productPrice shoppingCartId Enrichment: Used by consumers

  35. Designing commands Created by a service from incoming request Processed by an aggregate Immutable Contains value objects for Validating request Creating event Auditing user activity @crichardson

  36. Events and Commands @crichardson

  37. Hybrid OO/FP domain objects @crichardson

  38. OO = State + Behavior Account State balance processCommand(cmd : Command) : Seq[Events] applyEvent(event : Event) : Account Behavior @crichardson

  39. Aggregate traits Used by Event Store to Apply event returning reconstitute updated Aggregate aggregate Map Command to Events @crichardson

  40. Account - command processing Prevent overdraft @crichardson

  41. Account - applying events Immutable @crichardson

  42. Event Store API trait EventStore { def save[T <: Aggregate[T]](entity: T, events: Seq[Event], assignedId : Option[EntityId] = None): Future[EntityWithIdAndVersion[T]] def update[T <: Aggregate[T]](entityIdAndVersion : EntityIdAndVersion, entity: T, events: Seq[Event]): Future[EntityWithIdAndVersion[T]] def find[T <: Aggregate[T] : ClassTag](entityId: EntityId) : Future[EntityWithIdAndVersion[T]] def findOptional[T <: Aggregate[T] : ClassTag](entityId: EntityId) Future[Option[EntityWithIdAndVersion[T]]] def subscribe(subscriptionId: SubscriptionId): Future[AcknowledgableEventStream] } @crichardson

  43. FP-style domain objects @crichardson

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend