A description of how we moved a status-heavy application to use Events. An overview of the requirements of Events Sourcing and how the classes work together.
1. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 1/58
2. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 2/58
I'm a PHP developer
Organizer of Triangle PHP and
Director of WWCode
Raleigh/Durham
I work at a company that builds
tools for network security threat
assessment
3. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 3/58
WHAT WE'LL COVER:
Processes from paper to web forms
What is Event Sourcing?
Introducing what this code looks like (LIGHT)
Advantages and Disadvantages
5. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 5/58
SIGN THE WAIVER
I, __(state your name)__, will not blame Emily if Event Sourcing
makes my head explode. I promise I will not leave a bad review. And I
promise to be kind to myself as I learn new things.
Emily will not be held responsible if your head explodes
7. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 7/58
8. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 8/58
PAPER FORMS HANDLING STATE
Status labels are like a rubber
stamp
Status doesn't always communicate
why or what happened
9. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 9/58
10. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 10/58
WHY ARE THEY IN THE CURRENT STATE?
11. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 11/58
HOW WORKFLOWS BECOME COMPLEX
12. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 12/58
PAPER FORMS HANDLING STATE
Piles indicate status of the form
13. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 13/58
A SIMPLE STATUS DROP-DOWN
RECEIVED
14. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 14/58
A "SIMPLE" STATUS DROP-DOWN
RECEIVED
CANCELLED
COURSE CANCELLED
COURSE NOT APPROVED
CPC DENIED
CPC NOT APPROVED
CPC PENDING TRANSCRIPT
CPC PROCESSING
DENIED
DROPPED AFTER CENSUS
DROPPED BEFORE CLASSES BEGUN
DROPPED BETWEEN BEGINNING OF CLASS AND CENSUS DATE
DROPS/WITHDRAWALS AT SITES
ECE ON CAMPUS STUDENTS
ENROLLMENT CANCELLED
EOL APPROVED
EOL MISC
NEW STUDENT REGISTRATION
PENDING ON CAMPUS REQUEST
ON CAMPUS STUDENT NOT APPROVED
PENDING CASHIER HOLD
PENDING EOL APPROVAL
PENDING INSTRUCTOR APPROVAL
PENDING INTERNATIONAL STUDENT
PENDING NDS OPEN ENROLLMENT
PENDING OIS VISA STUDENT
PENDING PERMANENT RESIDENT
PENDING TERM ADVISEMENT HOLD
PENDING TRANSCRIPT
PENDING TUITION PREPAYMENT
PREAPPROVED RETURNING
PROCESSING NDS
PROCESSING SITE
PROCESSING Z
PROJECT MESSAGE - MAE 586
PROJECT MESSAGE - NE 693
REGISTERED
15. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 15/58
REGISTERED
REGISTERED ASHEVILLE
REGISTERED HAVELOCK
REGISTERED WILMINGTON
SITE APPROVAL: ASHEVILLE
SITE APPROVAL: HAVELOCK
SITE APPROVAL: WILMINGTON
SITE NOT APPROVED
SWAPPED OUT
TRANSCRIPT APPROVED
WITHDRAWN
16. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 16/58
SOMETHING HAPPENED
17. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 17/58
SOMETHING HAPPENED
Status is a reflection of something
that happened
There is ONE of each status +
reasons/details
Events can record what happened
18. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 18/58
THE REQUEST DOESN'T GET STUCK
19. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 19/58
ENTER EVENT SOURCING
20. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 20/58
DEFINITION EVENT SOURCING
The fundamental idea of Event Sourcing is that of ensuring every
change to the state of an application is captured in an event
object, and that these event objects are themselves stored in the
sequence they were applied for the same lifetime as the application
state itself.
Martin Fowler
21. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 21/58
WHAT'S IMPORTANT ABOUT EVENTS
Events
Details of the Event (attributes)
Order/Sequence
22. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 22/58
RULES FOR EVENTS
Events are usually named as past-tense verbs
RARELY changed
Never deleted
Have attributes that are values
never an aggregate root
never a model/collection/object
23. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 23/58
THE OBJECT COULD CHANGE
24. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 24/58
IF WE STORED IT IN AN EVENT...
25. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 25/58
EVENTS ARE NOT BIONIC
26. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 26/58
THE FACT THAT AN EVENT HAPPENED DOESN'T
EVER CHANGE EVEN THOUGH THE BEHAVIOR
AROUND IT MAY HAVE
27. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 27/58
WHY EVENTS?
state transistions are important
We need an audit log and proof of state
This history is more important than the current state
Able to replay these events to rebuild state
28. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 28/58
29. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 29/58
30. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 30/58
31. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 31/58
Events don't change
The part of the code that will change is most likely the result that
follows that event.
The structure of the resulting data is more likely to change than the
behavior
32. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 32/58
THE CODE
There are many classes involved:
Events
Domain Message
Classes with Listeners
Projections
Read Models
Commands & Handlers (CQRS)
33. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 33/58
34. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 34/58
35. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 35/58
<?php
namespace AppEnrollmentDomainEvents;
use AppEnrollmentDomainCourseOfferingId;
use AppEnrollmentDomainStudentId;
use AppSupportDomainUuid;
use AppSupportEventHandlingEvent;
class EnrollmentRequestRejected implements Event
{
/**
* @var Uuid
*/
public $enrollmentRequestId;
/**
* @var StudentId
*/
public $studentId;
/**
36. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 36/58
37. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 37/58
<?php
namespace AppSupportDomain;
use AppSupportEventHandlingEvent;
use DateTime;
class DomainMessage
{
/**
* @var string
*/
private $streamId;
/**
* @var int
*/
private $version;
/**
* @var Event
*/
38. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 38/58
EVENT STORE
A domain specific database
A functional database based on a publish-subscribe messages pattern
39. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 39/58
EVENTS TABLE - NO WRAPPER
40. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 40/58
EVENTS TABLE - NO WRAPPER
45. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 45/58
LISTENERS
Have methods that handle the
events they care about
Ignore the rest
Each handle method outlines the
steps to follow after an event
occurs
46. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 46/58
47. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 47/58
PROJECTOR
<?php
namespace AppEnrollmentReadModel;
use AppEnrollmentDomainEventsEnrollmentRequestRejected;
use AppEnrollmentDomainEventsStudentRequestedEnrollment;
use AppSupportReadModelReplayable;
use AppSupportReadModelSimpleProjector;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseConnection;
class EnrollmentRequestProjector extends SimpleProjector implements Replayable
{
/**
* @var Connection
*/
private $connection;
/**
* @var string table we're playing events into
*/
48. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 48/58
49. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 49/58
READ MODEL
<?php
namespace AppEnrollmentReadModel;
use CarbonCarbon;
use IlluminateDatabaseEloquentModel;
/**
* @codeCoverageIgnore
*/
class EnrollmentRequest extends Model
{
protected $table = 'proj_enrollment_requests';
public $incrementing = false;
public $timestamps = false;
public static function current()
{
return static::where('student_id', auth()->user()->name)->get();
}
public static function lookupRequestsFor($username)
{
return static::where('student_id', $username)->get();
50. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 50/58
51. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 51/58
52. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 52/58
COMMANDS
<?php
namespace AppEnrollmentCommands;
use AppSupportCommandHandlingCommand;
use AppCommonSemesterTerm;
use DateTime;
use IlluminateHttpRequest;
class ScheduleEnrollmentPeriod implements Command
{
const DATE_FORMAT = DateTime::ATOM;
/**
* @var DateTime
*/
public $open;
/**
* @var DateTime
*/
public $close;
53. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 53/58
HANDLER
<?php
namespace appEnrollmentCommands;
use AppEnrollmentDomainEnrollmentPeriod;
use AppEnrollmentIdentityProvider;
use AppSupportCommandHandlingCommandHandler;
use AppSupportRepositoryEventSourcingRepository;
use IlluminateAuthAccessAuthorizationException;
class EnrollmentPeriodHandler extends CommandHandler
{
/**
* @var IdentityProvider
*/
private $auth;
/**
* @var EventSourcingRepository
*/
private $repository;
public function __construct(IdentityProvider $auth, EventSourcingRepository $repository)
54. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 54/58
PROS
maps closely to the process
flexible to changes in process
meaning of events can change without altering history
scholarships; able to back up all events to roll over a new year.
Didn't need to preserve full database.
55. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 55/58
CONS
a lot of classes
more design patterns to adjust to (complicated)
56. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 56/58
57. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 57/58
LINKS FOR FURTHER READING
(+2 more)
Greg Young CQRS and Event Sourcing
Greg Young - long class
Greg Young - A Decade of DDD, CQRS, Event Sourcing
PHP Round Table - Event Sourcing
Broadway - framework for CQRS and ES
58. 9/8/2017 Status Change: Now Using Event Sourcing
http://localhost:8080/status_change.html#/ 58/58
THANK YOU!
Emily Stamey
Joind.in:
@elstamey https://joind.in/talk/a0c6e
@elstamey
https://joind.in/talk/a0c6e