SlideShare a Scribd company logo
1 of 54
Download to read offline
CQRS & EVENT SOURCING
IN THE WILD
MICHIEL ROOK
➤ Java, PHP & Scala
developer
➤ Consultant, trainer,
speaker
➤ Dutch Web Alliance
➤ make.io
➤ Maintainer of Phing
➤ @michieltcs
YOU
RAISE YOUR HAND
IF YOU HAVE
heard about CQRS / Event Sourcing
RAISE YOUR HAND
IF YOU HAVE
heard about CQRS / Event Sourcing
followed a tutorial, built a hobby project
RAISE YOUR HAND
IF YOU HAVE
heard about CQRS / Event Sourcing
followed a tutorial, built a hobby project
used it in production
RAISE YOUR HAND
IF YOU HAVE
TOPICS
➤ Quick recap
➤ Replays and rebuilds
➤ Event versioning
➤ Concurrency
➤ Scale
QUICK RECAP
' Event Sourcing ensures that all
changes to application state are stored
as a sequence of events.
-Martin Fowler
ACTIVE RECORD VS. EVENT SOURCING
Account
number
Balance
12345678 €€ 50,00
... ...
Money Withdrawn
Account number 12345678
Amount €€ 50,00
Money Deposited
Account number 12345678
Amount €€ 100,00
Account Created
Account number 12345678
COMMANDS TO EVENTS
Deposit Money
Account number 12345678
Amount €€ 100,00
Money Deposited
Account number 12345678
Amount €€ 100,00
class DepositMoney {

public $accountNumber;

public $amount;

}
class MoneyDeposited {

public $accountNumber;

public $amount;

public $timestamp;

}
function depositMoney(DepositMoney $command) {

$this->apply(new MoneyDeposited($command->accountNumber,

$command->amount, date()));

}
AGGREGATES
class BankAccount {

public $accountNumber;

public $balance;



// command handlers...



public function applyAccountCreated(AccountCreated $event) {

$this->accountNumber = $event->accountNumber;

$this->balance = 0;

}



public function applyMoneyDeposited(MoneyDeposited $event) {

$this->balance += $event->amount;

}



public function applyMoneyWithdrawn(MoneyWithdrawn $event) {

$this->balance -= $event->amount;

}

}
AGGREGATE STATE
Account
number
Balance
12345678 €€ 0,00
Money Withdrawn
Account number 12345678
Amount €€ 50,00
Money Deposited
Account number 12345678
Amount €€ 100,00
Account Created
Account number 56789012
Account
number
Balance
12345678 €€ 100,00
Account
number
Balance
12345678 €€ 50,00
CQRS
➤ Command Query Responsibility Segregation
➤ Separate writes (events) and reads (UI)
➤ Optimize for reads!
Domain
Event Bus
Event Handlers
Command
Repository
Data Layer
Database Database
Event
Store
commands
events
events
queries DTOs
Aggregates
PROS AND CONS
➤ Domain fit
➤ Testing
➤ Audit trail
➤ Scalability
➤ Complexity
➤ Library support / maturity
DISCLAIMER
REPLAYS AND REBUILDS
PROJECTIONS AND READ MODELS
User Registered
User Registered
User Unregistered Number of active users?
PROJECTIONS AND READ MODELS
User Registered
User Deactivated
User Reactivated
Number of active users?
User Registered
User Unregistered
PROJECTIONS AND READ MODELS
User Registered Event Handler
Number of
active users
+1
User Unregistered Event Handler
Number of
active users
-1
PROJECTIONS AND READ MODELS
Events Event Handler(s) Storage
ELASTICSEARCH
class CompanyRegistered {

public $companyId;

public $name;

public $street;

public $city;

}



