際際滷

際際滷Share a Scribd company logo
NOTYOURUSUALCRUD!
ADIFFERENTAPPROACHTOARCHITECTUREANDPERSISTENCE
WHATISWRONGWITHCRUD?
Inplaceupdatescanleadtodegradedperformance
Scalabilityislimited
Historyislost
Doesnotsupportdifferentreadandwritesemantics
Con ictsarehardtomanage
WHATCANYOUEXPECTFROM
TODAY?
IntroductiontoEventSourcing
IntroductiontoCQRS
Proofthatitisnotcomplicatedjustdifferent
WHATAREEVENTS?
Immutablefactsfromthepast
Containallinformationdescribingthechange
WHATISEVENTSOURCING
ABOUT?
Donotstoreandmutatethecurrentstate
Recordsequenceofchangesaseventsinajournal
Considerthejournaltobethesinglesourceoftruth
HOWDOESAJOURNALLOOKLIKE?
createtableifnotexistsjournal(
idBIGSERIALPRIMARYKEY,
aggregate_idVARCHAR(255)NOTNULL,
versionBIGINTNOTNULL,
typeVARCHAR(255)NOTNULL,
payloadJSONBNOTNULL,
tagsJSONBNOTNULL,
timestampTIMESTAMPNOTNULL
);
WHATDOWESTORE
Payload
{
"product":"123",
"amount":5
}
Tags
{
"aggregate"->"cart",
"tenant"->"123"
}
LIMITATIONS
Datamodeldoesnotqualifyforadvancedqueries
Toolingisnotasadvanced
CQRS
CommandQueryResponsibilitySegregation
Separatedatamodelforprocessingupdates
Separatedatamodelforperformingqueries
LIMITATIONS
Complexity
EventualConsistency
WORKSHOP
Clonethecodefromthegitrepository
JDK8+,SBT,PostgreSQLrequired
Pleaseaskforassistence
https://github.com/dpfeiffer/eventsourcing-postgres-jdbccontains
example(master,solutions)
init.sqlcontainsDDL
JOURNALFORSTORINGEVENTS
traitJournal{
defstore(events:List[EventEnvelope]):Unit
defstream(aggregateId:String):LazyList[EventEnvelope]
}
AGGREGATESASCOMMAND
HANDLERS
abstractclassAggregate[C<:Command,E<:Event,S](journal:Journal,eventStream:EventStream){
protecteddefinitialState:S
protecteddefencode(event:E):String
protecteddefdecode(`type`:String,payload:String):E
protecteddefhandleCommand(s:S,c:C):(List[E],Any)
protecteddefhandleEvent(s:S,e:E):S
defprocessCommand(c:C):Any=???
...
}
EVENTSTREAMASMESSAGING
MECHANISM
classEventStream{
defpublish[E](event:E):Unit=???
defsubscribe[E:ClassTag](handler:E=>Unit):Unit=???
}
SHOPPINGCART
Addingproducts:quantity,productId
Removingproducts
Chaningquantity
SHOPPINGCART-ENCODING
importeventsourcing._
importexample.ShoppingCart._
importplay.api.libs.json._
objectShoppingCart{
traitShoppingCartCommandextendsCommand
caseclassAddItem(id:String,productId:String,quantity:Int)extendsShoppingCartCommand
abstractclassShoppingCartEvent(`type`:String)extendsEvent(`type`)
caseclassItemAdded(productId:String,quantity:Int)extendsShoppingCartEvent("item.added")
privatevaladdedFormat=Json.format[ItemAdded]
}
classShoppingCart(j:Journal,s:EventStream)
extendsAggregate[ShoppingCartCommand,ShoppingCartEvent,Map[String,Int]](j,s){
overridedefdecode(`type`:String,payload:String):ShoppingCart.ShoppingCartEvent=`type`match{
case"item.added"=>addedFormat.reads(Json.parse(payload)).get
}
overridedefencode(event:ShoppingCart.ShoppingCartEvent):String=eventmatch{
casee:ItemAdded=>addedFormat.writes(e).toString()
}
}
SHOPPINGCART-COMMAND
HANDLING
classShoppingCart(j:Journal,s:EventStream)
extendsAggregate[ShoppingCartCommand,ShoppingCartEvent,Map[String,Int]](j,s){
overridedefhandleCommand(s:ShoppingCartState,c:ShoppingCart.ShoppingCartCommand):(List[ShoppingCa
casec:AddItem=>???
}
overridedefhandleEvent(s:ShoppingCartState,e:ShoppingCart.ShoppingCartEvent):ShoppingCartState=
ematch{
casei:ItemAdded=>???
}
}
}
SHOPPINGCART-USAGE
packageexample._
importeventsourcing._
objectMain{
defmain(args:Array[String]]):Unit={
valcarts=newShoppingCart(journal,eventStream)
carts.processCommand(ShoppingCart.AddItem("customer-1","jeans"))
carts.processCommand(ShoppingCart.AddItem("customer-1","bluejeans"))
}
}
select*fromjournal;
SHOPPINGCARTICON
Queryviewforasumofitemsintheshoppingcart
Usetheeventstreamtosubscribetoshoppingcartsupdates
SHOPPINGCARTICON-
ENCODING
abstractclassView[E<:Event:ClassTag,R](journal:Journal,stream:EventStream){
protecteddefdecode(`type`:String,payload:String):E
protecteddefhandleEvent(result:R,e:E):R
protecteddefinitialState:R
protecteddefinitialStream:LazyList[EventEnvelope]
defget:R=???
}
PRODUCT
Reservequantityifauserputsitintothecart
Releasequnatityifauserremovesitfromthecart
PRODUCT-ENCODING
classProduct(journal:Journal,stream:EventStream)extendsAggregate[...](journal,stream){
stream.subscribe[ShoppingCart.ItemAdded]{event=>

}
}
REFERENCES
https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrsfor
useful gures

More Related Content

Event Sourcing without any Framework