3. JakubPilimon
DISCLAIMERS
• Traps based on private experiences
• Solutions worked in my context
• Haven’t pushed anything to production since … 11
months
• … But this is based on previous experiences
• Completely new content …
• … Please don’t throw tomatoes
7. JakubPilimon
EVENT-DRIVEN TO ME
• EDA != “I have microservices”
• EDA != “I have a message broker”
• Events might be transported for instance via HTTP
• Events can live only in application memory
• … Events might not be even visible in the code
(solution space)
• … but are present in the business process (problem
space)
• Event Sourcing counts too
13. JakubPilimon
TRAP #1: MISSING AN EVENT
REASONS:
▸ Boundary of software != Boundary of business process
▸ Sometimes Software != Source of Truth
▸ Protocol’s semantics != protocol’s implementation
SOLUTIONS:
▸ Event Storming
▸ Don’t try to be consistent no matter what (sometimes it is impossible)
▸ Attach to semantics, not to implementation (focus on an intention of
any communication)
14. JakubPilimon
@PostMapping("/ends")
public ResponseEntity stopSession(@RequestBody StopTransaction stopTransaction) {
try {
ChargingSession session = chargingSessionRepository.findById(id)
.orElseGet(() -> new ChargingSession(id, null));
session.finishedAt(Instant.now());
} catch (Exception e) {
//DO WHAT YOU CAN - ASK BUSINESS
}
return ResponseEntity.ok().build();
}
MAKE IT SAFE
18. JakubPilimon
TRAP #2: VERSIONING OF BEHAVIORS
REASONS:
▸ Temporal values
▸ OccurredAt vs ArrivedAt mismatch!
SOLUTIONS:
▸ Calculation logic in projection should be done at time of
event creation and the result should be inside the event
▸ Same with external calls
21. JakubPilimon
TRAP #3: EXTERNAL CALLS
REASONS:
▸ Relying on a single source of truth
SOLUTIONS:
▸ External calls should be done at time of event creation
and the result should be kept inside the event
▸ Stream/Stream Join
26. JakubPilimon
TRAP #4: IGNORING CAP THEOREM
REASONS:
▸ Ignoring the fact that every now and then things will not work
▸ Trying to be consistent IMMEDIATELY!
▸ Experience with 2PC/DTC
SOLUTIONS:
▸ Event Sourcing
▸ At-least once (and deduplicating) or at-most once
▸ Listen to yourself
27. JakubPilimon
@Transactional
public ResponseEntity stopSession(StopTransaction stopTransaction) {
//change database
TransactionSynchronizationManager.registerSynchronization(new
TransactionSynchronization() {
@Override
public void afterCommit() {
//eventPublisher.publish(...);
}
});
return ResponseEntity.ok().build();
}
@Transactional
public ResponseEntity stopSession(StopTransaction stopTransaction) {
ChargingSession session = database.findById(stopTransaction.getId());
session.finishedAt(now());
database.save(new ChargingSessionFinished());
return ResponseEntity.ok().build();
}
AT LEAST ONCE
AT MOST ONCE
31. JakubPilimon
TRAP #5: ANEMIC-EVENTS
REASONS:
▸ Focusing on data instead of behavior
SOLUTIONS:
▸ Domain events (with behavior)
▸ Thinking about business intent of any change, not only
about the representation of that change
▸ Event Storming