function handleCompanyRegistered(CompanyRegistered $event) {

$this->elasticsearch->index([

'index' => 'companies',

'type' => 'company',

'id' => $event->companyId,

'body' => [

'name' => $event->name,

'address' => [

'street' => $event->street,

'city' => $event->city

]

]

]);

}
READ MODEL UPDATES
➤ New type
➤ New structure
➤ Based on existing events
➤ Generate from scratch?
REBUILDING
Stop
application
Remove
old read
model
Loop over
events
Apply to
read model
Start
application
ZERO DOWNTIME
Loop over
existing
events
Apply to
new read
model
Apply
queued
events
Start using
new read
model
New events Queue
ELASTICSEARCH: MAPPING CHANGE
Create
index with
new
mapping
Reindex
existing
documents
Apply
queued
events
Start using
new index
New events Queue
CHALLENGE: LONG RUNNING REBUILDS
➤ Alternatives
➤ Distributed
➤ In memory
➤ Partial
➤ Background
CHALLENGE: SIDE EFFECTS
User Registered
User Id 123abc
Email Address test@example.net
Event Handler
Exclude during replays!
CHALLENGE: TRANSACTIONS
Event Handler
Event Handler
Event
Event Handler
Event Handler ?
CHALLENGE: EVENTUAL CONSISTENCY
➤ Asynchronous event handlers
➤ Reads eventually return the same value
➤ Compare with ACID
EVENT VERSIONING
DILEMMA
➤ New business requirements
➤ Refactoring
➤ New view on events
NEW EVENTS / VERSIONS
➤ No longer relevant
➤ Renamed
➤ Additional or renamed field(s)
➤ Too coarse, too fine
SUPPORT YOUR LEGACY?
➤ Events are immutable
➤ Correct (incorrect) old events with new events
UPCASTING
Event Store
UserRegistered_V1
Upcaster
UserRegistered_V2
Event Handler
UPCASTING
class UserRegistered_V1 {

public $userId;

public $name;

public $timestamp;

}



class UserRegistered_V2 {

public $userId;

public $name;

public $date;

}



function upcast($event): array {

if (!$event instanceof UserRegistered_V1) {

return [];

}

return [

new UserRegistered_V2($event->userId, $event->name,

$event->timestamp->format("Y-m-d"))

];

}
REWRITING HISTORY
Load (subset of) events
Deserialize
Modify
Serialize
Save/replace
THINGS TO BE AWARE OF
Upcasting
➤ Performance
➤ Complexity
➤ Existing projections not
automatically updated
Rewriting events
➤ Running code that
depends on old structure
➤ Breaking serialization
➤ Changing wrong events
CONCURRENCY
CONCURRENT COMMANDS
Withdraw Money
Account number 12345678
Amount €€ 50,00
Deposit Money
Account number 12345678
Amount €€ 100,00
?
PESSIMISTIC LOCKING
Withdraw Money
Account number 12345678
Amount €€ 50,00
Deposit Money
Account number 12345678
Amount €€ 100,00
Account
number
Balance
12345678 €€ 100,00
Account
number
Balance
12345678 €€ 50,00
wait for lock
lock
OPTIMISTIC LOCKING
Withdraw Money
Account number 12345678
Amount €€ 50,00
version 1
Deposit Money
Account number 12345678
Amount €€ 100,00
version 1
Account
number
Balance
12345678 €€ 100,00
version 2
ConcurrencyException
SCALE
PERFORMANCE
➤ Server
➤ Database
➤ Framework
➤ Language
STORAGE
➤ #events
➤ #aggregates
➤ #events_per_aggregate
➤ Serializer
➤ Speed
➤ Payload size
➤ Costs
SNAPSHOTS
Events
1 Account Created
2 Money Deposited
3 Money Withdrawn
4 Money Deposited
SNAPSHOT
5 Money Withdrawn
Events
1 Account Created
2 Money Deposited
3 Money Withdrawn
4 Money Deposited
5 Money Withdrawn
SHARDING
➤ Aggregate Id, Type, Event Timestamp, ...
➤ Rebalancing
➤ Distribution
ARCHIVING EVENTS
➤ Reduce working set
➤ Inactive / deleted aggregates
➤ Historic / irrelevant events
➤ Cheaper storage
FRAMEWORK COMPARISON
Framework Upcasting Snapshots Replaying
Broadway
(PHP)
No (PR) No (PR) Not in core
Prooph
(PHP)
MessageFactory
Yes, triggers on
event count
Example code,
off line
Axon
(Java/Scala)
Upcaster /
UpcasterChain
Yes, triggers on
event count
Yes,
ReplayingCluster
Akka
Persistence
(Java/Scala)
Event Adapter
Yes, decided by
actor
Yes
BROADWAY VS PROOPH
class TodoItem extends EventSourcedAggregateRoot {

private $itemId;



public function __construct(PostTodo $command) {

$this->apply(new TodoPosted($command->getItemId()));

}



public function getAggregateRootId()

{

return $this->itemId;

}



public function applyTodoPosted(TodoPosted $event) {

echo "Posted: " . $event->getItemId() . "n";

}

}
BROADWAY VS PROOPH
class TodoItem extends AggregateRoot {

private $itemId;



public function __construct(PostTodo $command) {

$this->recordThat(new TodoPosted($command->getItemId()));

}



protected function aggregateId() {

return $this->itemId;

}



public function whenTodoPosted(TodoPosted $event) {

echo "Posted: " . $event->getItemId() . "n";

}

}
THANK YOU!

