The dreaded status column w/ Daniel Coulbourne + Cheyne Rood
00:06.61
Chris Morrell
All right welcome back to another episode of overengineered the podcast where we ask the very important question. What's the best way to do things that don't really matter today I am here with my friends asschene rood and Danielle colborn.
00:22.90
Cheyne Rood
Clo.
00:23.86
Chris Morrell
Welcome guys. Um, and we have been talking about this particular topic outside of the podcasting world for a while. So I'm excited for it but ah before we kind of get into what we're talking about today.
00:23.95
Daniel Coulbourne
What up.
00:41.10
Chris Morrell
Ah, would you 2 like to introduce yourselves.
00:45.78
Cheyne Rood
Surere I'm Shane I am a developer and own a couple of businesses in the magic gathering space I've been working with ph p for a little over. 15 years
01:04.34
Daniel Coulbourne
Cool. Um I'm Daniel I'm a developer I currently run ah like a small agency called thunk with a couple of my friends sort of specializing accidentally in like events sourcing and like livewire and alpine stuff so that is. Kind of what I'm up to these days but I've written a lot of laravel and various frontend javascript frameworks and stuff over the last couple of years.
01:29.61
Chris Morrell
I also can't imagine that someone will be listening to this without having heard of no plans to merge but Daniel is also the co-host of the podcast. No plans to merge that's right, not fm.
01:42.17
Daniel Coulbourne
No plans to mege.com ah no but I do own nptm dot fm which redirects to no plans tomerge.com so
01:52.29
Chris Morrell
Um, weren't you the one who convinced me to get the dot fm.
01:54.75
Daniel Coulbourne
Because the.com wasn't available. Yes.
01:59.56
Chris Morrell
Um, okay, all right? Well so event sourcing is definitely one of the things that's going to come up today but let me let me set the scene. So right? like ah every episode we pick a thing that ah. Programmers in general probably but certainly laravell developers are likely to to bump into over and over again and ah choose a solution that is fine but maybe not the best um and one of them that Shane and I have talked about a ton. And you and I have talked about Aund Daniel are ah status columns when you have a model and it has a status column and you need to deal with status transitions and you need to deal with time stamps related to statuses I feel like this is. Ah, thorn in my side. Ah every few months and I've never really been happy with the solution that I've come up with whether that's you know, just a column that is the status and then a couple timestamp columns or some sort of like status column that's derived from timestamp columns. And know that there are lots of packages out there that try to do this but ah, it's just always annoying to me.
03:22.33
Daniel Coulbourne
And I feel like 1 thing to call out is that like the status column is not really a problem. The status column itself is a solution. Um, and so like I think there is like getting to the underlying problem that a status column solves which is like.
03:30.36
Chris Morrell
Um, yes.
03:39.75
Chris Morrell
Um, sure.
03:40.88
Daniel Coulbourne
I Have a model that passes through phases and I want to know like where it is in that in that journey right.
03:45.64
Chris Morrell
Yeah, where it is potentially when it got to where it is or when it got to specific phases I think that.
03:52.52
Daniel Coulbourne
Potentially Also how and why it got there but a status column won't tell you those things.
03:57.22
Chris Morrell
Yes, yeah, how and why I think how and why don't come up as much for me but sometimes they do for sure when happens a lot I think depending on the status and then what the status is at the current moment. I think comes up all the time right? is there anything that you want to add to to that Shane.
04:20.81
Cheyne Rood
Um, yeah I mean this is something I see a lot of is various contexts of having a status column and and my general approach is just that have a status column and have a timestamp for every possible value. Um, and that I find works in the majority of cases.
04:46.65
Daniel Coulbourne
So like ah accepted at rejected at declined at canceled at just a bunch of timestamps for all of the different transitions Gotcha I feel like when we're talking about this. We should I feel like we should like.
04:54.49
Cheyne Rood
E.
05:03.57
Daniel Coulbourne
Take a step back and like define a domain that we're trying to solve a problem for even if it's like a fake made up domain. Do you have 1 in mind Chris.
05:10.97
Chris Morrell
Um, yeah I'm happy to ah, provide something or if like Shane and do you want to use a ah real world example from from the app that you're working on or do you want to? ah use I have an example I could make up.
05:26.40
Cheyne Rood
Yeah I mean I definitely could offer some examples I was just looking at stuff like this earlier today. Um, so I'm trying to pick like what's the best sort of model to start with um, let's say somebody wanted to sell.
05:39.62
Chris Morrell
Are.
05:42.84
Cheyne Rood
A collection of magic cards. That's something I see all the time in my life. Um, so if I were thinking through what are the statuses of that kind of what we I refer to as an inquiry. Um.
05:45.23
Daniel Coulbourne
Yeah, let's let's just say for instance.
06:01.35
Cheyne Rood
So they submit a form and at that time let's say it's created is the status and we've sat created at which you know that comes with most models. We're all used to that already. Um and then from there.
06:12.96
Chris Morrell
Um.
06:21.30
Cheyne Rood
Ah,, let's say we need to price it so we have some kind of process that runs um at that time we might find that we run into like an error state. Let's say that their file is Invalid. So. We'd maybe want to have a way to handle that it could be a status. We also might find that their cards aren't really worth our time and so we might say we don't want to make an offer at all. Um, but if it meets our Criteria. We'll say we do generate an offer. So at that time we would say okay the status is that we have issued an offer now the customer has a choice they can decide to accept it and if they do so we have the offer accepted status and then maybe we want to see that the cards were transferred to us. And once that's happened. There's a transferred status and then we need to issue payment and so at that point once we've issued the payment we would maybe call that completed.
07:27.12
Chris Morrell
Yeah I think I mean this is ah sort of the typical flow right? It's like you've got some sort of record. It's going to flow through a bunch of statuses I think one of the places that I notice throws a wrench in things are um. Like nonlinear statuses things like an error state or an issue or like needs. Um, like maybe you have a linear flow of like created um offer issued offer accepted payment paid or whatever. But. You may have like in this case, maybe maybe there's like a black lotus in there. There's a car that's incredibly valuable and it needs some sort of manual review right? So you I think the the one of the wrenches that I want to make sure that we like identify early is um.
08:23.55
Chris Morrell
Ah, situations where there's like a linear flow but there are also like statuses that are outside of that linear flow that need to be accounted for and maybe there's some sort of logic about like when something gets into the issue state. It needs to.
08:29.82
Daniel Coulbourne
Yeah.
08:39.15
Chris Morrell
Go through some other process before it can get back into the regular flow. Um.
08:43.81
Daniel Coulbourne
So I I think that every every flow. No how no matter how regular it seems inevitably has some something that breaks it if you live with the app long enough. Um, so for example, like ah.
08:55.24
Chris Morrell
Um, yeah.
09:01.78
Daniel Coulbourne
The situation you just just described right? So like you accept a inquiry right? and so then now they need to like send you the cards. Um, well what happens if Fedex loses that package right? So now Fedex loses the package so like what state is the order in in a situation where like they accepted it. Maybe.
09:08.87
Cheyne Rood
You know.
09:21.64
Daniel Coulbourne
We were going to pay them then they sent us the thing and then the thing got lost but we have the shipping number for it and like it's now in a state that is just like different than any other state we had planned for right? The state of like am I suing Fedex like what's going on here. You know.
09:35.65
Chris Morrell
Yeah, package lost state.
09:37.95
Daniel Coulbourne
Package lost state right.
09:42.58
Cheyne Rood
Yeah I do think that some of the things I work with when there is a status it really is that cut and dry like it really doesn't change. Um and you know I think Chris you and I have talked a lot about stuff like this because. We both have apps that we lived with for many years and so we've seen like the progression of certain things needing to be maintained or changing statuses like this need to be to to be maintained and um.
10:12.78
Cheyne Rood
Definitely it does seem like a contextd driven like complexity driven situation where like the status column with times stampmps works for me when things are simple but once to your point Chris like things get nonlinear or you have like branching paths it it gets hairier and maybe that does call for. Things that are like a more sophisticated handling. Um, but yeah, it's to your specific question about like this collection. What if it goes missing or something like that again, it depends on like how sophisticated you want to get I mean you could just say um in the case of ah. My one business card conduit where we're dealing with these kinds of shipments. We might have something as simple as ah, returned sort of catch all that says. Yeah, we just shipped these cards back to the customer or canceled. Um. And something that requires more like support like we have to get involved with Fedex or something like that is really sort of handled offline. It. It doesn't necessarily need to be the concern of the web app at that point.
11:20.00
Chris Morrell
Right? You can just kind of use a catch-all like issue or like problem status and just leave it to manual action from there on out I mean that's and that's kind of how we do that We we have a similar sort of like job.
11:34.30
Daniel Coulbourne
Um, so I have.
11:39.76
Chris Morrell
Ah, um, job assignment or you know work assignment Feature. Ah where things tend to be linear but we have those like Catch-all just oh this. This job has a problem of some sort. It's in a problem state and like. There's now it's just up to admins to figure out what to do with it.
11:58.59
Cheyne Rood
E.
12:01.97
Daniel Coulbourne
So I have kind of like a thesis right? So like I'm I'm kind of coming in with like ah with like ah, an angle right? which is I've said this publicly already. But like I think like generally speaking Status Columns are like an indication. Ah that. You want to actually be storing actions instead of the acted upon objects. Um, and so like if you think about like the sta coms that we've brought up before' there's like offered right? and then there's like accepted and rejected and sent. Right? And all of them are sort of these like past tense verbs um that refer to a thing that happened um, an event an action. Whatever whatever you want to call it right? and I think that like in object-oriented World. Um.
12:43.16
Chris Morrell
Um, one might even say an event.
12:54.73
Daniel Coulbourne
We are So We're really mostly only comfortable with nouns. Um, we only like to store objects and like objects with attributes and like things like an order or or a ah a post or a user or you know things that ah. People places and things. Um and my argument is that like the existence of Status Columns is a yearning for a verb right? And like if you've added a status column to to a. An Object What you're saying is I need a way to store verbs but I want I want to keep inside of this noun-based Paradigm. So I'm going to store verbs as attributes of Nouns. Um and generally speaking I think that. The fact that we hamstring ourselves into only using sort of objects and attributes leads us into these situations where we're forced to use catchall statuses because the actual specificity of what really happened doesn't fit the model. Um, and so we're sort of forced into these like extremely broad catchall statuses where you know an object may have gotten into this state in 15 different ways that aren't really the same thing. Um, but we're going to kind of try and find an equivalence.
14:27.47
Daniel Coulbourne
Between as many of them as possible. Just so that we don't end up with 45 different statuses that we have to write giant branching if statements about.
14:36.83
Cheyne Rood
I do think there is an inherent awkwardness to the status. Column I've always felt that I don't know it is just a sort of awkward thing to work around I'm comfortable with it now. Um and sort of have the pattern I like to apply. But event sourcing in the concepts around. It are super interesting to me I was actually recently telling Chris that that's something I'm starting to study and I think is going to be a really good fit for something I'm working on. Um I guess like what concerns me is the cost in terms of additional complexity. And just not really being familiar with um the implementation.
15:16.26
Chris Morrell
Yeah I mean part of the reason that I asked the 2 of you to be on this call is like I think these are two sort of your current approaches represent the 2 extremes right? like the status column and a bunch of timestamps. Is um, really obvious um and works well I think until it doesn't excuse me and then on the other side. Um, treating. Statuses as ah, events or actions or whatever probably more accurately represents the real world but is is a level of of abstraction that I think just is is inherently less obvious.
15:55.74
Cheyne Rood
You.
16:12.50
Chris Morrell
And I'd love I feel like you know I I come into this I come into each episode imagining a world where we like solve this problem at the end of it. You know, not not with any belief that that's truly possible but I would love to come out of this imagining a world where. You can get the benefits of sort of an evented approach but the clarity of the sort of straightforward just have a status column approach like that's that's that's my agenda. Maybe I have I shouldn't have an agenda but that's that's where I am because I. I agree with kind of both both of you on this.. It's like I have seen the power of event sourcing and um, it's been really, really useful to us in in the places that we've used it. But I also know that. When I go back to that code. It takes me a little while to get my head wrapped back around how the heck it's working you know.
17:16.74
Daniel Coulbourne
Yeah I think 1 thing you said which I'm not going to give you for free is that ah event sourcing is somehow like non obviousious or like ah more of an abstraction or more of a mental convolution.
17:34.20
Daniel Coulbourne
To wrap your head around then sort of ah this sort of status Column approach which you described as obvious um I think I completely disagree right? So I think the status Column I think of the status Column approach as like a convolution. Um and like taking. A thing that was a clean concept like if I just described to you the customer canceled the order right? like that to me is a straightforward concept and ah if I said to you the customer moved the order into the status canceled like. To me. That's like a non-obvious ah concept right? So I think that the the actual implementations of event sourcing are different than a lot of regular object- orientiented code that we write and so since we live in object-oriented land so much of the day. It's a shift to it's a mindset shift to think differently and if you're if 85% of your code is just regular object-oried code and you've got 15%. That's event sourced. It. The context switching may you know may make it seem more complicated than it is but when I live in an app that is fully event sourced. Um, or when I when I stay in event mode for extended periods of time. Ah I think that that to me storing actions and thinking in terms of what happened as opposed to how like as opposed to.
19:06.69
Daniel Coulbourne
What were the sort of secondary effects and the ways that the world changed as a result of what happened um is easier for me to wrap my head around and more obvious and.
19:16.90
Chris Morrell
Um, I Yeah I Totally agree with that I I guess I'll clarify. Um I think you're absolutely right that the ergonomics of triggering The events is is much better right? Like you said, ah you know accept.
19:32.70
Cheyne Rood
Oh.
19:35.10
Chris Morrell
Accept The shipment is is much more clear than like set the shipment to the accepted status. Um, and yeah when I talk about obviousness I guess I'm thinking within the context of like ah this.
19:53.13
Chris Morrell
Standard conventions of a layerrall app right? This is not how the majority of laral developers think about code. So like if you're bringing on a new new developer or if you're working on an open source project that other people are going to be interacting with or you know anything where other people. Um, need to interface with the code sticking to straightforward conventions. Um I think is more obvious and I also will say that I find um and I I'm just going to kind of ah lob this up as as something to. To ah sort of dispel later. But um I think a large portion of the time when I'm dealing with statuses I am dealing with them in the context of a point in time right. So I want to pull all of the jobs that need to be assigned or I want to um, find all the jobs that haven't had you know were assigned but haven't been scheduled. You know. Or you know where the window between when they were signed and scheduled is more than three days or something like that I'm I'm kind of like a lot of the time that I'm dealing with models that have a status column. It's not.
21:24.34
Chris Morrell
In the impacting the status. It's the dealing with the current state of of the model and so I think you know I can add a helper function that's like um accept to a model that just. Sets the status to accepted and now I get the ergonomics of like using the verb but it's a little bit harder. Um, if I'm just thinking of like okay a model has many events. And now I need to like parse through all of the events to determine like what its current state is obviously that's if that were the solution. It would not. It would not be very economic.
22:12.10
Daniel Coulbourne
So sure Shane what are you thinking.
22:20.43
Cheyne Rood
I Guess thinking like you're describing this ah event sourcing um as a way of sort of seeing how things happened over time and to me this sort of status Column concept with. If you're providing a timestamp that you're setting for each one of those possible statuses. It's not that dissimilar from it just in a much more primitive form like you're getting a timestamp like if you want to to know the sequence of events you know? Okay, it was the ah. Offer was generated at this time and then this happened and then this happened and you can sort of read it back like a story. Ah, just with the timestamps. You're just not.. You're not working with the nomenclature that you prefer you know the Concepts Um, and so that admittedly is a little more awkward. But. And ah, and of course it's a it's a more brittle sort of hardcoded um situation. But you still get to tell the story when you look at the state of the model. Yes, you can look at the current status and then you can look back at this sort of expected sequence again. Pretty linear. Um, but you I mean you do have that information.
23:38.68
Chris Morrell
Um, yeah, and less like you go back? Oh go ahead.
23:38.68
Daniel Coulbourne
And 1 other thing that I feel like well I was going to say like 1 other thing that I feel like ah starts to make it unwieldy is as soon as you need a second piece of information about any status change right. So for example, like say I need for legal purposes to capture a user's ip address and user agent when they accepted the offer right? So that I can have some sort of indication that it was actually this user my only option then is to add a. User accepted offer ip column and a user accepted offer Ua Column and store both of those things and if I need to god forbid store an ip and user agent for multiple status changes. So like the first status change I need what ip were they on. The second status change I need what I p were they on now I might be adding rather than just adding one column for each status change I might be adding 3 columns for each status change.
24:32.23
Cheyne Rood
Yeah, yeah.
24:40.40
Cheyne Rood
I Think that's totally valid and I think that that's where as things get more complex like these kinds of problems arise the other place that I like not that long ago was grappling with some aspects of this was. I Wanted to have a sort of wizard flow for our customers to be able to step through um the various states of sending a shipment to us and there are um. Various sort of like disclaimers along the way where we explain. Okay here are the fee structures. Please agree to these terms here are the ah I don't know some other information or like um things that we want the user to be presented with and we and we want them to able to go Back. So you're on your current state. Status where you're sort of seeing this is what you have to interact with and maybe they're just waiting for something to happen but we want them to be able to go back and see like okay, what terms did I agree to and what fees did you say there were going to be and those are scenarios where it is pretty tricky to implement that with this you know. Pretty simple. You know status and timestamp.
25:53.60
Daniel Coulbourne
Like like storing non-final data or something like data like this isn't finalized data that we can like use in the app yet it only really exists to be able to like repopulate the form that they filled out that they want to view before submitting it.
26:10.93
Cheyne Rood
Yeah, and we want to make sure that what they're seeing is consistent with what they experienced. So if you change your fee structures which could happen. You know so you need to sort of be mindful of ah showing the same terms that they agreed to you know?? whatever? um. And that stuff is ah is tricky.
26:33.12
Chris Morrell
So I feel like there are 2 concepts that in my mind if I'm trying to imagine like a really nice generalized solution to this problem. Ah the two things that I'm going to reach for are state machines right? and event sourcing. Think that while I'm not convinced that I'm not convinced yet that just a regular vanilla larall app should immediately jump to event sourcing when they need a status column because I I do worry about. The context switching there. Um I wonder if there's maybe an abstraction around event sourcing that would feel um, feel more obvious in the sort of object-oriented world. Um, and I you know and I think that there's been a lot of work done around state machines um state transitions and like the sort of rules because that's something we haven't really talked about but you know oftentimes you you for more complex systems. You may have roles in place about what? Um, what transitions are possible. Can you go from a to b right? or you know or you can't go from a to c you need to go from a to b to c um, and so I think I would guess.
28:00.53
Chris Morrell
That state machines. Um Well state machines are are complex but in the simplest form right? It's just some system of defining the different states that a thing can be in and the rules about. How they can transition between those states and what to do when they do. Ah yeah, and event sourcing is kind of you know a similar concept. Maybe they are they're they're kind of overlapping concepts. But.
28:22.32
Daniel Coulbourne
Yeah, it's like the the rules and also the process for transitioning. Um.
28:37.47
Chris Morrell
I'm just going to take one second and Daniel then maybe correct me if I get any of this wrong, but let's just like put a basic ah the basic terminology together so that then we can kind of think about how we might be able to to solve this um using these ideas so like. And event sourcing we have events and projectors and ah something called an aggregate route which we don't really have to think about more than the aggregate route is the thing that events happen to um and so we have this. Um, what's ah, what's it called chain an offer or ah, an inquiry right? So the aggregate route is the inquiry um events happen to the inquiry and then you have projectors that take the event and project state.
29:17.22
Cheyne Rood
Can inquiry.
29:33.68
Chris Morrell
Into your system right? So when a ah created event happens to the inquiry that is going to set the status on your inquiry model to create it and when an accepted offer accepted event happens. The projector will project the. Accepted status onto your model and if in the case of your of your business logic. You need to know the accepted at Timestamp very regularly you can choose to add an accepted at column to your model and have your projector. Project that um timestamp to the model. Um, when an accepted event happens. But for the statuses that you don't really care about the times stamps for you. Don't need to store them on your model. Because you have that data in your event stream. You can always go back and grab it. Um, you can always add a new projector later that projects that data if you need it? Um, so the data is there but it's not your model is sort of just memoizing the data um or caching the data. Ah, for the current state of the stream of events does that seem like a clear enough picture of sort of formal event sourcing.
30:58.99
Daniel Coulbourne
Yeah I would um I think that you leaned away from aggregates as like a thing that we don't need to talk about I think aggregates are I would say we don't really need to talk about projectors I think aggregates are the most important thing to talk about which is like the idea of building up a state. From the things that have happened so being able to answer the question like what is the situation right now based on what has happened in the past to me is like the most important thing that you can do with event sourcing.
31:32.63
Chris Morrell
Sure I I Guess in my mind I think of aggregates as um, the implementation of of doing that internal to your event sourcing logic and then projectors are the way to. Get the results of that work out into the rest of your app and so while I agree that understanding and and implementing aggregates is really really fundamental to to getting event sourcing right? I think from from the outside world. All I Really care about is when I do. When I trigger a new and accepted event I Want my model to have an accepted status and I want that to just always work and like throw an error if that's not allowed to happen.
32:25.16
Daniel Coulbourne
Yeah I mean I think that that that is ah that is a way to do it right? I think there's also like a world where maybe I want totally separate models for the accepted and rejected ones. Maybe I want like 1 table that's full of. Accepted events because like there I care about a lot more information like there's like in those cases I care about like having like ah you know a ship date and like you know, maybe a shipment id and all these other things that like might only relate to something that I've accepted. Whereas if it's declined maybe all I care about is like what date did we decline it and who submitted it because like there's never going to be a shipment so why have an empty shipment id column you know so there are cases where like I think a single aggregate might project into multiple different models or ah. Might project totally differently than just sort of like a model with a status column.
33:24.69
Chris Morrell
Um, sure. So I guess my question is is is there like an in-between somewhere where you know for for for. Chains app like if he doesn't want to buy in you know altogether to event sourcing and he doesn't want to let's imagine that he doesn't want to have to understand what an aggregate route is or the rules around like what can happen in your aggregate and what. Why your aggregate can't understand the model that models exist like all the sort of rules that are are good to know when you're implementing event sourcing like is there is there like a world where where you can just. Pull on some sort of trait onto a model and under the hood. It could use formal event sourcing Concepts so that you can sort of peel that back later and and get more sophisticated but you could kind of solve the problem that we're talking About. Of I Want to have a status column I Want to have I want to understand some metadata around that those statuses but I don't want to get too fancy.
34:52.50
Daniel Coulbourne
And so I could imagine something along those lines I think that I'm a little bit. Um I'm a little bit event supremacist here in that like I think that you're what you're going. You're. Can think of all of the ways where this is going to make you wish that you had just done event sourcing in the first place right? Like you're going to try on this half this half measure um and then you're going to run into its limitations and be like ah why didn't I just do this the other way. But. I can imagine a situation where like you know, maybe you create these like sort of action methods that accept some metadata so you could just have like action and apply action methods so like ah cancel offer and apply canceled offer methods. That you could just potentially stick on your model and ah they would each accept some metadata right? Um, and then ah I could imagine that working. Um.
36:04.77
Daniel Coulbourne
And so the main the main thing that you avoid there is having to have actual event objects right? and so you could just instead of having objects. You could have like some sort of structured data.
36:04.96
Chris Morrell
Um, but isn't that it.
36:22.60
Daniel Coulbourne
Structure that you're passing around that isn't actually reflected by a class and a file that exists in the file system. Um and instead of having a file that represents an aggregate you could just have like some random methods on your model that maybe you demarcate with attributes or something to say like. Hey these are ones for dealing with with events. So like you could You could take all of the bits of event sourcing and sort of shoehorn them into existing files in a larabel app. Um I think that.
36:56.18
Chris Morrell
Um, but that that feels like the worst of both worlds right.
36:56.93
Cheyne Rood
Ah I was going to say I I think the the idea of dedicated files in classes for events that are meant to capture a moment in time and like something happening is is quite appealing I think that.
36:58.84
Daniel Coulbourne
Well, that's what I'm saying I kind of think all of this feels like the worst of both worlds like you know.
37:16.58
Cheyne Rood
What I struggle with and again I'm sort of looking into it because I think this implementation could be really good for something I'm working on right now. The thing that's tough for me is like where are the edges and I think Daniel before you said that it's you want to sort of go all in because the context. Switching can be burdensome and for me if I don't want to go all in but I do want to implement this is that is the juice worth the squeeze in that scenario.
37:46.78
Daniel Coulbourne
So I would not say you want to go all in the the thing I was saying is that I think that the reason it feels complicated is because of the kind of the context switching right? um.
37:55.00
Cheyne Rood
And it's like an ethos right? I mean it's like a you're you're approaching these problems with a different mindset.
38:01.96
Daniel Coulbourne
Sure? But there are I mean there are huge like there are parts of apps that I do not think should be event source right? like ah authentication right? like I don't think authentication should be event source I think users should have like a. Password hash column and an email address column and then they should type their username and password into a form and submit it and then get logged in and I don't think that we should have like a user logged in event that then projects their session hash or you know something crazy like that like I think that. For the most part like object-oriented. Programming is good and you know I know there's people who disagree but like object-oriented programming is like fine. Um, there was a time back when all of the architectural concepts that led to rails and larael. Were being bandied about in the first place by people like Martin Fowler and all these you know all these architecture wizards um, where domaindriven design this concept right? was like the idea of like 3 types of models right? which are like. Ah, like models where like you care about their identity that have an id right? and then like models where you don't care about their identity where they're basically like ah fungible and any model could be any other model and then like events those were like the 3 types of models you know in domain-d driven design and like.
39:34.53
Daniel Coulbourne
Somewhere along the line like we just kind of got to this place where we we dropped events. But I think that these things actually do live really nicely alongside each other and I think that like things like users where like it's important to distinguish one user from another user. Ah.
39:34.57
Cheyne Rood
You can.
39:51.67
Daniel Coulbourne
Are like identity based models and like shouldn't be sort of brought into like an event paradigm. But.
40:01.71
Chris Morrell
Um, yeah, the the question just becomes how do you if you're if you're building an app that where you know this idea the status column is sort of the first place where you're really, um.
40:19.71
Chris Morrell
Wanting an evented approach. You know is there is there a way to to implement some of these concepts without introducing quite so much complexity as formal event sourcing.
40:32.34
Daniel Coulbourne
Can you be more explicit about like what complexity You think you can get rid of.
40:39.61
Chris Morrell
Um, well okay, yeah here I'll just imagine something like I can imagine I agree with Shane that um, having objects that represent. The events makes a lot of sense right? And um I think.
40:49.52
Daniel Coulbourne
Ah.
40:57.70
Chris Morrell
And and as soon as I say this out loud I may change my mind but I'm going I'm going to go down this path at least I think that there's maybe a world where I have a um accepted event or Accept. You know Accept Um, why can't I think of that I keep on losing this word Inquiry Accept Inquiry right? or inquiry accepted. Yeah, um, right? and in the constructor. The inquiry accepted event.
41:20.54
Daniel Coulbourne
Yeah, accepted Inquiry is probably what I would call it past tense Inquiry accepted. Sure.
41:35.31
Chris Morrell
Takes all the metadata that that event is going to need and I know that from a you know event sourcing purism perspective. This is probably terrible. But what if that event just had. Projection Logic right? There here's the event and then there's also a method on the event that Accepts an inquiry model and applies the event data to that model and that's the whole thing right? So Now. You have you just dispatch these events. They project themselves to to whatever models you need them to project themselves to and um, under the hood.
42:15.35
Daniel Coulbourne
Like events that project themselves. Basically.
42:31.70
Chris Morrell
In an ideal world. There would be um, a proper event sourcing implementation that this is sort of like a layer on top of so that the moment you need to do something that's sort of outside of the scope you need multiple projectors you need reactors. You need I don't know. Um.
42:47.96
Daniel Coulbourne
You need to make a decision about whether or not to project some data based on other events that have already happened right.
42:50.24
Chris Morrell
You need to? yeah like you can kind of peel this layer away when you need it but in the beginning I could just have an inquiry accepted event that Accepts the inquiry and the metadata.
43:03.63
Daniel Coulbourne
Are.
43:10.90
Chris Morrell
And then just applies and then just updates the inquiry object to have the status accepted and that's the whole thing and that.
43:21.65
Daniel Coulbourne
Yeah I think that's fine I Don't think there's anything wrong with that. Um, yeah I think that basically like I think the requiring a projector to be a separate file than an event is.
43:25.55
Chris Morrell
Um, that feels good to me.
43:39.15
Daniel Coulbourne
You know I think if you build if you build something more than like maybe this one state machine you will quickly want separate projectors but I do think that like like we have a really really big. Event sourcing app. Um, this game that we built and we have one projector file like we have a file that contains all projection logic in the entire app and it's giant 800 line file or whatever but like it's one file you know? Um. So I don't think that there's like a right or wrong place to put projection logic. Um I think that having it on the event itself is a little bit uncomfortable because it removes. The logical path to like an event fires then we make decisions then we project. But I think as like a starting point I think saying that like events have an optional project function on them and that if an event has a project function.
44:50.51
Chris Morrell
Yeah.
44:54.87
Daniel Coulbourne
Then we fire that project function. Um I think that's fine. Um.
45:02.69
Chris Morrell
Um, right? and then you could have like ah um, you know you could optionally implement a more complex projector if you needed to. But if if all you're doing is projecting to one model.
45:12.34
Daniel Coulbourne
Um, I'm just thinking about.
45:17.53
Daniel Coulbourne
I'm thinking about the the user story for like okay I implemented this I implemented things using this kind of like one file per event mechanism where like the event and the projector are the same file right. And then now I have some additional complexity where I need to make like historically informed decisions before projecting Data. So therefore I need to start extracting a separate projector I'm trying to see if that would like this is what I'm trying to wrap my head around is like. Is there like a easy story to tell about how you transition from like the naive implementation to like the more fully ah fully fleshed out event sourcing implementation.
46:05.79
Chris Morrell
Um, well that I mean that decision that that situation. It's not even necessarily that you need to extract out a new projector. It's that you need an aggregate route at that point right.
46:16.18
Daniel Coulbourne
Right? And that's what I'm saying is like is there a world where I could implement an aggregate route having a history of existing events that I had created in sort of this other implementation and Then. Re theoretically like replay all those events and like have everything be okay, you know I can imagine doing it. Yeah.
46:38.23
Chris Morrell
Um I can imagine I mean and this is yeah this is getting into I mean I I worry that I'm going to listen back to this and be like God No one's going to have any idea what we're talking about here but i' just going to keep on going.
46:49.72
Daniel Coulbourne
Okay.
46:51.78
Cheyne Rood
Ah, just to just a comment I have no idea what you're talking about. But I mean a little bit a little bit.
46:57.47
Chris Morrell
Ah, okay so I mean I think what Daniel's getting at is sometimes you have you need to make decisions about events based on the history of the events that have fired thus far right? and like. Hate to use this example, but it's the one that comes to mind and it's the one that everyone uses like in a ah go for it. Yeah yeah, that's not banking.
47:19.23
Daniel Coulbourne
Wait I Have an example I have an example that's domain that domain specific So like imagine imagine yeah, that's not banking. Um, so imagine you get an inquiry submitted from a user right? And in the past um this user's ah. I Don't know payments have been declined or like when you received the cards you found out they were fake and so you have reason to distrust this user so you probably don't want to immediately project things when you receive like you probably don't want to immediately put them into like a.
47:56.44
Cheyne Rood
Is.
47:56.53
Daniel Coulbourne
Order acceptance flow when the thing comes in you might want to immediately reject them because you think they're fraudulent and so this is an instance where like these events that happened in the past which is like okay maybe when 3 of their if 3 of their inquiries have been rejected then we're going to. Reject all of their inquiries in the future. That's the type of thing where like an event comes in and before we make database projections. We first want to make decisions based on previous events.
48:19.92
Cheyne Rood
Right? and.
48:27.56
Cheyne Rood
So You're saying if you were to implement this in a more simplistic fashion where you are as you described making the projection just based on the snapshot of information which which is not enough to flag something for fraud as you're describing or something like that. Then if you later are like I want this more robust implementation with this kind of projection that's happening based on the the full sequence as you're describing I Guess the question becomes that you're asking is is there like a clean path.
49:02.47
Daniel Coulbourne
To Migrate from the from the sort of more simple implementation to the more full fleshed out.
49:04.25
Cheyne Rood
From one to the other and like how do you resolve that like do you have to? yeah.
49:14.50
Daniel Coulbourne
I think so I think the thing Chris is describing is actually fine. So I think what you could do is basically take those project methods that you had on your events pull them out to a separate file. Um where where they actually become basically event listeners. That listen for an event and then do something um and then you sort of put a ah an aggregate in between those for lack of a better word. The issue is that normally what you would do is you would listen to 1 event and then project another event. So there's normally would be like a first event and a second event. Um, so anyway, that's.
49:56.57
Chris Morrell
Um, I think let me I want to make maybe I'm wrong here. But I think there's a distinction also because in in what you're describing. You're talking about making decisions. Like if we're thinking about the inquiry as the thing that events are happening on right? You're making decisions about that inquiry based on events that happened to other things right.
50:18.16
Daniel Coulbourne
Um.
50:25.89
Daniel Coulbourne
Yes, there would be different. There would be different aggregates here So there would be an account aggregate and an inquiry aggregate and.
50:33.80
Chris Morrell
Right? What? So I think that there's another example, um, where it's all within the same same thing the same aggregate right? and like.
50:46.37
Daniel Coulbourne
Oh.
50:49.94
Chris Morrell
That's that's why I was going to use the banking example, right? like if you have ah an account and it has you know there's a money deposited event of a hundred dollars and then a money withdrawn event of $100 and the user tries to do another withdrawal right? It needs to understand that the current balance of the account is 0 and not allow the money withdrawn event to be fired and. In in the naive approach that I was talking about where the events just project themselves. Um, those events you know, firing a money withdrawn event would have no understanding of the the balance of the account. All it would have is you know the the right and so in that moment you do need to have an aggregate that can hold event data over time.
51:44.93
Daniel Coulbourne
The mechanism to cause the account balance to decrease. Basically.
51:58.18
Cheyne Rood
Is that always true like okay, you're describing this withdrawal withdrawal situation where you need to have the funds available and that depends on the history. But when it comes to like a status. Update you similarly, you need to know that it's a valid status. It. So.
52:16.96
Chris Morrell
Um, yeah I mean you could get away with.
52:17.32
Daniel Coulbourne
So there is like then so that yeah so the naive move would be to basically just like query the account model and be like if account arrow balance is greater than event arrow Withdrawal amount then we're good otherwise.
52:25.17
Cheyne Rood
And.
52:26.43
Chris Morrell
Um, yeah.
52:36.26
Daniel Coulbourne
You know, do something else. Um, the issue there is that you're embedding yourself even further into a non-aggregate implementation which makes your transition to. Your eventual transition to aggregates even more work right.
52:56.28
Chris Morrell
Yeah,, that's what I was getting at too is like in event sourcing you really want your aggregates and projectors to have no understanding of the the underlying data that they're well the projectors do but like. You don't want the logic around your events to understand the eventual models that you're projecting data into because if you keep that separation then if you ever need to change something or rerun your event stream. You. You just reproject the events and you like build up state um without any problem whereas if your event logic relies on the current state of the projected Data. You know you lose the ability to rerun events you lose the ability to add new projectors and project. Old data to new new places like you lose a lot of the um flexibility the power of event sourcing. So I think that the moment that you need to hold aggregated event data um to make event logic.
53:55.77
Daniel Coulbourne
The power. Yeah.
54:12.25
Chris Morrell
Decisions you need an aggregate right? You need to have a place to store that and so like in my sort of imaginary world I could see just having like a interface that you could add to a model that's like get aggregate and if your system.
54:13.13
Daniel Coulbourne
And forth.
54:28.92
Daniel Coulbourne
Um.
54:32.38
Chris Morrell
Encounters a model that implements that interface instead of using the model. It uses the aggregate and that way when you need to start aggregating data. You can, but you still don't need it until you need it. Maybe there's a world where like. Maybe that introduces some bad habits but is okay.
54:52.54
Daniel Coulbourne
So there are some other concepts that exist so like um like Spotsy's package includes this concept like called event queries which are basically like they're like aggregates but less ah less declarative. Um. So they're basically like okay well what if I just wrote a good query that told you what events should be applied to this aggregate and then use those events to build up a state overtime so rather than having an event be assigned to an aggregate when you run it. Right? Or when you dispatch it where you say like I'm dispatching this event onto this aggregate instead you can sort of have like a post facto. Ah well I'm just going to like build an aggregate up from historical events instead. Um, which is useful in cases where you need to like. Do secondary state building with aggregate or with events that were actually assigned to different aggregates. Um, but I don't know so I'm thinking maybe the naive implementation if you want to like avoid aggregates and you want to be able to like.
55:57.46
Chris Morrell
Um, right.
56:06.44
Daniel Coulbourne
Transition to aggregates with old data that wasn't assigned to aggregates when it was created um that maybe there's some sort of like ah query based solution that you could build or whatever.
56:22.49
Chris Morrell
Does that make any sense Shane.
56:24.86
Cheyne Rood
Ah, yeah, that it does um I don't know for any closer to you know me implementing this tomorrow. Um, but okay, here's it.
56:36.60
Daniel Coulbourne
I Would love to like know what the problem you want to solve is.
56:37.40
Chris Morrell
Right.
56:44.10
Cheyne Rood
I mean I think it's a good one and it relates to what you were describing before Chris with the banking example, but we have um, ah a rental program. This is for the online game magic online. Um, we don't have to get too deep into the nitty-gritty here. But. We let our customers um have a rental limit and they can then take out whatever cards they want to play with and we have to keep track of what cards they've taken and deduct that from their balance and then. When they return them. They free up that balance to be able to take out other cards and so keeping tabs on that is um, having discussed it a bit with Chris before and and sort of thought thought about it because I have this opportunity to sort of build all of this from scratch I'm in the process of sort of rebuilding everything. And um, it struck me that event sourcing could be great as a way of knowing what cards are on loan and what ah customers balances at any given time and sort of you know, being able to make use of that that implementation pattern.
57:55.66
Chris Morrell
Well, another important distinction is that card values change you know regularly so having to have an understanding of what was the value of the card when they rented it and what is the value of the card when they're returning it? um.
57:59.30
Daniel Coulbourne
With us.
58:12.48
Chris Morrell
Well needing to understand what was the value of the card when they rented it because that's the that's the amount that has to be returned regardless of what the value is now but also being able to do some sort of secondary analytics on like you know.
58:21.58
Cheyne Rood
Um.
58:26.41
Chris Morrell
How much are card values changing between the time when they're rented and returned.
58:30.94
Cheyne Rood
Totally Yeah, there's a lot of interesting information there as well as like utilization um rates for our customers. You know, ah being able to spot sort of problematic patterns. Um, for people that are sort of abusing this system that we have um. So the story that can be told by having things in this address event driven thing that where you can do. These projections is super interesting for that reason.
58:59.69
Daniel Coulbourne
Yeah, that makes sense. Um, yeah I think that in that case, right? like the big thing that you care I mean it might be useful to have like a card aggregate or something as well. For other reasons but like.
59:11.32
Cheyne Rood
Come on.
59:16.16
Daniel Coulbourne
The big thing that you care about is like a user like lending account aggregate so you want to aggregate information about like a given user's lending account and like what they are rental account or whatever and basically like what is their current. Balance right? which is like they're I guess Their're borrowing potential or something Um, and so like how much are they currently allowed to leverage essentially versus ah and then like all of the events that change that which is like taking things out returning things.
59:37.86
Cheyne Rood
No.
59:55.38
Daniel Coulbourne
You know stuff of that nature and you know I don't exactly know what the attributes that are that you're updating are whether there's like ah just a number which represents their you know their available credit or whatever. Um.
01:00:12.28
Daniel Coulbourne
And that that number like goes up and down or whether it's more complex and it's like it's a difference. It's a combination of like number of cards and value of cards or something.
01:00:17.69
Cheyne Rood
No, no, it's it's I mean it's very simple. It'll just be you take out the cards. We what of it with you know, take a snapshot of their value at that moment and that needs to be deducted. So if your bounce is 500 and you take out a bunch of cards and they're worth in total 400 ah, the in-gain currency then your balanced at that point be 100 and then and then maybe and this is again sort of like a step forward traditional in the old web app which was built you know many years ago um this system came sort of late in the game. We were originally just sort of traditional ecommerce.
01:00:41.76
Daniel Coulbourne
Gotcha.
01:00:56.77
Cheyne Rood
And so when we introduced this rental program. Ah you would place an order for the cards. Let's say it's you know 100 cards or something and um, when you were ready to return. You had to return the order. There was a sort of tight coupling between the cards you had taken and this one sort of.
01:01:10.74
Daniel Coulbourne
Oh.
01:01:16.35
Cheyne Rood
Order resource and so ah, that's another thing that's a part of the system would be great. Is you You can place this order that order you Maybe you friended the same card.
01:01:23.30
Daniel Coulbourne
Yeah, so your 1 order might have 4 cards in it and then you might have a you might only send you might send back 2 of those cards and 2 other cards from a separate order at the same time.
01:01:33.69
Cheyne Rood
And some of those orders might have the same exact card. Um at different values because they're at different points in time and so then you want to return them at some point it's so we just need a way to sort of reconcile all of that.
01:01:49.30
Chris Morrell
Um, yeah I mean this is a really really I think really good case for event sourcing and I'll happily hang out talking about event sourcing for a while I I also could see saying like do we want to get back to statuses. But um.
01:01:49.36
Daniel Coulbourne
That's so interesting.
01:02:07.24
Chris Morrell
I'm I'm good either way I just wanted to at least put that out there.
01:02:12.50
Daniel Coulbourne
Yeah I mean this in this case like a balance. You know it's statuses are more like Ah, how do you say? Statuses are more like balances are continuous right from zero to infinity and everywhere along the way.
01:02:31.78
Daniel Coulbourne
Um, whereas statuses are like there's like 5 of them or whatever and we like rotate through them depending on like what the status is um but I think essentially balances and statuses are the same problem which is that like actions happen and I'm trying to reduce that down to a single piece of data. You know, um.
01:02:48.66
Chris Morrell
Yeah I mean that was like a thing that I am embarrassed to say took me so long to wrap my head around is like when when I'm using eloquent and I call some under the hood. That's. That's calling an aggregate method and like it took me so long to wrap my head around the fact that in event sourcing this term aggregate root is the same as a sum or an average or.
01:03:08.65
Daniel Coulbourne
Who.
01:03:22.95
Chris Morrell
Um, um, a median like an aggregate function in in a database or in ah in a you know or in anything that they're all the same. The aggregate route is just aggregating all the things into 1 thing right.
01:03:35.70
Daniel Coulbourne
Yeah, it's just applying one applying a function on top of another function on top of another function on top of another function until the state is up to-date.
01:03:43.92
Chris Morrell
Right? right? and and status columns are the same. You're aggregating a bunch of events into one single status the current status. Yeah.
01:03:49.84
Daniel Coulbourne
A bunch of timestamps. Yeah, right.
01:04:00.28
Daniel Coulbourne
Yep I agree. Um, and I think that I mean yeah I don't know that we are I don't know that we're going to come up with any kind of like solution here except that like I think the solution is like you know. Get more comfortable with verbs you know and I do think there are in-between things that people can do before like installing a package about it. You know I think that they should maybe experiment with like well why don't you create a table in your database that is a verb you know, just like any verb. Um. But create a table that doesn't describe a noun that describes a verb instead. Um and then see what the logic that you have to write in order to incorporate those verbs are right? So I think like.
01:04:54.52
Daniel Coulbourne
You know an example is like you know like a cancellations table or something right? like that right like it's when we we you know Noun ourselves a verb um you know, but I think that like creating a table that ah is made up of like times when people did a certain action. Um, and then like writing the logic that way rather than ah rather than like keeping the actions imaginary and writing the effects in in the database I think that is like a really good like training wheels for this mental model of like. Just deal with verbs more um and deal with nouns less and see how it feels and see the types of queries you write. You know that would say I would say that would be my like baby steps.
01:05:48.13
Chris Morrell
Um I like I do really like that insight that this problem that we're kind of touching on or so and specifically the problem of statuses is is really trying to shoehorn a noun into. A place where you're dealing with verbs a status is is describing Basically the most recent thing that happened and like trying to unwind that a little bit makes a lot of sense.
01:06:06.71
Daniel Coulbourne
Um, yeah, actions. Yeah.
01:06:24.40
Daniel Coulbourne
Um, yeah I'm.
01:06:28.24
Chris Morrell
I'm still not opposed to the idea of like if you have a status column just make each status or each way that something can get into a status an event. That gets stored in a table and then just have that event have like a handle method or whatever that just applies that event to the model itself.
01:06:57.54
Daniel Coulbourne
Um, and like even even if you want to right? if you want to like not if you want to like be I'm not going to like I insist I won't event source this whole app right? So like I'm going to draw a hard wall I think even making a table called like inquiry events. And so it's a dedicated table. That's only full of things that happen to an inquiry and maybe it has a type column or it's like you know a magic string that describes the type of event that happened and then it has a bunch of other columns for metadata.
01:07:17.00
Chris Morrell
Um, sure.
01:07:35.49
Daniel Coulbourne
Right? Or it has like a Json column that can accept some magic payload of metadata like I think even just like building that column and like sort of do it yourself like when something happens store an event in that column and then like create like an accessor on your. Inquiry model that just like runs a query of like all of the events that happened to this thing that then like aggregates them in real time and generates your status or something you know I think that.
01:08:07.50
Chris Morrell
Um, well you could even add a like on created listener to that table I mean to that model. Yeah, that applies the event to because I think in the end I mean the thing that I am very adamant about.
01:08:11.95
Daniel Coulbourne
Yeah, you could make like an observer or some shit.
01:08:23.91
Chris Morrell
Is a solution where you don't have a status column on the inquiries table is going to be bad to use like in day to day work because I need to query inquiries. Yeah.
01:08:27.88
Daniel Coulbourne
Easy. Right? because you want to write a query of like all of the ones in this current status right? for like a triage view or something.
01:08:39.85
Chris Morrell
Yeah, and I don't want to do some sort of subquery where I'm querying on the events table and finding the latest event and yeah.
01:08:46.85
Daniel Coulbourne
Of course yeah you want to project that that data you just also want to be able to delete the entire column of statuses and recalculate it at any given time.
01:08:58.15
Chris Morrell
Um, yeah.
01:08:58.28
Cheyne Rood
Yeah I do think that the metadata is a huge piece and with this very simple implementation. You really get like the timestamp and then to your point Daniel you have to like awkwardly define very specific database fields. Um. And so yeah, like maybe a separate table. You could call it inquiry events or it could be inquiry statuses. It could be even more specific and it's just like okay here's the status update and here's the metadata if any um and the timestamp. Um, yeah.
01:09:21.51
Daniel Coulbourne
Yeah, yeah.
01:09:29.48
Daniel Coulbourne
I would go status transitions. Maybe.
01:09:29.82
Chris Morrell
Um I wouldn't go statuses because sure because like you want the whole point is you want to capture not the status. But the thing that made the status change because you may like.
01:09:33.97
Cheyne Rood
Um.
01:09:36.87
Cheyne Rood
Right? right? d.
01:09:42.30
Daniel Coulbourne
Yeah.
01:09:45.63
Chris Morrell
Inquiries isn't as good an example but in in the system that we have in place where we're We're um, assigning assigning work to inspectors and by and assigning jobs to inspectors. Um, you know those go through a ah, pretty typical. You know created. Offered assigned scheduled completed kind of um, set of statuses. But if a job needs to be assigned to a different inspector right? Um, it would be great. To have a reis reassigned event that not only changes the status but also nulls out some other columns Knolls out. Maybe some of the times stampmps that we're storing because we need to query on those timestamps but like. Something can transition from scheduled to assigned where really it was rolled all the way back to new and then reassigned all in the same moment and so being able to represent that.
01:10:52.44
Cheyne Rood
Yeah.
01:10:57.73
Chris Morrell
Whole suite of changes as a single event would be way way nicer to work with.
01:11:05.45
Cheyne Rood
That's a really good point I mean that kind of reversion is a standard thing that I typically have as part of this implementation like people make mistakes they click the button but like on the admin side most often to advance something and then they say oh I want to undo that and so they revert or in your. What you're describing Chris where you need to sort of reset and you know there's obviously very simple ways to handle that but oftentimes that means unless you're doing like auditing and stuff like you're kind of losing a bunch of data. You're like wiping out a bunch of timestamps and so what you're describing. Could be nice as a way to capture that moment.
01:11:42.78
Daniel Coulbourne
Um, yeah, um.
01:11:44.79
Chris Morrell
Right? Maybe they accepted an offer and then like you realized oh this card that we thought was worth forty. Cents is actually worth $200 like you have to reissue a new offer to them because you made a mistake and like you want to. Yeah, you want to have knowledge of that that fact somewhere in your system.
01:12:11.94
Daniel Coulbourne
There's um, this is just sort of unrelated to what you were just saying but something and I've been thinking about recently is that like git is an event source system right? So like.
01:12:21.60
Chris Morrell
Right.
01:12:23.84
Daniel Coulbourne
If you like use git and like do commits and ah bases and merges and you know revert commits and you know do all of this stuff like what you're doing is basically deriving the state of your codebase from the aggregate of all of the events that have happened over time right. And ah, you can delete your dot gett folder and the codebase is still in the same state it was before um and so there's something cool about the fact that ah.
01:13:03.27
Daniel Coulbourne
You know every like every day we kind of interact with something that's like fully event sourced and like we don't think about it as such all the time. Um, and I do think that like git has a lot of lessons to teach us about event sourcing right? and so like if you just look at. Like git one of the biggest things that git does is tell you whether a certain chain of events is compatible with another chain of events and like whether you can like combine those 2 chains of events or not or if there are conflicts between them and like you would need to resolve those conflicts in order to merge them and so like. Those are the sorts of things I'm starting to think about now we're talking about building some some games that are more like real-timey um, meaning that like we might be building up event queues like each player might be building up their own event queues that sort of get pushed up to the server. In batches every once in a while and so there's some stuff to like make sure that the the batch of events that you get from player one is compatible with the batch of events that you get from player 2 before you sort of zip them up and apply them. Um, and I think like git implementation of that is like really strong. And so thinking about like event sourcing as like deriving the state of your application from git and like people doing commits instead of doing events is like a really interesting thought right? and so when you talked about this right? The reason I thought of it is when you were talking about like people.
01:14:34.96
Daniel Coulbourne
Making a mistake on the admin side and the needing to like revert those changes like earlier yesterday I actually merged a Pr in a client's repo right? that like was not ready to merge and so I had to like quickly revert it well like github gives you a button that it just says revert. And it just opens another branch and like opens like a pr creation dialogue to just like press 2 buttons and have another poll request up that undoes all of the changes that you just did. But it's kind of this like forward. Only. Like in the in the same way that like people don't use like down methods on their migrations or whatever. It's kind of this like forward only except for cress. Um, it's this forward. Only thing where it's like if you want to undo something you just do more stuff to undo it right? And anyway.
01:15:14.42
Chris Morrell
Except for me.
01:15:26.81
Daniel Coulbourne
These are all the thoughts that I'm just like swimming in all the time is just I feel like I'm like ah seeing the seeing the universe all the time or just like oh my God there's events. Everything's events.
01:15:39.47
Chris Morrell
Um, well yeah, there's like the whole what the heck is I always forget this acronym CRCQRS yeah um conflict. Ah.
01:15:44.52
Daniel Coulbourne
Cqrs What which stands for hold on it's Command Query Responsibility Segregation Cqr S is an architectural pattern for separating reading data a query from writing data a command.
01:15:54.95
Chris Morrell
Yeah, yeah, there you go.
01:16:02.28
Daniel Coulbourne
Cqrrs Divide ah derives from command and query separation commands mutate state and are approximately equivalent to method invocation on aggregate roots or entities queries read state but do not mutate it. So yeah.
01:16:15.84
Chris Morrell
Um, wait but isn't there. There's like ah there's there's another similar acronym that that describes um like the the type of event that's like ah, an ah, an event that's built. To be um, never mind I'm not.. It's not going to come to me. But yeah, that's ah, that's a whole that's a whole other piece is like if you get. Too far down this rabbit hole. Then you start thinking? Yeah, you have to start thinking about um you know conflict resolution and asynchronous event ah concerns and you know like if you if you ever tried to implement offline mode in an app or something like that you need to.
01:16:54.64
Daniel Coulbourne
Listen. Yeah, right? So this is actually so I was just talking to John I was just talking to John my thunk partner about this and.
01:17:06.91
Chris Morrell
Resolve all the actions that were taken into separate clients like yeah, it's it gets wild.
01:17:18.56
Daniel Coulbourne
He's also like the game design guy and he has this card game that he built that we're probably going to build like a react native implementation of it and we're like we need to build like a react native like a react event sourcing framework really because like what we're doing is like. It's all events right? A player does an event and does another event and whatever. Um, and I was telling him about like so in hearthstone when you like if you switch applications in the middle of a turn and then come back. It plays all of the events back to you at like 3 x speed to like catch you up to the current moment and I was like oh well that like shows me the technical implementation that they actually do have a queue of events going on because if they didn't they wouldn't be able to do that so they have a queue of events that happen.
01:17:53.49
Chris Morrell
Right.
01:18:08.00
Daniel Coulbourne
And they're just like playing them one after the other in order to like make things happen. So anyway, it's just stuff like this where I'm like I'm everywhere I look I'm like events I see it I see it. There's events there these things that look like static states are actually derived from events.
01:18:18.30
Chris Morrell
Um, well, especially and yeah, especially games like hearthtun where or or magic I mean is a perfect example of like you've got all these very complex rules about like phases and priority and like. You know when when 2 different things that sort of kind of happen at the same time happen like which one applies first yeah like um, in game design I imagine that this comes up all the time.
01:18:42.90
Daniel Coulbourne
It does matter which one happens first. Yeah.
01:18:51.30
Daniel Coulbourne
It does.
01:18:55.93
Chris Morrell
Yeah, Well I I I Really like this idea of um, even if it's not a package even if it's just like a you know a custom sort of bespoke implementation. This idea of just having. Ah, table of events that happened to your thing that needs needs statuses right? and.
01:19:17.52
Daniel Coulbourne
A specific model. Yeah, because then if you do decide to go full event sourcing. It's pretty easy to like write a job that would turn that table into event events right? So like as Chris and I have experienced saying like.
01:19:30.37
Chris Morrell
Right? right? Yeah, yeah, you could backfill events easily.
01:19:36.44
Daniel Coulbourne
Let's event source something that we have a ton of like 10 years of historical data for that wasn't event source you know so like if we could do that you could definitely turn that table into events right.
01:19:42.38
Chris Morrell
Um, yeah.
01:19:47.40
Chris Morrell
Um, right? something that's already basically event sourced and then yeah like each one of those models each one of those events you you know you could do something pretty simple like just have a ah. Ah, callback like a static callback inside of the saved or created um event listener and in that static callback. It just like runs a switch statement on what is the type of event right? You like have an enum or something like that. Trying to just keep it as simple as possible. So You have an enum or you just have some constants on the model itself I don't care. Um, Ideally, you'd have an E num.
01:20:28.18
Daniel Coulbourne
Yeah, so my thing I think I think this is actually like the way to go. So I think like if you're like on the fence about event sourcing build your own implementation based on like some of the concepts of event sourcing but like.
01:20:45.46
Chris Morrell
Um, yeah.
01:20:46.39
Daniel Coulbourne
Fuck all of the specific words like aggregate roots and projectors and reactors and like all of that and don't use a package because then you're going to have to learn all those words in order to do anything like just start building the implementation using verbs and like you will get to a point where you're like oh man it would be really cool if I could like. Aggregate all of these events to derive a specific state and be like okay, cool. You have now happened upon the concept of an aggregate route right? Like you've happened upon the need for which this thing was was created and then at that point you either build your own event sourcing package which is what we're doing. Um, or you just don't and just like keep it in house or you go pull in event sauce or spotsy's event package or ours whenever with the fuck we get it out. You know, but ah, you know, eventually maybe you want to like fall into some sort of a framework. Um, but I think. At first like just build some actions you know and like see how it feels to play with them. You know.
01:21:52.10
Chris Morrell
Um I I accept that that's a great suggestion for Shane it doesn't satisfy my ah my desire to um, just say oh I have a solution for this whenever I need a status column here on out.
01:21:58.18
Daniel Coulbourne
Um I think it's for everyone.
01:22:09.92
Chris Morrell
To pull in this package that I wrote that just solves it for me but I can live with that for now I suppose I'll I'll probably end up hacking on something after this because I do think that there's a world.
01:22:11.69
Daniel Coulbourne
Sure Yes I think so.
01:22:25.54
Daniel Coulbourne
I Do like I mean I I am going to take this self-projecting events concept and pull it into our package I think because like I think as like ah because I'm always thinking about things in terms of the like the learning process. You know.
01:22:42.50
Chris Morrell
Yeah.
01:22:42.28
Daniel Coulbourne
And like the onboarding process for a new user and I think for a non eventee person like the onboarding process 2 events if you just say like hey here's an event and here's how it mutates the database. It's all in 1 file like go to town like I think.
01:23:00.18
Chris Morrell
Um, yeah.
01:23:02.70
Daniel Coulbourne
That is a cool onboarding process I do want to do some work on like what is the upgrade path to aggregates you know? Um, but I think that like I do think that any non aggregate event. There's nothing.
01:23:13.90
Chris Morrell
Um, yeah.
01:23:21.82
Daniel Coulbourne
Preventing it from being a single file.
01:23:22.72
Chris Morrell
Yeah, and and I think that there's pretty easily I think that there is a world where you can just inject and aggregate into that scenario as well. If you need it I don't think I think. That you could I think that you could never write a projector I bet you you could get away with only having self-projecting events for a while and then introducing aggregates second. And introducing a projector third I don't think that you need to extract out to projector I think you could just.
01:24:01.29
Daniel Coulbourne
Um I agree I think that projectors being like the first like projectors being the first concept you learn about in event sourcing is like really ass backwards.
01:24:12.39
Chris Morrell
Yeah, and like maybe maybe the um maybe you force that separation by letting the events from the execution perspective I can just pass in my inquiry model into the event. But the package under the hood basically says like hey if this event doesn't have an aggregate just call to array I mean if this model doesn't have an aggregate just call to array and pass that array in and that way like from your. Projection Perspective. You're not dealing with the event itself and you're not dealing with the model Itself. You're just dealing with data and that way from the very beginning like you could even make it so that your system did like array accept model get key. So that the thing that goes into the event itself doesn't have the id of the model. So like your code is forced to not think about the database at that moment. I.
01:25:15.82
Daniel Coulbourne
Um, I think what you're describing as a transducer.
01:25:23.29
Chris Morrell
Ah I'm glad that we got there because it is. It's all transducers in the end. It's it's transducers over time Shane just face shame just made. Ah, ah.
01:25:30.41
Daniel Coulbourne
Um, in the end, it's all transducers all the way down who.
01:25:42.98
Daniel Coulbourne
Um, well in my current side project I am writing a rust Audio Editor. Um, and so the idea of like processing like an evergrowing stream of bits. Over time and doing complex branching things with them has caused me to wonder whether I actually just want transducers so we'll see.
01:26:02.74
Chris Morrell
Yeah, you might need them in rust and it could be great. Well I feel like this is a good I feel like this is a good place to stop I This has been fun. Yeah, this is one I I've been thinking about this for so long I'm.
01:26:12.68
Daniel Coulbourne
Yep, Spin a flash.
01:26:21.32
Chris Morrell
I'm not I'm not sure if tomorrow I'm going to wake up and be like all right? We need to get on and have a whole other discussion or or where it's going to land. But.
01:26:27.21
Daniel Coulbourne
I am always down to spend 90 minutes talking about my psychotic fever dreams of events.
01:26:32.68
Cheyne Rood
Well, this has been great. Yeah I'm gonna I'm gonna be using some of this for shirt.
01:26:37.31
Daniel Coulbourne
Um, Shane I put a link in the chat that you should look at it's ah it's an event flow that we just did for a client ah for their orders system. Um, and it's kind of similar to your system. So maybe take a look.
01:26:38.86
Chris Morrell
Um, yeah I can't wait to see what happens with it.
01:26:51.58
Cheyne Rood
Um, oh excellent I Love it. Thank you.
01:26:55.60
Daniel Coulbourne
See if there's anything the glean.
01:26:58.48
Chris Morrell
Um, and I'll just be putting your proprietary stuff in the show notes. Don't worry now.
01:26:59.94
Daniel Coulbourne
Do that. Don't do that.
01:27:04.56
Chris Morrell
Ah I will all right? Ah, we good anything else all right here we go.
01:27:07.57
Daniel Coulbourne
We could.
01:27:18.45
Daniel Coulbourne
I I am I a proud for my brown profound.
01:27:26.71
Chris Morrell
I Just triggered the altro event.
01:27:28.33
Daniel Coulbourne
Hell yeah yeah.