-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstatus_change.html
2000 lines (1825 loc) · 93.4 KB
/
status_change.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Status Change: Now Using Event Sourcing</title>
<meta name="description"
content="Being flexible to changes in business process makes our jobs easier, and it helps our applications adapt to those changes with minimal code changes. One of the biggest adaptions in our applications has been the addition of Events to make a note of an Event in the system. With these Events, we can affect change immediately, or even later. This is most helpful in our reporting interfaces. We can build, change, and throw away our reports very easily. This is much easier than our older reports being generated by large SQL queries.">
<meta name="author" content="Emily Stamey">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/white.css">
<link rel="stylesheet" href="css/my-style.css">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="./node_modules/highlight.js/styles/zenburn.css">
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
<!--<link rel="stylesheet" href="plugin/accessibility/helper.css">-->
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
</head>
<body>
<div class="reveal">
<div class='footer'>
@elstamey <a href="https://joind.in/talk/a0c6e">https://joind.in/talk/a0c6e</a>
</div>
<div class="slides">
<section>
<myColBox>
<article>
<img src="img/status_change/events_title1.png">
</article>
</myColBox>
<aside class="notes">
</aside>
</section>
<section>
<myRowBox>
<article>
<myColBox>
<article>
<!--<h3>Emily</h3>-->
<img src="img/me/developer.png" alt="developer">
</article>
<article>
<p>I'm a PHP developer</p>
<p>Organizer of Triangle PHP and Director of WWCode Raleigh/Durham</p>
<p>I work at a company that builds tools for network security threat assessment</p>
<!--<p>I work<u>ED</u> at a University</p>-->
</article>
</myColBox>
</article>
<article>
<myColBox>
<article>
<img src="img/inquest.svg">
</article>
<article>
<img src="img/trianglePHP_sm.jpg">
</article>
<article>
<img src="img/wwcode.png">
</article>
</myColBox>
</article>
</myRowBox>
<aside class="notes">
<li>I am Emily. I'm a php developer</li>
<li>I love community, so I help to build them at home.</li>
<li>I work at Inquest, a network security company based in Washington, DC. </li>
<p>We are going to talk about Event Sourcing, but we will begin in a sort of roundabout way because
at State we have been adding Event Sourcing to many of our legacy projects. We have one project
that we are rewriting, and it's a good case study for an older approach with status flags and we are rewriting it to use
event sourcing.</p>
</aside>
</section>
<section>
<myTitleBox>
<h2>What we'll cover:</h2>
</myTitleBox>
<myColBox>
<article>
<ul>
<li>Processes from paper to web forms</li>
<li>What is Event Sourcing?</li>
<li>Introducing what this code looks like (LIGHT)</li>
<li>Advantages and Disadvantages</li>
</ul>
</article>
</myColBox>
<aside class="notes">
<li>We will talk about these web processes going from paper forms to web forms.</li>
<li>The definitions and terminology around Event Sourcing</li>
<li>We'll talk about what the PHP code generally looks like in this event sourced application</li>
<li>Finally, we'll look at pros and cons. It's a REAL mental shift coming from a legacy application to Event Sourcing</li>
</aside>
</section>
<section>
<myColBox>
<article>
<img src="img/status_change/thinking_cap_travel_oriented.jpg">
</article>
<article>
<h5 class="attrib" style="position: relative; top: 500px; align: bottom;left: -100px;">© photo by <a
href="https://www.flickr.com/photos/traveloriented/">Travel Oriented</a></h5>
</article>
</myColBox>
<aside class="notes">
</aside>
</section>
<!--<section>-->
<!--<myTitleBox>-->
<!--<h1>Brace Yourself!</h1>-->
<!--</myTitleBox>-->
<!--<myRowBox>-->
<!--<article>-->
<!--<img src="img/status_change/sea_kayak_waves_lee_ciaran.jpg">-->
<!--<h5 class="attrib" style="position: relative; top: 500px; align: bottom;left: -100px;">© photo by <a-->
<!--href="https://www.flickr.com/photos/lee_ciaran/">Ciaran Lee</a></h5>-->
<!--</article>-->
<!--</myRowBox>-->
<!--<aside class="notes">-->
<!--<li>So be patient with yourself</li>-->
<!--<li>If you've ever done this, you know it's tough. The strategy is to point into the waves and paddle HARD</li>-->
<!--</aside>-->
<!--</section>-->
<!--<section>-->
<!--<myTitleBox>-->
<!--<h1>Relax, Enjoy the Ride!</h1>-->
<!--</myTitleBox>-->
<!--<myRowBox>-->
<!--<article>-->
<!--<img src="img/status_change/sea_kayak_crash_lisakayaks.jpg">-->
<!--<h5 class="attrib" style="position: relative; top: 500px; align: bottom;left: -100px;">© photo by <a-->
<!--href="https://www.flickr.com/photos/lisakayaks/">Lisa Ouellette</a></h5>-->
<!--</article>-->
<!--</myRowBox>-->
<!--<aside class="notes">-->
<!--<li>If you try to change direction, you often tip over like this.</li>-->
<!--<li>This is my way of asking that you try to follow along with me.</li>-->
<!--</aside>-->
<!--</section>-->
<section>
<myTitleBox>
<h2>Sign the waiver</h2>
</myTitleBox>
<myRowBox>
<article>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. </article>
<article><img src="img/status_change/head_explode.gif" class="fragment"></article>
</myRowBox>
<footer>
<p><i class="fragment">Emily will not be held responsible if your head explodes</i></p>
</footer>
</section>
<section>
<myTitleBox>
<h2>Forms</h2>
</myTitleBox>
<myColBox>
<article>
<p>A lot of our systems were built to replace paper processes</p>
<p>They often closely map to this physical form.</p>
</article>
<article>
<img src="img/status_change/tax_form_aidanmorgan.jpg" alt="Paper form">
<h5 class="attrib" style="">© photo by <a
href="https://www.flickr.com/photos/aidanmorgan/">Aidan Morgan</a></h5>
</article>
</myColBox>
<aside class="notes">
<li>At the University our applications began with a need to
collect data from paper forms that students were filling out.</li>
<li>As the administration became comfortable with computers, more of the process went into our applications</li>
<li>Often this increased the complexity in the tools</li>
</aside>
</section>
<section>
<img src="img/status_change/form_process.png" alt="FormProcess"></p>
<aside class="notes">
<li>For this application, a student requests enrollment in a Distance Ed class</li>
<li>That request is either approved or rejected</li>
<li>The paper version of this process meant the Admin put the request form into an approve
or reject pile</li>
</aside>
</section>
<section>
<myTitleBox>
<h2>Paper Forms handling state</h2>
</myTitleBox>
<myColBox>
<article>
<img src="img/status_change/collegerejection.jpg" alt="stamped application">
</article>
<article>
<p>Status labels are like a rubber stamp</p>
<p>Status doesn't always communicate why or what happened</p>
<p></p>
</article>
</myColBox>
<aside class="notes">
<li>You may have seen a paper form with a rubber stamp on it with its status. </li>
<li>What if it changes state multiple times through the process? And each time the status overwrites itself?</li>
<li>The rubber stamp method wasn't flexible to change </li>
<li>But what if things change, and a rejection can be undone. Suppose it was rejected because tuition wasn't paid at the time</li>
<!--<li>The history doesn't convey between piles. And sometimes our application doesn't retain that information either</li>-->
</aside>
</section>
<section>
<myColBox>
<article>
<img src="img/status_change/CompensatingMeasures.png" alt="Compensating Measures: diagram of a table with a status column added and a drawing of a table with a related status table">
</article>
</myColBox>
<aside class="notes">
<li>We wanted to capture these status changes, so we added a column to the table with our form data</li>
<p>Or we added a related table to attempt to preserve history</p>
<!--<li>more statuses to include the many forks in the process (like what type of hold)</li>-->
</aside>
</section>
<section>
<myTitleBox>
<h2>Why are they in the current state?</h2>
</myTitleBox>
<myColBox>
<article></article>
<article>
<img src="img/status_change/history_book.png">
</article>
</myColBox>
<aside class="notes">
<li>The status label tells where it is in the process, but it doesn't tell you what led to that status</li>
<li>Status names often carry assumed knowledge of the process without the system reflecting that meaning.</li>
<li>Status names can be interpreted differently ESPECIALLY when you have many people using them</li>
<li>Status labels & meaning can change over time without the code changing at all</li>
</aside>
</section>
<section>
<myTitleBox>
<h2>How workflows become complex</h2>
</myTitleBox>
<myColBox>
<article>
<img src="img/status_change/requestPath.png" alt="a diagram of a request coming in to be reviewed and the admin sending it either to approved, rejected, or hold piles; but hold has another fork for reasons and hold can be for academic or financial reasons">
</article>
</myColBox>
<aside class="notes">
<li>Over time we add more states to the process to solve confusion, or to distribute load, lots of reasons!</li>
<li>Processes that handled lots of paper could become much more complex, even in trying to organize them</li>
</aside>
</section>
<section>
<myTitleBox>
<h2>Paper Forms handling state</h2>
</myTitleBox>
<myColBox>
<article>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6f/Copies_of_documents_at_European_Parliament_in_Strasbourg.jpg/1024px-Copies_of_documents_at_European_Parliament_in_Strasbourg.jpg" alt="Paper forms sorted for a process">
</article>
<article>
<p>Piles indicate status of the form</p>
</article>
</myColBox>
<aside class="notes">
<li>These piles indicated the status of the student's request for a class</li>
<li>On the web, we created an admin panel with a drop-down to indicate status</li>
</aside>
</section>
<section>
<myTitleBox>
<h2>A simple status drop-down</h2>
</myTitleBox>
<myColBox>
<article>
<select name="newStatus">
<option value="RECEIVED">RECEIVED</option>
<option value="CANCELLED">CANCELLED</option>
<option value="COURSE CANCELLED">COURSE CANCELLED</option>
<option value="COURSE NOT APPROVED">COURSE NOT APPROVED</option>
<option value="CPC DENIED">CPC DENIED</option>
<option value="CPC NOT APPROVED">CPC NOT APPROVED</option>
<option value="CPC PENDING TRANSCRIPT">CPC PENDING TRANSCRIPT</option>
<option value="CPC PROCESSING">CPC PROCESSING<em></option>
<option value="DENIED">DENIED</option>
<option value="DROPPED AFTER CENSUS">DROPPED AFTER CENSUS</em></option>
<option value="DROPPED BEFORE CLASSES BEGUN">DROPPED BEFORE CLASSES BEGUN<em></option>
<option value="DROPPED BETWEEN BEGINNING OF CLASS AND CENSUS DATE">DROPPED BETWEEN BEGINNING OF CLASS AND CENSUS DATE</em></option>
<option value="DROPS/WITHDRAWALS AT SITES">DROPS/WITHDRAWALS AT SITES<em></option>
<option value="ECE ON CAMPUS STUDENTS">ECE ON CAMPUS STUDENTS</option>
<option value="ENROLLMENT CANCELLED">ENROLLMENT CANCELLED</option>
<option value="EOL APPROVED">EOL APPROVED</em></option>
<option value="EOL MISC">EOL MISC<em></option>
<option value="NEW STUDENT REGISTRATION">NEW STUDENT REGISTRATION</option>
<option value="PENDING ON CAMPUS REQUEST">PENDING ON CAMPUS REQUEST</option>
<option value="ON CAMPUS STUDENT NOT APPROVED">ON CAMPUS STUDENT NOT APPROVED</option>
<option value="PENDING CASHIER HOLD">PENDING CASHIER HOLD</option>
<option value="PENDING EOL APPROVAL">PENDING EOL APPROVAL</em></option>
<option value="PENDING INSTRUCTOR APPROVAL">PENDING INSTRUCTOR APPROVAL</option>
<option value="PENDING INTERNATIONAL STUDENT">PENDING INTERNATIONAL STUDENT</option>
<option value="PENDING NDS OPEN ENROLLMENT">PENDING NDS OPEN ENROLLMENT</option>
<option value="PENDING OIS VISA STUDENT">PENDING OIS VISA STUDENT</option>
<option value="PENDING PERMANENT RESIDENT">PENDING PERMANENT RESIDENT</option>
<option value="PENDING TERM ADVISEMENT HOLD">PENDING TERM ADVISEMENT HOLD</option>
<option value="PENDING TRANSCRIPT">PENDING TRANSCRIPT</option>
<option value="PENDING TUITION PREPAYMENT">PENDING TUITION PREPAYMENT</option>
<option value="PREAPPROVED RETURNING">PREAPPROVED RETURNING</option>
<option value="PROCESSING NDS">PROCESSING NDS<em></option>
<option value="PROCESSING SITE">PROCESSING SITE</em></option>
<option value="PROCESSING Z">PROCESSING Z<em></option>
<option value="PROJECT MESSAGE - MAE 586">PROJECT MESSAGE - MAE 586</option>
<option value="PROJECT MESSAGE - NE 693">PROJECT MESSAGE - NE 693</option>
<option value="REGISTERED">REGISTERED</option>
<option value="REGISTERED ASHEVILLE">REGISTERED ASHEVILLE</option>
<option value="REGISTERED HAVELOCK">REGISTERED HAVELOCK</option>
<option value="REGISTERED WILMINGTON">REGISTERED WILMINGTON</option>
<option value="SITE APPROVAL: ASHEVILLE">SITE APPROVAL: ASHEVILLE</em></option>
<option value="SITE APPROVAL: HAVELOCK">SITE APPROVAL: HAVELOCK<em></option>
<option value="SITE APPROVAL: WILMINGTON">SITE APPROVAL: WILMINGTON</em></option>
<option value="SITE NOT APPROVED">SITE NOT APPROVED</option>
<option value="SWAPPED OUT">SWAPPED OUT</option>
<option value="TRANSCRIPT APPROVED">TRANSCRIPT APPROVED<em></option>
<option value="WITHDRAWN">WITHDRAWN</em></option>
</select>
</article>
</myColBox>
<aside class="notes">
<li>This is that simple drop-down after about ten years of this app being used.</li>
<li>It looks fairly innocuous, right?</li>
</aside>
</section>
<section>
<myTitleBox>
<h2>A "simple" status drop-down</h2>
</myTitleBox>
<myColBox>
<article>
<select name="newStatus" size="47">
<option value="RECEIVED">RECEIVED</option>
<option value="CANCELLED">CANCELLED</option>
<option value="COURSE CANCELLED">COURSE CANCELLED</option>
<option value="COURSE NOT APPROVED">COURSE NOT APPROVED</option>
<option value="CPC DENIED">CPC DENIED</option>
<option value="CPC NOT APPROVED">CPC NOT APPROVED</option>
<option value="CPC PENDING TRANSCRIPT">CPC PENDING TRANSCRIPT</option>
<option value="CPC PROCESSING">CPC PROCESSING<em></option>
<option value="DENIED">DENIED</option>
<option value="DROPPED AFTER CENSUS">DROPPED AFTER CENSUS</em></option>
<option value="DROPPED BEFORE CLASSES BEGUN">DROPPED BEFORE CLASSES BEGUN<em></option>
<option value="DROPPED BETWEEN BEGINNING OF CLASS AND CENSUS DATE">DROPPED BETWEEN BEGINNING OF CLASS AND CENSUS DATE</em></option>
<option value="DROPS/WITHDRAWALS AT SITES">DROPS/WITHDRAWALS AT SITES<em></option>
<option value="ECE ON CAMPUS STUDENTS">ECE ON CAMPUS STUDENTS</option>
<option value="ENROLLMENT CANCELLED">ENROLLMENT CANCELLED</option>
<option value="EOL APPROVED">EOL APPROVED</em></option>
<option value="EOL MISC">EOL MISC<em></option>
<option value="NEW STUDENT REGISTRATION">NEW STUDENT REGISTRATION</option>
<option value="PENDING ON CAMPUS REQUEST">PENDING ON CAMPUS REQUEST</option>
<option value="ON CAMPUS STUDENT NOT APPROVED">ON CAMPUS STUDENT NOT APPROVED</option>
<option value="PENDING CASHIER HOLD">PENDING CASHIER HOLD</option>
<option value="PENDING EOL APPROVAL">PENDING EOL APPROVAL</em></option>
<option value="PENDING INSTRUCTOR APPROVAL">PENDING INSTRUCTOR APPROVAL</option>
<option value="PENDING INTERNATIONAL STUDENT">PENDING INTERNATIONAL STUDENT</option>
<option value="PENDING NDS OPEN ENROLLMENT">PENDING NDS OPEN ENROLLMENT</option>
<option value="PENDING OIS VISA STUDENT">PENDING OIS VISA STUDENT</option>
<option value="PENDING PERMANENT RESIDENT">PENDING PERMANENT RESIDENT</option>
<option value="PENDING TERM ADVISEMENT HOLD">PENDING TERM ADVISEMENT HOLD</option>
<option value="PENDING TRANSCRIPT">PENDING TRANSCRIPT</option>
<option value="PENDING TUITION PREPAYMENT">PENDING TUITION PREPAYMENT</option>
<option value="PREAPPROVED RETURNING">PREAPPROVED RETURNING</option>
<option value="PROCESSING NDS">PROCESSING NDS<em></option>
<option value="PROCESSING SITE">PROCESSING SITE</em></option>
<option value="PROCESSING Z">PROCESSING Z<em></option>
<option value="PROJECT MESSAGE - MAE 586">PROJECT MESSAGE - MAE 586</option>
<option value="PROJECT MESSAGE - NE 693">PROJECT MESSAGE - NE 693</option>
<option value="REGISTERED">REGISTERED</option>
<option value="REGISTERED ASHEVILLE">REGISTERED ASHEVILLE</option>
<option value="REGISTERED HAVELOCK">REGISTERED HAVELOCK</option>
<option value="REGISTERED WILMINGTON">REGISTERED WILMINGTON</option>
<option value="SITE APPROVAL: ASHEVILLE">SITE APPROVAL: ASHEVILLE</em></option>
<option value="SITE APPROVAL: HAVELOCK">SITE APPROVAL: HAVELOCK<em></option>
<option value="SITE APPROVAL: WILMINGTON">SITE APPROVAL: WILMINGTON</em></option>
<option value="SITE NOT APPROVED">SITE NOT APPROVED</option>
<option value="SWAPPED OUT">SWAPPED OUT</option>
<option value="TRANSCRIPT APPROVED">TRANSCRIPT APPROVED<em></option>
<option value="WITHDRAWN">WITHDRAWN</em></option>
</select>
</article>
</myColBox>
<aside class="notes">
<p>I like to open this up for the full effect of how ridiculous it can become. This group was
maintaining their own web app before we inherited it</p>
<p>There are some that are actually subsets of the same status with some explanation attached</p>
<li>Registered with a Site location</li>
<li>Pending with reasons attached</li>
<li>dropped with a time component of when it was dropped</li>
<li>Things like this make the drop-down complicated, error-prone, and go beyond the the problem we want to solve</li>
</aside>
</section>
<section>
<myTitleBox>
<h1>Something Happened</h1>
</myTitleBox>
<myColBox>
<article>
</article>
</myColBox>
<aside class="notes">
</aside>
</section>
<section>
<myTitleBox>
<h3>Something happened</h3>
</myTitleBox>
<myColBox>
<article>
<p>Status is a reflection of something that happened</p>
<p>There is ONE of each status + reasons/details </p>
<p>Events can record what happened</p>
</article>
<article>
<img src="img/status_change/collegerejection.jpg" alt="stamped application">
</article>
</myColBox>
<aside class="notes">
<p>In a workflow, usually something happens and THEN your object's status is
updated to reflect that something happened.</p>
<p>There aren't 9 PENDING states. There is ONE PENDING and some number of reasons for it to be PENDING </p>
<p>Events can record what ACTUALLY happened and the important details of that event. It is actually your history!</p>
<p>Our code can then be written to describe what that event means with context.</p>
</aside>
</section>
<section>
<myTitleBox>
<h2>The Request Doesn't Get Stuck</h2>
</myTitleBox>
<myColBox>
<article>
<img src="img/status_change/events_guage.png">
</article>
<!--<article>-->
<!--<p>The request doesn't get stuck. One event can happen, and then another event can occur after it.</p>-->
<!--<p>A Hold can be lifted, and the request can continue through the process</p>-->
<!--<p>The request can move to a next state </p>-->
<!--<p>History is preserved</p>-->
<!--</article>-->
</myColBox>
<aside class="notes">
<p>The request doesn't have to get stuck. One event can happen, and then another event can occur after it.</p>
<p>A Hold can be lifted, and the request can continue through the process</p>
<p>The request can move to a next state </p>
<p>History is preserved</p>
</aside>
</section>
<section>
<myTitleBox>
<h1>Enter Event Sourcing</h1>
</myTitleBox>
<myColBox>
<article>
</article>
</myColBox>
<aside class="notes">
</aside>
</section>
<section>
<myTitleBox>
<h2>Definition Event Sourcing</h2>
</myTitleBox>
<myColBox>
<article>
<p>The fundamental idea of Event Sourcing is that of ensuring <strong>every change to the state</strong> of an application <strong>is captured in an event object</strong>, and that these event objects are themselves stored in the sequence they were applied for the same lifetime as the application state itself.</p>
<ul>
<li>Martin Fowler</li>
</ul>
</article>
</myColBox>
<aside class="notes">
<p>A lot of what we read about Event Sourcing comes from Martin Fowler. But I like Greg Young's talks the best. His examples are clear</p>
<p>The idea of Event Sourcing is that of ensuring <strong>every change to the state</strong> of an application <strong>is captured in an event object</strong>,</p>
<p>These event objects are then stored in the order they were applied for always and forever</p>
</aside>
</section>
<section>
<myTitleBox>
<h2>What's important about Events</h2>
</myTitleBox>
<myColBox>
<article>
<ul>
<li>Events</li>
<li>Details of the Event (attributes)</li>
<li>Order/Sequence</li>
</ul>
</article>
</myColBox>
<aside class="notes">
<p>We will collect the details of the event, its attributes</p>
<p>The timestamp is important in order to apply it in the correct order</p>
<p>If we were tracking transactions for a bank account, we would have events like Deposit Money
and Withdraw Money. Those would have an amount and an account number. And the order in
which they happened would be critical to having an accurate balance</p>
<p>We are capturing the crucial details with those events. And our system will later apply them
using the rules of OUR process</p>
</aside>
</section>
<section>
<myTitleBox>
<h3>Rules for Events</h3>
</myTitleBox>
<myColBox>
<article>
<ul>
<li>Events are usually named as past-tense verbs</li>
<li>RARELY changed</li>
<li>Never deleted</li>
<li>Have attributes that are values
<ul>
<li>never an aggregate root </li>
<li>never a model/collection/object</li>
</ul>
</li>
</ul>
</article>
</myColBox>
<aside class="notes">
<li>Event Names use Past-tense verbs like Enrollment Request Was Approved </li>
<li>We should <b>try hard</b> not to alter a recorded event</li>
<li>We try to never delete events. This is a historic record within our system. We may stop handling an event if it loses significance in our system. </li>
<li>validation was done prior to recording the event,
and these are KNOWN happenings in our system</li>
<li>This Event will have attributes, like the student id, the course id, and who the approver was
because this is the important information</li>
<li>We wouldn't store the Enrollment Request Object because if makes us unable to change the object in the future; we'd have to reconstruct that object</li>
<li>Storing the VALUES on our Event gives us the flexibility for the system to change later
But that event never will</li>
</aside>
</section>
<section>
<myTitleBox>
<h3>The Object could change</h3>
</myTitleBox>
<myColBox>
<article>
<img src="img/status_change/objects.png">
</article>
</myColBox>
</section>
<section>
<myTitleBox>
<h3>If we stored it in an event...</h3>
</myTitleBox>
<myColBox>
<article><img src="img/status_change/EventWithObject.png"></article>
</myColBox>
<aside class="notes">
<p>If we had stored the older version of the Object, we would have problems accessing it in this case</p>
<p>We could make the third attribute optional or write something to upgrade all the Objects stored in events...</p>
</aside>
</section>
<section>
<myTitleBox>
<h3>Events are not Bionic</h3>
</myTitleBox>
<myColBox>
<article>
<img src="img/status_change/we_can_rebuild_him.jpg">
</article>
</myColBox>
<aside class="notes">
<li>But just because we CAN do it doesn't mean we should do it.</li>
<li>If we store the relevant attributes of an Event, in their data types, we don't have to spend $6 million dollars to rebuild a cat</li>
</aside>
</section>
<section>
<myColBox>
<article>
<h2>The fact that an event happened <u>doesn't ever
change</u> even though the <u>behavior</u> around it may have</h2>
</article>
</myColBox>
<aside class="notes">
<p>Read it</p>
<p>So unlike statuses in our system which evolve over time and could change meaning, You will never change this event</p>
</aside>
</section>
<section>
<myTitleBox>
<h2>Why Events?</h2>
</myTitleBox>
<myColBox>
<article>
<p><u>state transitions</u> are <u>important</u></p>
<p>We need an <u>audit log</u> and <u>proof</u> of state</p>
<p>This <u>history</u> is more important than the current state</p>
<p><u>Able to replay these events to rebuild state</u></p>
</article>
</myColBox>
<aside class="notes">
<li>The events that got us to this state are more important than the current status</li>
<li>We now have an audit log, and proof of how we got to this state</li>
<li>That history is more important that the current state BECAUSE</li>
<li>We are able to replay those events to prove the state</li>
<li>With our Scholarships Application, we helped a student match for the scholarship. We kept track of the current budgets so different users of the system could see what money was left to be awarded</li>
<li>If we needed to see the budgets on any given day in the past, we could produce that information</li>
<li>And when they completely changed the format of budgets they wanted to review, we could easily rebuild that without affecting the amounts.</li>
</aside>
</section>
<!--<section>-->
<!--<myColBox>-->
<!--<article>-->
<!--<p><img src="img/status_change/why_events.jpg" alt="why_events.jpg"></p>-->
<!--</article>-->
<!--</myColBox>-->
<!--<aside class="notes">-->
<!--<li>The events that got us to this state are more important than the current status</li>-->
<!--<li>We now have an audit log, and proof of how we got to this state</li>-->
<!--<li>That history is more important that the current state BECAUSE</li>-->
<!--<li>We are able to replay those events to prove the state</li>-->
<!--<li>With our Scholarships Application, we collected the attributes that helped a student match for the scholarship to keep a record of why they were chosen </li>-->
<!--<li>If we needed to see the budgets on any given day in the past, we could produce that information</li>-->
<!--<li>And when they completely changed the format of budgets they wanted to review, we could easily rebuild that without affecting the amounts.</li>-->
<!--</aside>-->
<!--</section>-->
<section>
<footer>
<img src="img/status_change/dont_delete_events.png" alt="event_rules.jpg">
</footer>
<aside class="notes">
<p>Greg Young in a talk makes a point of how difficult it was to find a picture of an accountant erasing
because that's not something they do. They make a correction to undo a mistake and then make the intended adjustment</p>
<p>So to fix one event, you may have two other events, but that event will (almost) never be deleted</p>
<p>You want to adjust your thinking in this way</p>
</aside>
</section>
<section>
<footer>
<p><img src="img/status_change/events_treated_differently.png"></p>
</footer>
<aside class="notes">
<p>In our system, we have an event with some meaning, and a listener that sees that event when it happens
<li>the apply method tells our system what should happen in this context and it produces this result</li>
<li>Maybe these are two different views in our system, that handle different behavior, those would coexist; like reports for two different types of users</li>
</aside>
</section>
<section>
<footer>
<p><img src="img/status_change/events_replaced.png"></p>
</footer>
<aside class="notes">
<li>but what if our understanding of the event changes. We might rewrite that apply event method, which produces a different result</li>
<li>But it could also be that we rewrite what it means to apply that event and the new apply method stays, with the new report, and the old is deleted</li></p>
</aside>
</section>
<section>
<myColBox>
<article>
<p>Events don't change</p>
<p>The part of the
code that will change is most likely the result that follows that event.</p>
<p> The structure of the resulting data is more likely to change than the behavior</p>
</article>
</myColBox>
<aside class="notes">
<p>The event is less likely to change. Things like Approve and Reject a
Request may later require additional attributes</p>
<p>The part of the process most likely to change is the result that follows that event.</p>
<p>For example, they may add a step in the process</p>
<p>The structure of the resulting data is more likely to change than the behavior</p>
<p>For example, they may decide to change a report</p>
</aside>
</section>
<section>
<myTitleBox>
<h2>The Code</h2>
</myTitleBox>
<myColBox>
<article>
<p> There are many classes involved:</p>
<ul>
<li>Events</li>
<li>Domain Message</li>
<li>Classes with Listeners<ul>
<li>Projections</li>
<li>Read Models</li>
</ul>
</li>
<li>Commands & Handlers (CQRS)</li>
</ul>
</article>
</myColBox>
<aside class="notes">
There are several patterns that we use here, and I'm going to try to describe how the pieces fit
together, but I am avoiding including code because of time limitations
</aside>
</section>
<section>
<footer>
<img src="img/status_change/exercising_brain.jpg">
</footer>
<aside class="notes">
<li>It's completely normal to feel like this when you're learning about Event Sourcing</li>
<li>It's a REAL mental shift coming from an older application to ES, so try to relax your brains a little</li>
<li>Try to follow the way I'm describing how it can be used because it will help when you begin to see event sourced code.</li>
<li>Be patient with yourself and know that you may do more reading before this clicks</li>
</aside>
</section>
<section>
<section>
<myColBox>
<article>
<!--<ul>-->
<!--<li>request id</li>-->
<!--<li>student id</li>-->
<!--<li>course offering id</li>-->
<!--</ul>-->
<img src="img/status_change/EnrollmentRequestRejected.png">
</article>
</myColBox>
<aside class="notes">
<li>We will look at the Enrollment Request Rejected event for parts of this process</li>
<li>The event has a few values we care about </li>
</aside>
</section>
<section>
<pre><code><?php
namespace App\Enrollment\Domain\Events;
use App\Enrollment\Domain\CourseOfferingId;
use App\Enrollment\Domain\StudentId;
use App\Support\Domain\Uuid;
use App\Support\EventHandling\Event;
class EnrollmentRequestRejected implements Event
{
/**
* @var Uuid
*/
public $enrollmentRequestId;
/**
* @var StudentId
*/
public $studentId;
/**
* @var CourseOfferingId
*/
public $courseOfferingId;
public function __construct(Uuid $enrollmentRequestId, StudentId $studentId, CourseOfferingId $courseOfferingId)
{
$this->enrollmentRequestId = $enrollmentRequestId;
$this->studentId = $studentId;
$this->courseOfferingId = $courseOfferingId;
}
/**
* @return array
*/
public function serialize()
{
return [
'id' => $this->enrollmentRequestId->toString(),
'student_id' => $this->studentId->toNative(),
'course_offering_id' => $this->courseOfferingId->toNative(),
];
}
/**
* @param array $data
*
* @return static
*/
public static function deserialize($data)
{
return new StudentRequestedEnrollment(
Uuid::fromString($data['id']),
StudentId::fromNative($data['student_id']),
CourseOfferingId::fromNative($data['course_offering_id'])
);
}
}
</code></pre>
<span class="fragment current-only" data-code-focus="10"></span>
<span class="fragment current-only" data-code-focus="28"></span>
<aside class="notes">
<li>(*) The Enrollment Request Rejected Event inherits from an Event class that outlines a bit of behavior. </li>
<li>(*) The constructor sets the values we care about with the event object</li>
</aside>
</section>
</section>
<section>
<section>
<!--<myTitleBox>-->
<!--<h2>Domain Message Wrapper (Class)</h2>-->
<!--</myTitleBox>-->
<myColBox>
<article>
<!--<p>Event can be wrapped by Domain message</p>-->
<!--<p>This contains a version, timestamp, id, and the event itself</p>-->
<!--<ul>-->
<!--<li>stream id</li>-->
<!--<li>version</li>-->
<!--<li>payload (The Event)</li>-->
<!--<li>recorded on</li>-->
<!--</ul>-->
<img src="img/status_change/DomainMessage.png">
</article>
</myColBox>
<aside class="notes">
<li>The first app we used Event Sourcing, Scholarships, we included timestamp data on the
event, but for this application, my teammate had seen more consensus that the Event and
Message should be separated</li>
<li>We are able to keep the sequence and timestamp on the message, which holds the event as its payload</li>
<li>The version is useful in a workflow project, where we want to upgrade these to use a new workflow. We can keep track of which process was used to build something. </li>
</aside>
</section>
<section>
<pre><code><?php
namespace App\Support\Domain;
use App\Support\EventHandling\Event;
use DateTime;
class DomainMessage
{
/**
* @var string
*/
private $streamId;
/**
* @var int
*/
private $version;
/**
* @var Event
*/
private $payload;
/**
* @var DateTime
*/
private $recordedOn;
/**
* @param $streamId
* @param int $version
* @param Event $payload
* @param DateTime $recordedOn
*
* @internal param string $id
*/
public function __construct($streamId, $version, Event $payload, DateTime $recordedOn)
{
$this->streamId = (string) $streamId;
$this->version = $version;
$this->payload = $payload;
$this->recordedOn = $recordedOn;
}
/**
* @param $streamId
* @param int $version
* @param Event $payload
*
* @return DomainMessage
* @internal param string $id
*/
public static function recordNow($streamId, $version, Event $payload)
{
return new DomainMessage($streamId, $version, $payload, new DateTime());
}
/**
* {@inheritDoc}
*/
public function getStreamId()
{
return $this->streamId;
}
/**
* {@inheritDoc}
*/
public function getVersion()
{
return $this->version;
}
/**
* {@inheritDoc}
*/
public function getPayload()
{
return $this->payload;
}
/**
* {@inheritDoc}
*/
public function getRecordedOn()
{
return $this->recordedOn;
}
/**
* {@inheritDoc}
*/
public function getType()
{
return get_class($this->payload);
}
}
</code></pre>
<span class="fragment current-only" data-code-focus="39"></span>
<span class="fragment current-only" data-code-focus="55"></span>
<span class="fragment current-only" data-code-focus="63"></span>
<aside class="notes">
<li>This is our Domain Message class </li>
<li>(*) The constructor sets the values for our stream id, version, payload, and timestamp</li>
<li>(*) We use the Record Now method to record that the event happened, returning the new Domain message</li>
<li>This at first seemed like extra work, but I've grown to like it a little more</li>
<li>Below we have getters to get attributes of the Domain Message </li>
</aside>
</section>
</section>
<!--<section>-->
<!--<section>-->
<!--<!–<myTitleBox>–>-->
<!--<!–<h2>Simple event listener</h2>–>-->
<!--<!–</myTitleBox>–>-->
<!--<myColBox>-->
<!--<article>-->
<!--<!–<p>Handles Event Listening</p>–>-->
<!--<!–<p> </p>–>-->
<!--<!–<p><b>getHandleMethod()</b> - <br>uses the Event name to identify the handle method</p>–>-->
<!--<img src="img/status_change/Listeners.png">-->
<!--</article>-->
<!--</myColBox>-->
<!--</section>-->
<!--<section>-->
<!--<myTitleBox>-->
<!--<h2>Simple Event Listener </h2>-->
<!--</myTitleBox>-->
<!--<pre><code><?php-->
<!--namespace App\Support\EventHandling;-->
<!--use App\Support\Domain\DomainMessage;-->
<!--abstract class SimpleEventListener implements EventListener-->
<!--{-->
<!--/**-->
<!--* @param DomainMessage $message-->
<!--*/-->
<!--public function handle(DomainMessage $message)-->
<!--{-->
<!--$event = $message->getPayload();-->
<!--$method = $this->getHandleMethod($event);-->
<!--if (! method_exists($this, $method)) {-->
<!--return;-->
<!--}-->
<!--$this->$method($event, $message);-->
<!--}-->
<!--private function getHandleMethod(Event $event)-->
<!--{-->
<!--return 'handle' . class_basename($event);-->
<!--}-->