More Related Content

What's hot

DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkbanq jdon
 
Event Sourcing with Microservices
Event Sourcing with MicroservicesEvent Sourcing with Microservices
Event Sourcing with MicroservicesRalph Winzinger
 
Building and deploying microservices with event sourcing, CQRS and Docker (QC...
Building and deploying microservices with event sourcing, CQRS and Docker (QC...Building and deploying microservices with event sourcing, CQRS and Docker (QC...
Building and deploying microservices with event sourcing, CQRS and Docker (QC...Chris Richardson
 
A practical introduction to Event Sourcing and CQRS
A practical introduction to Event Sourcing and CQRSA practical introduction to Event Sourcing and CQRS
A practical introduction to Event Sourcing and CQRSRobert Lemke
 
Going Serverless with CQRS on AWS
Going Serverless with CQRS on AWSGoing Serverless with CQRS on AWS
Going Serverless with CQRS on AWSAnton Udovychenko
 
CQRS + Event Sourcing
CQRS + Event SourcingCQRS + Event Sourcing
CQRS + Event SourcingMike Bild
 
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with Sagas
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with SagasJavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with Sagas
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with SagasChris Richardson
 
Lighning Talk: Event-Driven architecture for microservices
Lighning Talk: Event-Driven architecture for microservicesLighning Talk: Event-Driven architecture for microservices
Lighning Talk: Event-Driven architecture for microservicesMartins Sipenko
 
Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Chris Richardson
 
Developing microservices with aggregates (devnexus2017)
Developing microservices with aggregates (devnexus2017)Developing microservices with aggregates (devnexus2017)
Developing microservices with aggregates (devnexus2017)Chris Richardson
 
Event Sourcing - Greg Young
Event Sourcing - Greg YoungEvent Sourcing - Greg Young
Event Sourcing - Greg YoungJAXLondon2014
 
Developing microservices with aggregates (melbourne)
Developing microservices with aggregates (melbourne)Developing microservices with aggregates (melbourne)
Developing microservices with aggregates (melbourne)Chris Richardson
 
A Pattern Language for Microservices (@futurestack)
A Pattern Language for Microservices (@futurestack)A Pattern Language for Microservices (@futurestack)
A Pattern Language for Microservices (@futurestack)Chris Richardson
 
Event sourcing with Eventuate
Event sourcing with EventuateEvent sourcing with Eventuate
Event sourcing with EventuateKnoldus Inc.
 
Microservice Architecture with CQRS and Event Sourcing
Microservice Architecture with CQRS and Event SourcingMicroservice Architecture with CQRS and Event Sourcing
Microservice Architecture with CQRS and Event SourcingBen Wilcock
 
Microservices in Java and Scala (sfscala)
Microservices in Java and Scala (sfscala)Microservices in Java and Scala (sfscala)
Microservices in Java and Scala (sfscala)Chris Richardson
 
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Chris Richardson
 
Events, Picos, and Microservices
Events, Picos, and MicroservicesEvents, Picos, and Microservices
Events, Picos, and MicroservicesPhil Windley
 
Building microservices with Scala, functional domain models and Spring Boot
Building microservices with Scala, functional domain models and Spring BootBuilding microservices with Scala, functional domain models and Spring Boot
Building microservices with Scala, functional domain models and Spring BootChris Richardson
 
#JaxLondon: Building microservices with Scala, functional domain models and S...
#JaxLondon: Building microservices with Scala, functional domain models and S...#JaxLondon: Building microservices with Scala, functional domain models and S...
#JaxLondon: Building microservices with Scala, functional domain models and S...Chris Richardson
 

What's hot (20)

DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFramework
 
Event Sourcing with Microservices
Event Sourcing with MicroservicesEvent Sourcing with Microservices
Event Sourcing with Microservices
 
Building and deploying microservices with event sourcing, CQRS and Docker (QC...
Building and deploying microservices with event sourcing, CQRS and Docker (QC...Building and deploying microservices with event sourcing, CQRS and Docker (QC...
Building and deploying microservices with event sourcing, CQRS and Docker (QC...
 
A practical introduction to Event Sourcing and CQRS
A practical introduction to Event Sourcing and CQRSA practical introduction to Event Sourcing and CQRS
A practical introduction to Event Sourcing and CQRS
 
Going Serverless with CQRS on AWS
Going Serverless with CQRS on AWSGoing Serverless with CQRS on AWS
Going Serverless with CQRS on AWS
 
CQRS + Event Sourcing
CQRS + Event SourcingCQRS + Event Sourcing
CQRS + Event Sourcing
 
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with Sagas
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with SagasJavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with Sagas
JavaOne2017: ACID Is So Yesterday: Maintaining Data Consistency with Sagas
 
Lighning Talk: Event-Driven architecture for microservices
Lighning Talk: Event-Driven architecture for microservicesLighning Talk: Event-Driven architecture for microservices
Lighning Talk: Event-Driven architecture for microservices
 
Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)Microservices + Events + Docker = A Perfect Trio (dockercon)
Microservices + Events + Docker = A Perfect Trio (dockercon)
 
Developing microservices with aggregates (devnexus2017)
Developing microservices with aggregates (devnexus2017)Developing microservices with aggregates (devnexus2017)
Developing microservices with aggregates (devnexus2017)
 
Event Sourcing - Greg Young
Event Sourcing - Greg YoungEvent Sourcing - Greg Young
Event Sourcing - Greg Young
 
Developing microservices with aggregates (melbourne)
Developing microservices with aggregates (melbourne)Developing microservices with aggregates (melbourne)
Developing microservices with aggregates (melbourne)
 
A Pattern Language for Microservices (@futurestack)
A Pattern Language for Microservices (@futurestack)A Pattern Language for Microservices (@futurestack)
A Pattern Language for Microservices (@futurestack)
 
Event sourcing with Eventuate
Event sourcing with EventuateEvent sourcing with Eventuate
Event sourcing with Eventuate
 
Microservice Architecture with CQRS and Event Sourcing
Microservice Architecture with CQRS and Event SourcingMicroservice Architecture with CQRS and Event Sourcing
Microservice Architecture with CQRS and Event Sourcing
 
Microservices in Java and Scala (sfscala)
Microservices in Java and Scala (sfscala)Microservices in Java and Scala (sfscala)
Microservices in Java and Scala (sfscala)
 
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
Handling Eventual Consistency in JVM Microservices with Event Sourcing (javao...
 
Events, Picos, and Microservices
Events, Picos, and MicroservicesEvents, Picos, and Microservices
Events, Picos, and Microservices
 
Building microservices with Scala, functional domain models and Spring Boot
Building microservices with Scala, functional domain models and Spring BootBuilding microservices with Scala, functional domain models and Spring Boot
Building microservices with Scala, functional domain models and Spring Boot
 
#JaxLondon: Building microservices with Scala, functional domain models and S...
#JaxLondon: Building microservices with Scala, functional domain models and S...#JaxLondon: Building microservices with Scala, functional domain models and S...
#JaxLondon: Building microservices with Scala, functional domain models and S...
 

Similar to CQRS & event sourcing in the wild

CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)Michiel Rook
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
Kafka as an Event Store - is it Good Enough?
Kafka as an Event Store - is it Good Enough?Kafka as an Event Store - is it Good Enough?
Kafka as an Event Store - is it Good Enough?Guido Schmutz
 
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019confluent
 
Introduction to Event Sourcing in PHP
Introduction to Event Sourcing in PHPIntroduction to Event Sourcing in PHP
Introduction to Event Sourcing in PHPEvan McMahon
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right wayThibaud Desodt
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
A Journey with React
A Journey with ReactA Journey with React
A Journey with ReactFITC
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference ClientDallan Quass
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Coupa Software
 
Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)guiwoda
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...tdc-globalcode
 
Kafka as an event store - is it good enough?
Kafka as an event store - is it good enough?Kafka as an event store - is it good enough?
Kafka as an event store - is it good enough?Guido Schmutz
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Joao Lucas Santana
 
How to convert custom plsql to web services-Soap OR Rest
How to convert custom plsql to web services-Soap OR RestHow to convert custom plsql to web services-Soap OR Rest
How to convert custom plsql to web services-Soap OR Restshravan kumar chelika
 
Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterciconf
 
CQRS / ES & DDD Demystified
CQRS / ES & DDD DemystifiedCQRS / ES & DDD Demystified
CQRS / ES & DDD DemystifiedVic Metcalfe
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application frameworkDustin Filippini
 

Similar to CQRS & event sourcing in the wild (20)

CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Kafka as an Event Store - is it Good Enough?
Kafka as an Event Store - is it Good Enough?Kafka as an Event Store - is it Good Enough?
Kafka as an Event Store - is it Good Enough?
 
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019
Kafka as an Event Store (Guido Schmutz, Trivadis) Kafka Summit NYC 2019
 
Introduction to Event Sourcing in PHP
Introduction to Event Sourcing in PHPIntroduction to Event Sourcing in PHP
Introduction to Event Sourcing in PHP
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right way
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
A Journey with React
A Journey with ReactA Journey with React
A Journey with React
 
FamilySearch Reference Client
FamilySearch Reference ClientFamilySearch Reference Client
FamilySearch Reference Client
 
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
Staying railsy - while scaling complexity or Ruby on Rails in Enterprise Soft...
 
Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)Introduction to Domain driven design (LaravelBA #5)
Introduction to Domain driven design (LaravelBA #5)
 
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Java EE How we figured out we had a SRE team at ...
 
Kafka as an event store - is it good enough?
Kafka as an event store - is it good enough?Kafka as an event store - is it good enough?
Kafka as an event store - is it good enough?
 
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
Um roadmap do Framework Ruby on Rails, do Rails 1 ao Rails 4 - DevDay 2013
 
How to convert custom plsql to web services-Soap OR Rest
How to convert custom plsql to web services-Soap OR RestHow to convert custom plsql to web services-Soap OR Rest
How to convert custom plsql to web services-Soap OR Rest
 
Who Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniterWho Needs Ruby When You've Got CodeIgniter
Who Needs Ruby When You've Got CodeIgniter
 
Patterns for Building Streaming Apps
Patterns for Building Streaming AppsPatterns for Building Streaming Apps
Patterns for Building Streaming Apps
 
CQRS / ES & DDD Demystified
CQRS / ES & DDD DemystifiedCQRS / ES & DDD Demystified
CQRS / ES & DDD Demystified
 
WordPress as an application framework
WordPress as an application frameworkWordPress as an application framework
WordPress as an application framework
 
Presentation Paul
Presentation PaulPresentation Paul
Presentation Paul
 

More from Michiel Rook

The road to continuous deployment (PHPCon Poland 2016)
The road to continuous deployment (PHPCon Poland 2016)The road to continuous deployment (PHPCon Poland 2016)
The road to continuous deployment (PHPCon Poland 2016)Michiel Rook
 
The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)Michiel Rook
 
The road to continuous deployment: a case study (DPC16)
The road to continuous deployment: a case study (DPC16)The road to continuous deployment: a case study (DPC16)
The road to continuous deployment: a case study (DPC16)Michiel Rook
 
Building and Deploying PHP apps with Phing
Building and Deploying PHP apps with PhingBuilding and Deploying PHP apps with Phing
Building and Deploying PHP apps with PhingMichiel Rook
 
Building and deploying PHP applications with Phing
Building and deploying PHP applications with PhingBuilding and deploying PHP applications with Phing
Building and deploying PHP applications with PhingMichiel Rook
 
Deploying PHP applications with Phing
Deploying PHP applications with PhingDeploying PHP applications with Phing
Deploying PHP applications with PhingMichiel Rook
 
Phing - A PHP Build Tool (An Introduction)
Phing - A PHP Build Tool (An Introduction)Phing - A PHP Build Tool (An Introduction)
Phing - A PHP Build Tool (An Introduction)Michiel Rook
 

More from Michiel Rook (7)

The road to continuous deployment (PHPCon Poland 2016)
The road to continuous deployment (PHPCon Poland 2016)The road to continuous deployment (PHPCon Poland 2016)
The road to continuous deployment (PHPCon Poland 2016)
 
The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)The road to continuous deployment (DomCode September 2016)
The road to continuous deployment (DomCode September 2016)
 
The road to continuous deployment: a case study (DPC16)
The road to continuous deployment: a case study (DPC16)The road to continuous deployment: a case study (DPC16)
The road to continuous deployment: a case study (DPC16)
 
Building and Deploying PHP apps with Phing
Building and Deploying PHP apps with PhingBuilding and Deploying PHP apps with Phing
Building and Deploying PHP apps with Phing
 
Building and deploying PHP applications with Phing
Building and deploying PHP applications with PhingBuilding and deploying PHP applications with Phing
Building and deploying PHP applications with Phing
 
Deploying PHP applications with Phing
Deploying PHP applications with PhingDeploying PHP applications with Phing
Deploying PHP applications with Phing
 
Phing - A PHP Build Tool (An Introduction)
Phing - A PHP Build Tool (An Introduction)Phing - A PHP Build Tool (An Introduction)
Phing - A PHP Build Tool (An Introduction)
 

Recently uploaded

Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdftimtebeek1
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletAndrea Goulet
 
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...Neo4j
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio, Inc.
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaNeo4j
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Maxim Salnikov
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfICS
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckMarc Lester
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Lisi Hocke
 
Test Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdfTest Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdfkalichargn70th171
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024MulesoftMunichMeetup
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AIAGATSoftware
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConNatan Silnitsky
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024SimonedeGijt
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Clinic
 
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...OnePlan Solutions
 
Software Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements EngineeringSoftware Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements EngineeringPrakhyath Rai
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfkalichargn70th171
 

Recently uploaded (20)

Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdf
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea Goulet
 
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
Abortion Pill Prices Germiston ](+27832195400*)[ 🏥 Women's Abortion Clinic in...
 
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
Abortion Clinic Pretoria ](+27832195400*)[ Abortion Clinic Near Me ● Abortion...
 
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...
CERVED e Neo4j su una nuvola, migrazione ed evoluzione di un grafo mission cr...
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdf
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
 
Test Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdfTest Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdf
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
 
BusinessGPT - Security and Governance for Generative AI
BusinessGPT  - Security and Governance for Generative AIBusinessGPT  - Security and Governance for Generative AI
BusinessGPT - Security and Governance for Generative AI
 
Effective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeConEffective Strategies for Wix's Scaling challenges - GeeCon
Effective Strategies for Wix's Scaling challenges - GeeCon
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
 
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
Abortion Pill Prices Jane Furse ](+27832195400*)[ 🏥 Women's Abortion Clinic i...
 
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
Optimizing Operations by Aligning Resources with Strategic Objectives Using O...
 
Software Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements EngineeringSoftware Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements Engineering
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
 

CQRS & event sourcing in the wild

  • 1. CQRS & EVENT SOURCING IN THE WILD MICHIEL ROOK
  • 2. ➤ Java, PHP & Scala developer ➤ Consultant, trainer, speaker ➤ Dutch Web Alliance ➤ make.io ➤ Maintainer of Phing ➤ @michieltcs
  • 3. YOU
  • 5. heard about CQRS / Event Sourcing RAISE YOUR HAND IF YOU HAVE
  • 6. heard about CQRS / Event Sourcing followed a tutorial, built a hobby project RAISE YOUR HAND IF YOU HAVE
  • 7. heard about CQRS / Event Sourcing followed a tutorial, built a hobby project used it in production RAISE YOUR HAND IF YOU HAVE
  • 8. TOPICS ➤ Quick recap ➤ Replays and rebuilds ➤ Event versioning ➤ Concurrency ➤ Scale
  • 10. ' Event Sourcing ensures that all changes to application state are stored as a sequence of events. -Martin Fowler
  • 11. ACTIVE RECORD VS. EVENT SOURCING Account number Balance 12345678 €€ 50,00 ... ... Money Withdrawn Account number 12345678 Amount €€ 50,00 Money Deposited Account number 12345678 Amount €€ 100,00 Account Created Account number 12345678
  • 12. COMMANDS TO EVENTS Deposit Money Account number 12345678 Amount €€ 100,00 Money Deposited Account number 12345678 Amount €€ 100,00 class DepositMoney {
 public $accountNumber;
 public $amount;
 } class MoneyDeposited {
 public $accountNumber;
 public $amount;
 public $timestamp;
 } function depositMoney(DepositMoney $command) {
 $this->apply(new MoneyDeposited($command->accountNumber,
 $command->amount, date()));
 }
  • 13. AGGREGATES class BankAccount {
 public $accountNumber;
 public $balance;
 
 // command handlers...
 
 public function applyAccountCreated(AccountCreated $event) {
 $this->accountNumber = $event->accountNumber;
 $this->balance = 0;
 }
 
 public function applyMoneyDeposited(MoneyDeposited $event) {
 $this->balance += $event->amount;
 }
 
 public function applyMoneyWithdrawn(MoneyWithdrawn $event) {
 $this->balance -= $event->amount;
 }
 }
  • 14. AGGREGATE STATE Account number Balance 12345678 €€ 0,00 Money Withdrawn Account number 12345678 Amount €€ 50,00 Money Deposited Account number 12345678 Amount €€ 100,00 Account Created Account number 56789012 Account number Balance 12345678 €€ 100,00 Account number Balance 12345678 €€ 50,00
  • 15. CQRS ➤ Command Query Responsibility Segregation ➤ Separate writes (events) and reads (UI) ➤ Optimize for reads!
  • 16. Domain Event Bus Event Handlers Command Repository Data Layer Database Database Event Store commands events events queries DTOs Aggregates
  • 17. PROS AND CONS ➤ Domain fit ➤ Testing ➤ Audit trail ➤ Scalability ➤ Complexity ➤ Library support / maturity
  • 20. PROJECTIONS AND READ MODELS User Registered User Registered User Unregistered Number of active users?
  • 21. PROJECTIONS AND READ MODELS User Registered User Deactivated User Reactivated Number of active users? User Registered User Unregistered
  • 22. PROJECTIONS AND READ MODELS User Registered Event Handler Number of active users +1 User Unregistered Event Handler Number of active users -1
  • 23. PROJECTIONS AND READ MODELS Events Event Handler(s) Storage
  • 24. ELASTICSEARCH class CompanyRegistered {
 public $companyId;
 public $name;
 public $street;
 public $city;
 }
 
 function handleCompanyRegistered(CompanyRegistered $event) {
 $this->elasticsearch->index([
 'index' => 'companies',
 'type' => 'company',
 'id' => $event->companyId,
 'body' => [
 'name' => $event->name,
 'address' => [
 'street' => $event->street,
 'city' => $event->city
 ]
 ]
 ]);
 }
  • 25. READ MODEL UPDATES ➤ New type ➤ New structure ➤ Based on existing events ➤ Generate from scratch?
  • 27. ZERO DOWNTIME Loop over existing events Apply to new read model Apply queued events Start using new read model New events Queue
  • 28. ELASTICSEARCH: MAPPING CHANGE Create index with new mapping Reindex existing documents Apply queued events Start using new index New events Queue
  • 29. CHALLENGE: LONG RUNNING REBUILDS ➤ Alternatives ➤ Distributed ➤ In memory ➤ Partial ➤ Background
  • 30. CHALLENGE: SIDE EFFECTS User Registered User Id 123abc Email Address test@example.net Event Handler Exclude during replays!
  • 31. CHALLENGE: TRANSACTIONS Event Handler Event Handler Event Event Handler Event Handler ?
  • 32. CHALLENGE: EVENTUAL CONSISTENCY ➤ Asynchronous event handlers ➤ Reads eventually return the same value ➤ Compare with ACID
  • 34. DILEMMA ➤ New business requirements ➤ Refactoring ➤ New view on events
  • 35. NEW EVENTS / VERSIONS ➤ No longer relevant ➤ Renamed ➤ Additional or renamed field(s) ➤ Too coarse, too fine
  • 36. SUPPORT YOUR LEGACY? ➤ Events are immutable ➤ Correct (incorrect) old events with new events
  • 38. UPCASTING class UserRegistered_V1 {
 public $userId;
 public $name;
 public $timestamp;
 }
 
 class UserRegistered_V2 {
 public $userId;
 public $name;
 public $date;
 }
 
 function upcast($event): array {
 if (!$event instanceof UserRegistered_V1) {
 return [];
 }
 return [
 new UserRegistered_V2($event->userId, $event->name,
 $event->timestamp->format("Y-m-d"))
 ];
 }
  • 39. REWRITING HISTORY Load (subset of) events Deserialize Modify Serialize Save/replace
  • 40. THINGS TO BE AWARE OF Upcasting ➤ Performance ➤ Complexity ➤ Existing projections not automatically updated Rewriting events ➤ Running code that depends on old structure ➤ Breaking serialization ➤ Changing wrong events
  • 42. CONCURRENT COMMANDS Withdraw Money Account number 12345678 Amount €€ 50,00 Deposit Money Account number 12345678 Amount €€ 100,00 ?
  • 43. PESSIMISTIC LOCKING Withdraw Money Account number 12345678 Amount €€ 50,00 Deposit Money Account number 12345678 Amount €€ 100,00 Account number Balance 12345678 €€ 100,00 Account number Balance 12345678 €€ 50,00 wait for lock lock
  • 44. OPTIMISTIC LOCKING Withdraw Money Account number 12345678 Amount €€ 50,00 version 1 Deposit Money Account number 12345678 Amount €€ 100,00 version 1 Account number Balance 12345678 €€ 100,00 version 2 ConcurrencyException
  • 45. SCALE
  • 46. PERFORMANCE ➤ Server ➤ Database ➤ Framework ➤ Language
  • 47. STORAGE ➤ #events ➤ #aggregates ➤ #events_per_aggregate ➤ Serializer ➤ Speed ➤ Payload size ➤ Costs
  • 48. SNAPSHOTS Events 1 Account Created 2 Money Deposited 3 Money Withdrawn 4 Money Deposited SNAPSHOT 5 Money Withdrawn Events 1 Account Created 2 Money Deposited 3 Money Withdrawn 4 Money Deposited 5 Money Withdrawn
  • 49. SHARDING ➤ Aggregate Id, Type, Event Timestamp, ... ➤ Rebalancing ➤ Distribution
  • 50. ARCHIVING EVENTS ➤ Reduce working set ➤ Inactive / deleted aggregates ➤ Historic / irrelevant events ➤ Cheaper storage
  • 51. FRAMEWORK COMPARISON Framework Upcasting Snapshots Replaying Broadway (PHP) No (PR) No (PR) Not in core Prooph (PHP) MessageFactory Yes, triggers on event count Example code, off line Axon (Java/Scala) Upcaster / UpcasterChain Yes, triggers on event count Yes, ReplayingCluster Akka Persistence (Java/Scala) Event Adapter Yes, decided by actor Yes
  • 52. BROADWAY VS PROOPH class TodoItem extends EventSourcedAggregateRoot {
 private $itemId;
 
 public function __construct(PostTodo $command) {
 $this->apply(new TodoPosted($command->getItemId()));
 }
 
 public function getAggregateRootId()
 {
 return $this->itemId;
 }
 
 public function applyTodoPosted(TodoPosted $event) {
 echo "Posted: " . $event->getItemId() . "n";
 }
 }
  • 53. BROADWAY VS PROOPH class TodoItem extends AggregateRoot {
 private $itemId;
 
 public function __construct(PostTodo $command) {
 $this->recordThat(new TodoPosted($command->getItemId()));
 }
 
 protected function aggregateId() {
 return $this->itemId;
 }
 
 public function whenTodoPosted(TodoPosted $event) {
 echo "Posted: " . $event->getItemId() . "n";
 }
 }