Become a Creator today!Start creating today - Share your story with the world!
Start for free
00:00:00
00:00:01
Ep. 5: What about event sourcing? image

Ep. 5: What about event sourcing?

S1 E5 · Over Engineered
Avatar
374 Plays1 year ago

In this episode we indulge in the purest form of Over Engineering—a 90 minute discussion of a completely different application paradigm/architecture. Our team has used event sourcing to some degree, and we're considering using it more heavily in the future. But before we do, we're going to step back and ask ourselves if it's worth it…

Some useful links:

Transcript

Introduction to Overengineered Podcast

00:00:07
Speaker
All right, welcome back to another episode of Overengineered, the podcast where we ask the very important question, what's the absolute best way to do things that don't particularly matter?

What is Event Sourcing and Its Relevance?

00:00:18
Speaker
Today, I am back with my friends Skylar and Bogdan, and we're here to talk about event sourcing.
00:00:25
Speaker
Hello, this is the most exciting thing I've been thinking about the whole week. It is an interesting topic and I'm looking forward to speaking about it for sure, especially after hearing the conversation you've had with Daniel at the last podcast. I think it raised some eyebrows. It's kind of an interesting conversation to have.
00:00:47
Speaker
For sure. Yeah, I mean, it's definitely, it's back in the air between us talking about it and him talking about it on no plans to merge and just, I don't know, it coming up a couple of times for us.

Understanding Event Sourcing vs. Object-Oriented Programming

00:01:00
Speaker
I am excited. And so I was saying before we started, I think just to set the stage, let's like have a quick conversation about what exactly event sourcing is and how event sourcing
00:01:14
Speaker
works in the like PHP Laravel world or how we've used event sourcing and then we'll go from there. So I'll just sort of start and YouTube pepper me with questions when I miss something or get something wrong and we'll go from there. Sounds good.

Programming Actions as Verbs: A New Analogy

00:01:37
Speaker
So event sourcing is basically this premise that instead of just updating models in your database, you store the events that happen in your application and trigger and use those events to change the state of your application.
00:02:01
Speaker
the way that Daniel described it in the last podcast is really a nice analogy like we as object-oriented programmers deal with nouns for the most part and event sourcing is effectively thinking in verbs and there are lots of times when we're dealing with verbs and we're trying to model them as nouns. I think that's like such a great way to talk about it.

Historical Data and Limitations in Traditional Systems

00:02:26
Speaker
And so in an event-sourced application instead of just
00:02:30
Speaker
changing a user record, right, you might store a user updated profile event and then have that event what store all the changed data on that event.
00:02:44
Speaker
and then use that data to update your user records. And it's usually talked about in the context of stuff like banking or financial systems, anything where you
00:03:00
Speaker
kind of already have this concept of a ledger. It's really easy to draw the analogy. But I think that in a lot of places, we deal with stuff that happens that has an effect. And
00:03:18
Speaker
we lose a lot of the context of the stuff that happens.

Applying Event Sourcing in Laravel: Trade-offs and Examples

00:03:21
Speaker
And we try to make up for it with audit logs or other packages that kind of are tracking history or using things like status columns, see the previous episode. And when we get into those places where we're trying to fake having this historical data,
00:03:40
Speaker
That's a good pointer for maybe we need event sourcing or maybe we want to consider event sourcing.
00:03:50
Speaker
And I want to get into the language around it in a minute, but this conversation kind of came up because we've used event sourcing for a couple of things inside of our app, Sident and Edgy. And it's been really useful. And I think talking about it, again, got me personally fired up thinking, oh, there are a couple other places that it really would be a good fit.
00:04:14
Speaker
But like I was saying on the previous podcast, I do think that
00:04:22
Speaker
It comes with some, you know, it comes with some trade-offs, certainly in a Laravel app that usually works one very specific way or like follows the typical Laravel conventions if all of a sudden you're doing everything with events. And so I was, I'm kind of thinking of this both as an opportunity to just talk about event sourcing and think about when it's useful and also just sort of to
00:04:52
Speaker
have our little debate about whether we want to embrace event sourcing a little bit more within our apps.

Event Sourcing Vocabulary Explained

00:04:59
Speaker
So that's kind of the backstory and the basic premise. And then I think I do want to get into sort of some of these terms so that we're all sort of on the same page. But is there anything that I missed before we get to the actual vocabulary?
00:05:19
Speaker
I don't think so. I think that's a good overview.
00:05:25
Speaker
Yeah, I am looking forward to hear all the vocabulary definitions. I feel like we need to have a disclaimer for the audience. At least for me, I am not an event source expert. And I would love to learn some of these, you know, definitions of the verbs and the things that we're going to talk about. So I'm looking forward as much as you are to hearing all about this. So with that, Chris.
00:05:49
Speaker
All right, so I'm going to try to keep this as brief as possible while covering the bases. So the core thing is events. We've got events. And we have some sort of dispatcher that fires events. And we have been using the Spotsy package, the Spotsy event sourcing package. There's also event sauce, which is a very popular PHP event sourcing package.
00:06:19
Speaker
But for the listener at home, just the regular Laravel event dispatcher can do a lot of this stuff and there's nothing stopping you from implementing something that uses the concepts of event sourcing without using a formal event sourcing package.
00:06:40
Speaker
So we've got events that we dispatch. An important thing about those events is they need to be stored somewhere, right? So we're storing them in a MySQL database. I think for a lot of Laravel developers, that's perfectly fine. I just checked and we're at about 12 million events in our events table, and it is perfectly performant. There's no issues with querying that data.
00:07:08
Speaker
Kind of because of the axis patterns that you have around events, as long as you're indexing them properly, you're never going to have to do these complex queries on that table. So it's really just pulling them out of the database in an ordered manner. So relational databases are really good at doing that.
00:07:32
Speaker
So you've got your events, and then on the other side of it, you've got your projectors and reactors they're typically called, but really just think of them as listeners, right? So when I fire a user updated profile event,
00:07:50
Speaker
a listener can listen to that user updated profile event and actually find that user's record in the database and change that user's table to reflect the changes that they made. This is not the best example, but it's fine. And the main difference between just using the regular Laravel event dispatcher and regular event listeners is we
00:08:21
Speaker
need to store those events to the database and then potentially play those events or handle those events in a queue or even replay them later, or there's a little bit more of a separation. It's not just all happening in memory, like a typical Laravel event lifecycle.
00:08:42
Speaker
And then the hardest piece in here to really wrap your head around is aggregates and aggregate roots. And they're kind of in the middle of it all. And so the aggregate or aggregate root is really just that, an aggregation of all the event data that has happened thus far.
00:09:07
Speaker
at the point of time that we are in. Either if you're replaying events, it might be a point in time in the past, or if the event just fired, it might be the current point in time.

Exam System Case Study: Event Sourcing in Action

00:09:22
Speaker
But the aggregate root is really a place to hold all of the state of your application as it relates to the event system such that you can dispatch future events and guard against invalid future events, right?
00:09:42
Speaker
For example, we have an exam system that uses event sourcing under the hood. And someone shouldn't be able to answer a question if the exam has ended, right? So when you try to fire a user-answered question event,
00:10:05
Speaker
There needs to be some sort of state that understands like, is the exam still active? So the aggregate root is the place to hold all that state for the current point in time and keep it kind of separate from the application state because this needs to work regardless of where your application happens to be, right?
00:10:29
Speaker
Because one of the values of event sourcing may be overstated value, but value nonetheless is the opportunity to replay events. So you don't want to ever get yourself in a position where your event sourcing system relies on the current state of your application.
00:10:50
Speaker
So in this exam example, which I think maybe is a good example to give, you might have a user started exam or a started exam event that has the exam and some metadata about it and timestamp of when they started and what user started the exam. And then you might have an answered question event, you might have a skipped question event, a couple of things like that.
00:11:17
Speaker
And our aggregate root, when we fire a exam started event, the aggregate root would then store, okay, who's the user that's taking this exam session? When does the session end based on the time limit for the exam? And when an exam question answered event is, when we try to fire an exam question answered event,
00:11:45
Speaker
the aggregate root can look at that time limit and say, hey, is the time that the person tried to answer this question after the exam ended? Well, then we're gonna trigger an exception instead of letting them fire that event and maybe even fire a separate event that was like user tried to answer question after exam ended. You can do all sorts of stuff like that.
00:12:12
Speaker
So the aggregate root is gonna be the tricky one to kind of, to get a sense of, but that's the basic premise. It's just like the place to hold the current state of your event system separate from your application. And I was thinking about this a little bit and almost feels like for anyone who's used to writing React or any sort of like,
00:12:44
Speaker
functional UI, it's almost like the aggregate root, the data on the aggregate root is your context and your projectors are use effect hooks. I don't know if that's useful to anyone, but I'm trying to draw that parallel. It's not perfect.
00:13:06
Speaker
It's just like another way to think about it. One thing that helped me understand aggregate roots a little bit better was that aggregate roots you can think of like they're just in memory.
00:13:21
Speaker
When you persist an aggregate route, what's actually happening is all of the events are being saved to the database or the event store. But your aggregate route is just in memory, and it gets built up every single time you ask for a specific aggregate route. It gets rebuilt based off of the events that have happened already and been saved.
00:13:48
Speaker
And so, I don't know, it was hard for me to try to think about like, oh, you have this, you have this exam aggregate route, but then you also have an exam, traditional, like, Laravel model. It's like, well, how are those connected? And they're not really connected. A projector might save something off to a regular Laravel model, but your aggregate route is just in memory.
00:14:14
Speaker
It has state of where things are right now, but I don't know, that helped me a little bit. Yeah, I think that's a really, that's a good distinction. And it's also worth, I think another useful thing to think about is when your system is built using event sourcing,
00:14:38
Speaker
your events and aggregate root can hold the state of what happened. And your database models can then be the data that you need to present your application. And so it gives you this flexibility to kind of store everything you could ever possibly want in your events.
00:15:00
Speaker
and aggregate that data in your root to the degree that you need it, but then project that data in the format that is actually useful for how you're going to present it in your UI.

Optimizing Performance with Snapshots

00:15:15
Speaker
It leads to some interesting considerations around normalization because you don't need to build your database models in a way that they
00:15:29
Speaker
can theoretically hold all the data that you ever might need to collect. Instead, you can build your database models
00:15:38
Speaker
specifically the way you need to query them for your application. And so in the exam, you know, we're storing a bunch of sort of security, you know, IP address, browser fingerprinting, like that sort of stuff that we may need, but the actual exam session table doesn't need to have the IP address of the user in it.
00:16:03
Speaker
And if we ever need to audit it, we can just project those events into a new table for auditing purposes. And it's, yeah, it's like that flexibility. And then the other thing that what you said, Skyler made me think of is,
00:16:23
Speaker
Yes, it is in memory, but that doesn't mean you can't optimize. So for example, the Spotsy package lets you snapshot an aggregate route. So at any moment, you can build up your aggregate route from all the events that have happened in your system.
00:16:40
Speaker
And then save a snapshot. And then next time you retrieve that aggregate route, instead of having to replay, say, the 50 events that got you to that moment in time, you just fetch the snapshot and then replay any events that have fired since that snapshot was stored. And so there are ways to optimize that so that you're not, like, constantly recomputing the state of anything.
00:17:03
Speaker
back from the beginning of time. Although in reality, recomputing that state is not very expensive and there are plenty of times when it's just fine to do that.

Transitioning to Event-Sourced Systems

00:17:14
Speaker
I will say, I mean, this conversation is great, but I love to take a step back, as I always do, and talk about how we approach things in a traditional Laravel application. For example, perhaps we can talk about just a general user flow using the eloquent ORM and how we could maybe build up on the idea of event sourcing.
00:17:35
Speaker
For me at least it took me a little bit of understanding what is the benefit of event sourcing. I know that there's a lot of things that we're talking about like snapshots, aggregates, and events and everything. Honestly, it's a bit even overwhelming hearing you guys talk about it.
00:17:53
Speaker
I was thinking like, perhaps we can set up an example of, you have a controller, a user controller that has a store method. And in that method, you would traditionally say user colon colon create, and you would create a user. And maybe from here we can transition into this event sourcing.
00:18:16
Speaker
You know, let's actually, we talked about this briefly on the last podcast. Let's actually use this job assignment system. Oh, sure. Because I think that's going to be a better, you know, there are cases that are not great example, like you wouldn't necessarily want to use event sourcing for. So let's use one where we might actually have a case to use it.
00:18:37
Speaker
And so I think that might be a better example. Imagine just a tool where opportunities for work come in, and then those jobs can be assigned to different people, and then those people can sort of transition those jobs through. It's assigned to them, and then maybe they scheduled it, and then they've completed it, and then maybe it's been reviewed and paid or something like that, you know, like where it goes through a bunch of different stages.
00:19:07
Speaker
Does that seem like a reasonable example? Yeah. So, I mean, in this example, right, you know, traditionally we would have like a job controller or an opportunity controller where, you know, we create some sort of job, right? There's the store method and we write directly into the jobs table.
00:19:25
Speaker
with some information about the job itself. And then we subsequently could have an update method on our jobs controller that could change the status. And I also feel like one of the things that we may not realize, but I feel like we kind of use event sourcing if you use audits.
00:19:48
Speaker
or non-event sourcing, but just kind of like history tracking of a given column using audit logs. And I feel like that's something that we've been doing inadvertently almost. It's kind of like trying to recreate the status of a model based on audit logs. And I think like for me, one of the things that
00:20:11
Speaker
kind of made some of the event sourcing click is, well, instead of trying to recreate history from a given model's audit table, you could create a model from the events. And I feel like it's like a little bit of a paradigm shift of how we actually deal with data. I don't know. Maybe you guys have some experience on how that works, or comments.
00:20:40
Speaker
No, I think that's absolutely right. I think that audit logs are useful. And there are lots of cases where audit logs are the right tool. But certainly the moment that you start reaching for audit logs to try to get back to, well, where was this at some point in the past, that is certainly a hint that maybe event sourcing would be a good tool here.
00:21:08
Speaker
Well, and so in this, in this jobs example, like we ran into an issue where when we changed the person who was assigned a job, we kind of like erase everything about the job and put it back into the like newly assigned category. But a situation happened where like a person was assigning it to an employee of their own company. It's like someone had done part of the job and then they were changing the assignment to another person to finish it. But.
00:21:37
Speaker
we basically like removed all their data and we went back to like our audit log and then like manually changed this information. But like, because we only had this one table, it created this like weird problem where we're like, Oh, well like that's not really a thing that we really thought about, like changing it to someone who was picking up the work where it left off rather than just starting it over.

Managing Complex State Transitions

00:22:06
Speaker
Right. Right. And that's like, that's a, I think that's such a good example of where just like the status column starts to fall apart because it's like, something can transition from assigned to assigned.
00:22:22
Speaker
but actually be in a totally new state and have a totally new status, right? And even the naive way of approaching this where you just say like, what was the old status? What's the new status? Is there any sort of cleanup that we have to do to take it to that new state? Where with this job assignment stuff, what we would have done was just
00:22:52
Speaker
clear out the assigned user, change the state to unassigned, and then immediately assign it to a new user.
00:23:05
Speaker
it, it got to that new assigned state in a totally different way than if it had just been new and then assigned for the first time. And you lose all that context when you just update the model directly. So in, in the example that Biden was giving, right? Yeah, there's a jobs controller, there's an update method on it.
00:23:29
Speaker
The admin goes and picks a new status from a drop down and does a put request to the update method. And maybe there's a little bit of logic in there that looks at the old status and the new status and does a little adjustment based on what the transition was.
00:23:48
Speaker
Maybe you're even using a package. You could use a state machine library that handles transitions. But in the end, it's always just kind of now updating the new state. And this is a perfect example because
00:24:08
Speaker
Uh, for, for business reasons, we need to know when was it assigned and when was it scheduled and when was it completed? And we have some SLA requirements around the, you know, what's the time between assigned and completed, or what's the time between scheduled and assigned. Um.
00:24:28
Speaker
And so not only are we storing the status column, but we're storing the these different status timestamps because they mean something to the application. And I mean, I don't want to just rehash the conversation that we had last episode, but
00:24:46
Speaker
you know, you just see it starts to fall apart with this traditional just model controller approach when the actual flow of the application is through states, you know, or through, you know, where the transition between different states matters a lot.
00:25:11
Speaker
Yeah, I think like one of the, you know, another point I believe that like is a benefit with event sourcing or just kind of like this paradigm of like, you know, firing some sort of events and, you know, you know, just
00:25:26
Speaker
Reacting to those events as you know even a basic example of you know yes you want to update the status of a job but there may be say a Web hook or something that gets pushed from a third party that also updates a job well now you could just trigger that same exact event that could handle
00:25:45
Speaker
a little bit of validation and business logic within that event almost to push it forward. I think that's one benefit that I feel is a little bit challenging in the basic controller writing directly to the database because you could potentially have two places of where the logic lives.
00:26:08
Speaker
Or you may have to create some sort of repository that holds some of this common functionality that you have to reuse. And I feel like by having an event that gets triggered, that then validates that this action is almost
00:26:27
Speaker
Allowed right like is the status change from you know new job to schedule job allowed you know for a job that you know say is deleted you know and So I think there's a lot of interesting ways to like encapsulate complex business logics and different events and I think that's like one additional benefit that you know is not clear or not visible in the surface and

Comprehensive Job System Example

00:26:56
Speaker
Yeah. Yeah. I mean, and that's, and that's where the aggregate route comes into play. Like the aggregate route becomes this sort of single entry point for all that stuff. Right. So to just kind of continue our example, um, in an event sourced world,
00:27:16
Speaker
there would certainly be a model called job or opportunity, right? But there's also going to be an aggregate root for the opportunity as well, right? And that object, the job aggregate, let's call it, right, will have a method, you know, maybe a static method called like
00:27:44
Speaker
new job, right? And it accepts all of the data that comes in from whatever source and whether that's from the administrative panel or coming from like a third party web hook or whatever, that fires
00:28:01
Speaker
the event that represents a new opportunity arrived in the system. Typically, that would be tied to something like a UUID so that
00:28:18
Speaker
it's still not, you're not worried about the specific database identity of that. You're just saying like, this is a new opportunity that came in. And then your system would just
00:28:36
Speaker
call that method, that method might have some validation of the incoming data, and then trigger the event, and separate from that, you would have a projector that takes this on, just listens for the new opportunity event, or it should be an event, so like a new opportunity arrived or something like that, I don't know.
00:29:05
Speaker
or job offered, maybe. And that listener, that projector, would essentially do job colon colon create, calling a regular eloquent model. And it would store that UID as well as any other data that you want to be on your job model for your application.
00:29:36
Speaker
Later, that job gets assigned, right? And so your aggregate route, you'd retrieve your aggregate route, the job aggregate by that UUID, and you would call assign on the aggregate route. Under the hood, the application is going to fetch all of the events
00:30:00
Speaker
that were fired on that UUID, which in this case is only going to be one, just the job was created event. And it's going to replay internally within the aggregate that event to set up the internal state of the aggregate. It's going to reapply that event to the aggregate root.
00:30:23
Speaker
And just think of that as basically like a reducer function. Your aggregate is just taking a stream of events and reducing them down to a state. So your aggregate root is probably going to need to store the current status of the job, which is just new.
00:30:47
Speaker
Um, you know, maybe it's going to store some timestamps, maybe it's going to store some other stuff that it needs, but in this case, all the aggregate routes going to need to store is this, this, that the current state of the job is new. Right. And so when you call a sign, the aggregate route can say, okay, well, I replayed all the events internally, or reapplied all the events internally.
00:31:09
Speaker
it's valid to transition from a new to an assigned state. So we'll let the job was assigned event get fired and that will fire with all the data. It'll

Replayability and Historical Data in Event Sourcing

00:31:23
Speaker
probably have the assigned user ID, maybe some notes that an admin added when they were assigning it.
00:31:34
Speaker
maybe probably the admin that did the assignment, maybe some other metadata. And that event gets fired and now your projector is listening for job was assigned. And when it sees a job was assigned, now it looks up the job in your database, your eloquent model that has the aggregate UUID of that event.
00:32:03
Speaker
that job was created earlier, so it fetches it from the database. And now maybe all your projector does is say, you know, job update status is assigned, user ID is event user ID, right? And so we just walk through, you know, the happy path when the job is scheduled, all the system, all that aggregate route needs to do is, well now,
00:32:31
Speaker
for the same case, like it hit the, you know, we fetch the aggregate, we retrieve the aggregate by its EU ID, we call schedule on it, the aggregate's gonna reapply all the previous events. So now when it sees the created and then assigned, it's gonna update its internal status to assigned, and it's gonna say, okay, well, it was assigned, so that means it's allowed to go into scheduled.
00:33:02
Speaker
And so it'll let the job was scheduled event fire and so on and so forth, right? So in this case, there is sort of this, the aggregate is kind of storing the same data as what you stored in the database.
00:33:19
Speaker
But those start to diverge as these systems get more complex. And so you just have to kind of trust that that's the case right now, but it definitely is. And the thing that's really interesting is we can have a job was assigned event that our projector
00:33:46
Speaker
just sets the user ID and the status to assigned. But we might have a job was reassigned event that in the beginning, maybe just sets the user ID and the status to assigned. Because at the current state of our application, that's all that matters. But
00:34:07
Speaker
There's an important difference because now we have an understanding that this job got to the assigned status in one of two different ways. And down the road, if it turns out that we need to do other work when a job is reassigned, we can replay those events. We can update our projectors.
00:34:28
Speaker
And we can replay all those old events and project new state as needed. And so having an understanding of what happened to get the thing in the state that it is becomes more and more valuable over time.
00:34:44
Speaker
Exactly now and like so so given given this example of like that was a happy path so let's say a job comes in as created and so the aggregate like puts it as created and then
00:35:00
Speaker
A webhook from a third-party system tries to schedule it as the next event. It goes to schedule, but it's in the new state, the created state, and so it never fires the schedule event. Instead, it throws an exception. A job has to be assigned before it can be scheduled.
00:35:25
Speaker
But not only like maybe in addition to throwing an exception, it also fires an event that said like,
00:35:32
Speaker
job was job tried to be scheduled before assigned. And that event has a reactor or projector that sends an email to an admin that says like, something happened that wasn't like this bad thing happened that we didn't want.
00:35:56
Speaker
Those paths can become a little bit easier to reason about in the specific case as opposed to this controller that maybe has now all these extra spots. Well, I would take that even further. What if what we wanted was if a third-party partner
00:36:27
Speaker
sends more than three invalid status updates, we want to notify them. We want to notify them and we want to notify admins. In the traditional model application, now we're storing a column on the vendor that's like,
00:36:50
Speaker
invalid webhook count that is really awkward and then we have to reset it at the appropriate time and it doesn't really have any
00:37:06
Speaker
it just feels weird in all other contexts except for this one case. Whereas if, yeah, if in our assigned method,
00:37:21
Speaker
we check, is this valid? And then if it's not, we trigger a, you know, attempted to set job status to an invalid state event, right? Then our aggregate root can just
00:37:43
Speaker
apply, listen for that event internally, and every time it sees it, it just increments an internal counter for the number of times it's seen that since it triggered a notified vendor of bad API calls event or something like that.
00:38:04
Speaker
And when that count gets to three, it does something else, and then resets the count to zero. And now that count is just held internal to your aggregate root in a way that makes a lot of sense from the event stream perspective. And your application doesn't have to look at it outside of the event stream perspective.
00:38:28
Speaker
And then let's say like six months down the line, an admin wants to see a list of all of our vendors and who's done this poorly. Well, like now, you know, we can make a new projector that stores this in a table that just has like the vendor name and their, uh, incident count, and we can replay all of the events.
00:38:56
Speaker
that have ever happened and project that final count and then have an index view that's just like the vendor name and their count because some staff person or an admin like wanted to see that report from a UI perspective. Yeah, and I mean, this is maybe a little bit of an unlikely case, but
00:39:22
Speaker
stuff like this does come up. And when you're, when you think about things in events, you just have a lot of flexibility to, to sort of after the fact to decide, Oh, I want to look at this data in a slightly different

Is Event Sourcing Suitable for Billing Systems?

00:39:37
Speaker
way. Well, as long as you have the data, um, you can just go back and just, just use historical data to do new things, which is really powerful.
00:39:48
Speaker
I have a question about this example, about bad status updates. Just to help me understand a little bit more. For example, we have this so-called vendor sending us invalid statuses. We have to record those statuses. I'm assuming every time a status comes up, say it's our controller,
00:40:13
Speaker
We record that thing, we persist that into our snapshot slash aggregate route. But then immediately we have to check to see if we want to react to something.
00:40:29
Speaker
Well, you wouldn't even let the event fire if it's invalid. I see. So you would never, yeah, you wouldn't even fire the like, the job was scheduled event. Instead, you would fire a different event.
00:40:44
Speaker
I see. I see. Okay. Yeah. You're not persisting an invalid event. That is the fundamental job of the aggregate route is to guard against dispatching invalid events. Well, but how do you then keep track of the number of invalid statuses they've sent?
00:41:09
Speaker
you trigger a different event. You would trigger a vendor attempted to schedule a job or something like that. And you can just decide like how granular you want that to be. Is it like a vendor attempted to assign job that was new or do you just trigger like a vendor attempted invalid job?
00:41:35
Speaker
job transition and you just store the status that it was and the status that they tried to attempt. The vendor made an oopsie event. Yes, exactly. I got you. Okay. Well, yeah, I suppose that makes a lot of sense. So then you would persist obviously those things and then that other validation aspect would just look for all of the persisted counts of those events. Exactly. Got it. Okay. All right. Well, that helped me understand that.
00:42:04
Speaker
So the reason that this came up, right, is we are doing, we're doing a pretty big billing refactor and we're switching from authorize.net to Stripe for some stuff. And Stripe is fundamentally a very evented implementation, right? Everything comes through web hooks.
00:42:33
Speaker
And so when we were first sort of tackling this, the conversation around event sourcing came up a little bit, but I essentially made the call that,
00:42:51
Speaker
we should just implement it not using the formal event sourcing processes, even though it is kind of event-driven anyway, but for reasons. And I think that now that I've just been thinking about event sourcing, again, I'm questioning that decision and I think we're at a place where
00:43:19
Speaker
you know, because a lot of the implementation is already, you know, just reacting to events, it wouldn't be a particularly difficult refactor to take the code that we have and instead of sort of these bespoke event handlers, webhook handlers, use projectors and reactors and an aggregate root for the subscription or whatever it might be.
00:43:49
Speaker
And when we first started talking about it, you know, the point came up that this may be a really good use case for event sourcing, but it does...
00:44:08
Speaker
It does, it's less obvious to, you know, the traditional Laravel developer how things work and is it worth sort of, you know, hiding some of this behavior behind, you know, a different paradigm. And I just thought it'd be really interesting to have that conversation here because I think there's something to it
00:44:37
Speaker
I'm not convinced that that's, you know, I still am sort of feeling like, especially in the case of Stripe where you're really dealing with a lot of webhook, reacting to webhooks, just using a formal event sourcing process might, I think it might be the right call, but I just, I don't know, I wanted to have that.

Personal Insights on Event Sourcing Benefits

00:45:01
Speaker
And I know Skyler, your initial reaction was just like,
00:45:06
Speaker
It just feels like it might be harder to reason about if we're not always inside this event sourcing stuff and billing is something that we're going to be dealing with a lot. So like, is it worth that cost? And I wonder if you're still feeling that or if you've kind of changed your position at all or I don't know where you are.
00:45:28
Speaker
Yeah. I mean, I think, um, I had, I had heard of event sourcing before I started at international, but I had never used it and.
00:45:39
Speaker
So I was just like, man, there's all these terms and like, well, I don't have a CS degree. Maybe if I had a CS degree, like I'd understand what an aggregate route and a projector and all this stuff was. And I was just like, man, like, I don't know. I just want to like have my models and like keep with the defaults. Uh, but I spent literally three hours, watch some videos, read some blog posts. And now I'm like, Oh, like I, I get it. And I actually think there's a lot of places where this
00:46:09
Speaker
would have been useful in past jobs that I've had. It's all events everywhere. I worked for a long time on a CMS product, and we had versions. People could create new versions of existing content. And so we had this table with the actual content.
00:46:31
Speaker
And then another table with the versions. But someone wants to preview a version but not publish it. Well, we didn't have a way to do that. And so then we had this third table that was preview. And then, oh, well, it needs to go through an approval process if it's just an editor and not an admin. And we had just had all these terrible, it was really hard to work with.
00:46:56
Speaker
in a quote unquote traditional sense. And like event sourcing, while it adds a level of complexity initially, like could have simplified the implementation of that. And so looking at all this code that we have for billing here already is like, man, this is
00:47:19
Speaker
a lot of weird edge cases that are being covered, that event sourcing, at least it's got more guardrails and it's got conventions of how to do something.
00:47:34
Speaker
in the sense of billing where a user might be entering credit card information, an admin might be crediting their account with something, Stripe's sending a webhook, Authorize.net is sending a settlement notification. We've got all these different things in different places and jobs are running to do subscriptions. I don't know, event sourcing might
00:48:00
Speaker
contain all of those different places in a, in a way that makes it easier to easier to work with. I love how what three hour video made Skylar an event source junkie. I know. Before I was like, man, listening to Daniel on all these different podcasts, talking about event sourcing. And I was just like, ah, like it's over, but now I'm like, oh man, Daniel was right.
00:48:26
Speaker
Yeah, I mean, you know, I think, you know, as far as the, you know, stripe example, you know, I don't have, you know, I have some doubts also with event sourcing, because I also feel like, you know, it is a bit of

Complexity vs. Benefits: Event Sourcing Analysis

00:48:41
Speaker
black magic. And I feel like anybody coming from like a traditional background, like you, Skylar, like you, Chris, and, you know, me and many other people who would be listening to this.
00:48:50
Speaker
you know it is a little bit of you know once you get your feet wet maybe then you'll start to really appreciate understand it i think that's part of it as far as the stripe implementation stuff you know what i worry about is you know are we collecting are we like
00:49:09
Speaker
Ever going to be in a position to replay those events to project different data and I know that we have a different payment processor right now that is painful. Which it's all for us at net. It's the worst I'm happy to say their name and disparage it because they're awful.
00:49:29
Speaker
Yes. But I feel like if Authorize.NET could send us events, they would probably be terrible. But it would be nice to replay some of this stuff in our database. We've certainly, over the years, have made mistakes. We are human. We're not perfect. And it would be nice to say, hey, just replay five years worth of Authorize.NET events to bring somebody's status up to speed or whatever it is.
00:49:58
Speaker
I do think that there is some value in recording some of these Stripe events. Is our application
00:50:09
Speaker
If we don't record it, it's almost like our application is like a projector of Stripe events, right? They send us the events and we kind of like crunch them down and we do stuff. But I suppose if we record them, then we could also replay those events. And I don't know how valuable that is. I mean, on one hand, it sounds like valuable, but what is your initial gut?
00:50:33
Speaker
I mean, I think the, the promise of being able to replay events is incredibly enticing. Um, and I think being able to replay events in development and testing is very ha has already proven to be incredibly valuable because I mean, I have a real world example that we were just working on earlier this week.
00:51:01
Speaker
Yeah. So in our application, like a user can go from paid to just like a guest user. And if they go back to paid within 12 months of downgrading, like we will reinstate them at their like
00:51:19
Speaker
level with all of their path like all of their like credits and things like they're there but if it's after 12 months then like we don't we don't we give them some things but not everything and so we've got to like store this date about like when
00:51:37
Speaker
When were they downgraded? When were they upgraded? And if we had these events, like the event itself would have that date. But if we change our minds and we say now it's 11 months or now it's 13 months, like
00:51:53
Speaker
We've got all these events that are user was downgraded user was upgraded. I don't know. I think like this is a case where like we were relying on this date that wasn't necessarily set correctly and people that had been downgraded for years like we're getting
00:52:11
Speaker
platinum status or whatever, like when they shouldn't have.

Replaying Events: Correcting Errors

00:52:15
Speaker
And it was confusing to them and to staff and to us. And like, we couldn't quite figure out how did they get into this state? Because we thought they deactivated in 2011, but like for some reason, we just don't know. Cause all we have is where they were at when we, where the database was.
00:52:37
Speaker
right yeah and and to be able to i mean even without that's the thing is like the promise of replaying events is really enticing and i i do think that there's value there but even beyond just replaying the events like in that case of that person that that uh there was an issue with
00:52:58
Speaker
Being able to just look at the stream of events and debug by just that instead of trying to recreate all of that history from all the other data and the audit logs and all these different various data points that we have around the application.
00:53:23
Speaker
That alone would have been really helpful, right but Yeah, I mean I I definitely think that Replaying events is is a powerful Feature of this, you know architecture and I think that it can come into play even if it's not I mean, you know the the big promise is
00:53:51
Speaker
If we go back to the exam system, the exam system is tested incredibly heavily and went through tons of QA, so obviously this didn't happen. But imagine a world where we accidentally didn't add up their score correctly in our
00:54:14
Speaker
you know, in our projector, right? We were doing like a, you know, plus equals and like we needed to be like reset. I don't know. I can't think of a case where this would actually happen, but like
00:54:29
Speaker
we somehow were screwing up the score. And maybe it was like, it was just like a rounding error. So it only came up in these really edge cases where it was like, you know, multiple choice question and it was an odd number of options. And there was like, you know, where it just didn't come up enough. And so people were getting these like fractional scores and the rounding wasn't working the way it was intended to work. Right. That's a that's a that's a theoretical scenario.
00:54:59
Speaker
The real promise of being able to replay events is theoretically, in that case, we would be able to go back and change round to floor to seal or whatever it was that the bug was.
00:55:17
Speaker
And then either just delete the entire exam sessions table and rerun all of those events. And now all the sessions come with the correct scoring. Or if you make all of your projectors idempotent, then you just replay all the events and they just get applied in order again.
00:55:43
Speaker
And they, you know, it just, it just recalculates that score for each session. Um, and I think that there's a lot of like, that's really interesting to me, but we've never been in a position to do that yet. So I don't know. I mean, I imagine that actually replaying 12 million events would take a while.
00:56:08
Speaker
Uh, and so there's like downtime considerations and there's like, what if things, what if there is an error, like halfway through the process, like.
00:56:17
Speaker
There's a bunch of questions that I don't know the answer to yet. You could replay to a new table. Yes. And then after it finishes, you deploy again, pointing to that new table in your UI. There's some options. And that's actually what's even cooler there is you can update your projector to project to two tables.
00:56:44
Speaker
then replay all your events into the new table. While that's happening, all of the events that get triggered during the migration are just getting projected into two places. So you have up to date state on both tables. And then once everything synced up, and I mean, this is what we did with the system in the past when we were actually
00:57:11
Speaker
moving to this event source system was we just projected everything into two places. And that way, we were, you know, able to do it over time without having to, like, make that moment in time switch. Yeah.
00:57:30
Speaker
Yeah, no, it definitely sounds like a very compelling argument. I feel like after also doing some research on the event sourcing and having this conversation and just kind of looking back at some of the old event sourcing code that we have.
00:57:45
Speaker
I think that it is a really good solution to handle complex logic such as the exam system. Like you mentioned earlier, we have to be able to prove that a certain person has taken this course and storing their IP address with every answer is just not viable. I think that there's a lot of benefits. Even if we do have to replay, it sounds like there's some options that we could
00:58:16
Speaker
We need to use a CPU that has not yet been developed to replay 12 million events. I'm sure that we'll be able to do it in time. It sounds like there's an off-ramp to be able to project into different tables, to be able to do various things. I feel like some of it still feels like black magic to me, and I'm sure Skylar probably feels the same way, and I'm sure Chris, you have some doubts. That's where I think we are, at least.
00:58:37
Speaker
even if it takes a while and we need to have a

Projecting New Data from Historical Events

00:58:47
Speaker
Yeah, I mean, the other thing about replaying events, and this I actually think is the bigger upside, is there's the scenario where you replay events just to fix something or maybe capture new data that you need.
00:59:05
Speaker
Right, because going back to this job assignment system, maybe in the beginning when a job was scheduled, event is fired, and a job was assigned, event is fired, all we're doing is updating the status of the job in our eloquent model. But maybe six months out,
00:59:27
Speaker
you know, our partner comes back and says, hey, we want, you know, we want to start auditing, um, the, you know, uh, the, the new to assigned timing of your application because like you agree to certain standards and now we're in a position where, oh shoot, we haven't been storing those timestamps on the, the jobs table.
00:59:53
Speaker
But we have those events. And I think the use cases for replaying events into new projectors is much more, I imagine that comes up more. I mean, that's something that we've already done. But I imagine that comes up more often where, OK, this new requirement comes in.
01:00:15
Speaker
And now, instead of having to store all of these timestamps on the jobs table, when those timestamps don't really matter to the application that's consuming that
01:00:31
Speaker
that model, we can instead just write a new projector that projects these time averages into these daily or weekly or monthly averages to a new table.
01:00:52
Speaker
that is custom built for the auditing purposes so that we can just show in January, our average time between new and assigned was 16 hours.
01:01:12
Speaker
And our highest was 28 hours and our lowest was two hours or whatever data we need. And in February, we aggregate however we want. And all that would be necessary to make that happen is
01:01:31
Speaker
build up the necessary state, add any necessary state to the aggregate root to do those calculations. And because, to Skyler's point at the very beginning, the aggregate root is just in memory, you can add new stuff to it whenever you want, because it's going to be recomputed. You might have to wipe out your snapshots if you're going to do that.
01:01:58
Speaker
And now we just have a new feature that we can build from this historical data. And I think in terms of projection that
01:02:07
Speaker
feels to me like a bigger upside or more realistic upside than this kind of imagined world where you just wipe your entire application state and replay all your events to get a new one. I think while it's nice to know that that's sort of there on the table, I imagine that's something that you do very infrequently.

Testing Strategies and Use Cases for Event Sourcing

01:02:31
Speaker
And I think that there's like two, there's like two stories that I'm still not fully, not fully like convinced, but mostly because I just don't know that like, I haven't done enough research. It's like, what's the testing story to this? Because it's so nice in Laravel to just be like,
01:02:49
Speaker
job factory like create a job and then like assert some stuff and like hit an endpoint and so like is there are there good testing facilities to like yes create a couple of events and then you know expect some things or and so like that's like one part and sounds like the answer is yes like use a package that's open source that has all that stuff and great
01:03:13
Speaker
And then I think another interesting conversation to have is like, all right, event sourcing is obviously not for everything. But what are some things that's probably not worth doing it on? And I know Daniel mentioned you shouldn't make your authentication event sourced. But I wonder, should your users be event sourced? Do we need to keep a history of when they updated their profile?
01:03:41
Speaker
Yeah, I mean, I'm gonna give the most unsatisfying answer. It depends, right? I think there are cases where authentication could be event sourced, maybe not to the degree where you're actually like,
01:03:58
Speaker
projecting their session on a queue in the, you know, like, but yeah, you may, if it's really important to your system from like a security and auditing perspective to know like exactly when people logged in and maybe, you know, you care about where they logged in from and like,
01:04:24
Speaker
You want to trigger specific events if someone logs in from one continent and then logs in from a different continent within 30 seconds or something. There are use cases where, from a security and auditing perspective, you may want to use event sourcing for four things like authentication.
01:04:48
Speaker
And yeah, in the same way, if the state of your users and their transition between those states is important, if you need to say, this person used a different company name six months ago,
01:05:10
Speaker
And they changed their company name, you know, five and a half months ago, like it may be worth it. Right. But on the flip side, if you're never going to ask those questions, it's probably way, way, way overkill them.
01:05:26
Speaker
Yeah, I could certainly see, you know, having an authentication kind of like tracking people's locations and stuff. I feel like I've done this without event sourcing by just writing custom data into an audit log, like a person logged in from this place and now it's in the audit log. But, you know, it's a very primitive, you know, obviously way of doing things. I think the other question that I also have like,
01:05:51
Speaker
When do you actually project events? If we take this example of recording where you logged in from, I don't want to compute that data during the login process. I just want to write that event. Would there be a background job of some sort process that says, just go through all of the latest logins and project them and do whatever else needs to happen?
01:06:21
Speaker
Yeah, I mean, this is getting a little bit to the edge of my comfort level with specifically the library that we use, the Spotsy library. But yeah, I imagine that you would essentially
01:06:43
Speaker
you would need to trigger a user logged in event and then maybe have like a reactor that runs on the queue that listens for the user logged in event.
01:06:59
Speaker
And, you know, fires a set, like does the, you know, the, um, IP lookup geo stuff in the background on the queue and fires like an additional like user login was geocoded event

Making Event Sourcing Laravel-Friendly

01:07:19
Speaker
or something like that. You know what I mean? Like, um,
01:07:24
Speaker
Because yeah, you obviously don't necessarily want to do that direct inside your synchronous login method.
01:07:31
Speaker
I feel like on this episode, we haven't talked about over-engineering anything yet. I feel like what if we over-engineered a basic user registration flow using event sourcing that triggers an event? Would that be an interesting way to explore some of the event sourcing magic? I feel like we've already walked through
01:08:01
Speaker
you know, other flows, I don't know that we would really, um, that we would really get to anything new there.
01:08:09
Speaker
I think it would be interesting to like, so Laravel has all these breeze starter kits that have like authentication out of the box. It'd be interesting to like make a breeze starter kit. That's like an event sourcing breeze starter kit where, yeah, like instead of it creating the user directly, it's firing a user registered event into the event sourcing thing. And it's like projecting
01:08:35
Speaker
that data, that how do we, how do you, what are, which isn't necessarily over-engineered, but it's how do we get our default layer belt conventions, but also integrate this event sourcing paradigm without it feeling like we're going against the framework, which is all vibes, for the most part, but still, that matters.
01:09:04
Speaker
Yeah. I, so I think, you know, something that I've been thinking about a ton is sort of the branding of event sourcing and like, yeah, these things like, uh, aggregate root and CQRS and CRDT and projectors and reactors and, you know, huh, aggregate versioning. And
01:09:29
Speaker
all this stuff. Like it's, it's hard. It's just like inaccessible in a way. And even if it's not, even if all those terms are perfectly fine, they, yeah, they don't vibe with the Laravel sort of way. And I, I do think that there is an opportunity to sort of like,
01:09:55
Speaker
implement a package that gives you a lot of the power of event sourcing, but just feels more, you know, artisanal. Throw some facades on there and make it like just so easy to use event sourcing that it becomes like easy. It doesn't feel like it's heavy handed. Obviously there's trade-offs to every like major architectural decision, but
01:10:25
Speaker
makes it easier if it feels like you're not fighting the framework.

CQRS and Its Role in Event Sourcing

01:10:35
Speaker
Here's another concept that I did want to introduce. The term is CQRS, Command and Query Responsibility Segregation.
01:10:51
Speaker
Well, first I'll describe what it is and then I'll bring it back to Laravel. The idea of CQRS is essentially that for an event-sourced application to really function well, you have to segregate your commands, your write activity from your queries, your read activity.
01:11:16
Speaker
And like in a formal event sourcing model, your application is going to trigger commands expecting nothing in return. And that's going to write to your right model, your right database. And that's effectively just saving events in the database. And then your event system is going to
01:11:45
Speaker
separate from the rest of your application, read the history of those commands. Technically, you don't need the projector process. You could always just instantiate your state by reapplying all the events and never project. But typically, you want to be able to query your data.
01:12:13
Speaker
And so, you know, you have the application triggers commands, those get written, and then some magic happens, you know, whether it's those commands are processed on a queue, maybe those commands are processed synchronously in your application, but like,
01:12:31
Speaker
from sort of the CQRS perspective, like these things are segregated. You write and then something happens and now you have a read model that you can read from. And so your read model in sort of the Laravel world would be eloquent models, right? And your write model would be the aggregate route triggering events.
01:12:57
Speaker
Um, and by separating those things out, like you need to separate those things out to kind of get a lot of the value that we talked about. But I think that fundamentally this separation of reads and writes just feels really
01:13:26
Speaker
I'm doing all this work in one place for one side of the interaction and then I have to do all this work in another place to get the other side of the interaction and I've got this
01:13:39
Speaker
job aggregate root, and I've got this job model, and I have to apply my job events inside of the job aggregate, and then I also have to project my job events into my job model, and it just starts to feel really heavy-handed. And so the thing that I keep on wondering is, is there a way to implement
01:14:10
Speaker
you know, implement sort of the principles of CQRS while making the ergonomics of it nicer inside of like a traditional Laravel application. And I don't know, I think that's like almost a question for another episode, but it's just like something to, to at least think about or start, start thinking about.
01:14:34
Speaker
Yeah, I don't know. I think, I think you can get, you, you have the potential of getting into weird situations where then you're like aggregates are pulling in data from a previous like state of where things are.
01:14:54
Speaker
somewhere else, but I don't know because there's no, I don't have like a good use use case one way or another. I will say like, it feels like a lot, but if you, I mean, Laravel has model events and observers and policies.
01:15:12
Speaker
And lots of things that are kind of spread out that act on like fire an event and then you can register listener or you can register model observer or you can have model events in a boot method on.
01:15:28
Speaker
the model like there's already you can already have layers of abstraction and so is it really that much more to say like you have your projectors that are writing to your eloquent models and you have your aggregates that are you know handling your events and
01:15:52
Speaker
we can come up with some like more, more Laravel-esque naming conventions of those things. But I don't actually think it's that, uh, I would have agreed with you two weeks ago, but like, I don't actually know that it's that much more now.

Event Sourcing Packages: Spotsy and Event Sauce

01:16:11
Speaker
That's fair. Yeah. And I mean, maybe there are, I do imagine that there are ways to, to make it feel a little bit better. Um,
01:16:22
Speaker
while still getting all the power of that separation.
01:16:30
Speaker
So let's talk about some of the packages. Let's say I want to create a new project or I want to tinker around with event sourcing. I know that there's the Spotsy package out there. There's also the event source package. What do you think is a good approach to start with? I feel like we should bring some value to our listeners. And how does one just go build events and project them?
01:17:00
Speaker
you know, replay them. What, where, where do you get all that testing magic you were talking about earlier? Well, the Spotsy package, um, comes with, uh, a lot of nice testing convenience out of the box. Um, I think that in their docs, they say that they were inspired by event sauces, testing conveniences. So I'll put it out there that, yeah.
01:17:27
Speaker
So it sounds like event sauce is like the OG PHP version. Yeah, I've never used event sauce and I haven't dug into it. Event sauce I know is it goes deeper than the spot C package. And I think that it touches on a bunch of things that, uh, or, or, you know, has answers to a bunch of questions that I've run into already. You know, a big one is just like,
01:17:56
Speaker
uh, when you have multiple aggregates that are sort of part of the same thing, right? If you think about our, our example of like the vendor sending a status update that's invalid, you know,
01:18:10
Speaker
You would argue that the actual event that you're triggering about the vendor should actually happen on the vendor aggregate. I think EventSauce has a better story around multiple aggregates all being part of the same interaction.
01:18:31
Speaker
Whereas the Spotsy package is a little bit more strict about this idea that everything happens to one aggregate and one aggregate only, or one aggregate root only.
01:18:45
Speaker
And I think that EventSauce supports more of the formal event stores and maybe has more formal concepts built in. The reason that we chose the Spotsy package when we did was that the Spotsy package already feels like it's
01:19:08
Speaker
making event sourcing more accessible to Laravel developers. It does use a lot of Laravel conventions. The testing helpers tie in nicely with the Laravel testing feature set.
01:19:25
Speaker
Um, and yeah, it's just, you know, it's, it's like a, a, a layer of L package through and through, um, that said, um, I don't know. Skyler was saying this earlier before we started recording. And I, I think that this resonated with me too.
01:19:46
Speaker
that it's nice to use one of these packages, but if someone's getting started, I do think that there's a lot of value in trying to implement the concepts yourself before reaching for a package, because the reality is it's not that hard. A lot of what these packages do is just like provide
01:20:10
Speaker
formal mechanisms for stuff that you're going to eventually need or guard against potential bad scenarios that you might not know to guard against in the beginning. There's value there, but
01:20:27
Speaker
just building it out in the beginning and just using the event dispatcher and a listener and a stored event model and write your own stuff on top of that. I think it's where I would start if I was trying to get my head wrapped around it.
01:20:47
Speaker
Yeah, I mean, I was going to say, I feel like writing your own event source package when you don't know what it is, is a big undertaking, I think, in my mind. I do think the happy medium perhaps is like actually sitting down and looking at the source code of Spotty package to figure out how it is that

Learning Through Practice: Getting Started

01:21:04
Speaker
it works. I mean, unless you've already wrapped your head around how event sourcing works, and you're very confident to get the event-driven workflow and how the aggregate route works,
01:21:17
Speaker
I think for an average person who has not experienced that, that is a big challenge. I totally get where you're coming from, Chris, but I feel like it's a huge ask. I don't know. I would say look at some source code. Maybe we can include some material that we've found on event sourcing for people to also educate themselves.
01:21:44
Speaker
about some of the concepts and maybe like the description of the podcast. I think that would be really cool. Yeah, we definitely can. There's that event sorcery YouTube series. That's also a really good place to start. Yeah. I mean, I think like we don't.
01:22:02
Speaker
My, my statement earlier off, off the podcast about like, maybe we, if we're going to do this more, we should write our own was more that like, uh, if this is going to be like, if it's first, if it's for a project, that's just like for learning, like using a package is, is great. Like writing it yourself is great. But if this is for like a thing that's making money is providing jobs for people. If you're relying on something that you don't totally understand how it works, that can become a risk.
01:22:32
Speaker
And like, if the package does make changes that you don't want, we're kind of like, you're kind of stuck. Whereas like, if this is a main part of the application, maybe writing our own makes sense in this context. Also, maybe it's an opportunity to over engineer something, you know, like,
01:22:51
Speaker
There's especially, there's those package changes are in private final state. Oh man. Getting spicy on the podcast. But I think like there's, there are, um, there are trade-offs, there are benefits of an open source package because fixing bugs and things like that. But the trade-off is like, you're kind of.
01:23:15
Speaker
beholden to what the community wants the package to do or what the maintainer of the package wants in or out of it. And I think it really depends. But if you look at the source code of spotty or event sauce and you're overwhelmed,
01:23:32
Speaker
like watch some videos and then maybe implement your own. That's just the bare minimum of what you need. Um, and in that sense, it can be, it's in the, in the sense of like, it's not that hard. Yeah. If you like watch some videos and read some blog posts, you may find that it is not as hard. Um,
01:23:54
Speaker
But if you look at the, at the package and you're like, Oh my gosh, there's all this stuff. Like at the, at the end of the day, it's not that much stuff. If you start with like a bare minimum, a minimal implementation. Yeah. I mean, another thing about like.
01:24:11
Speaker
when you're writing a package, the Spotsy package, for example, has an event repository interface, and then an event repository abstract event repository, and then an eloquent event repository, right? And all of that makes sense from a package perspective because they're trying to implement something that is flexible while defining a clear interface for writing to and reading events. And I mean, when we were looking at it,
01:24:42
Speaker
there was a period of time when we were looking at writing our own DynamoDB implementation of that event repository interface. And so having all those layers of abstraction makes a ton of sense at the package level. But internally, right?
01:25:03
Speaker
We're not, we don't need, uh, an event repository interface in an abstract event repository and an eloquent event repository. We can just have an event repository, uh, that, I mean, we can just have an event, a stored events model and use eloquent and not have a repository at all. And like.
01:25:26
Speaker
that works perfectly fine for us. And I think that that's definitely true about these packages is they need to account for a ton of different scenarios and any application only needs to account for their specific scenario.
01:25:41
Speaker
Agreed. All right. This feels like, um, a good place to start to slow down.

Fundamental Development Concepts Explored

01:25:50
Speaker
Um, you know, I worry there in the back of my mind, there's a tiny part of me that's like, people are going to listen to this and we will have never set the stage well enough for the conversation. It's going to make no sense. I hope not. Um,
01:26:08
Speaker
But I think that this architecture makes a lot of sense in a lot of places. And I definitely want to keep on sort of exploring it and talking about it, both for our application and I do really want to come back to this question of
01:26:29
Speaker
You know, is there a way to rethink some of the terms for specifically the world of Laravel developers and Laravel applications or rethink some of the, you know, the structure to make these things still have the benefit that they have, but kind of work within the traditional Laravel applications more?
01:26:54
Speaker
I think if you've come to the hour and 27 minute mark of this episode and you're like, I still don't understand event sourcing, go watch the first 14 episodes of Sean McCool's event sorcery course on YouTube. It's free.
01:27:11
Speaker
And it answers a lot of those questions, I think. I was skeptical until after listening to that. And he talks about event sourcing using PHP, but he caveats a lot of things that it has nothing to do with the PHP language. You could write event sourcing applications in any language with or without a framework.
01:27:39
Speaker
And, um, but it's super, it's super helpful. It like gave me like, now I feel like, yeah, I could go in and write some event sourcing code and, and understand what the heck I'm talking about. And I, I'll, uh, I'll shout it out, even though I haven't, um, looked at it in a long time, but you know, Spotsy has a whole advanced events sourcing, um, course that they released. Um, you know, it's a paid course, but, um,
01:28:09
Speaker
You know, I'm a little salty about it because a lot of that content used to just be included in the Spotsy event sourcing documentation. And now it's behind this paywall, but you know, you got to get paid. I don't mind paying a company for the work that they do. So that's another resource. I can't, I can't speak exactly to the quality of it because I haven't looked at the paid course. I've just seen some of the resources that kind of led up to that.
01:28:39
Speaker
But again, that's very specific to Laravel applications. So I think for Laravel developers, it's good to have it there.
01:28:50
Speaker
Yeah, I will say, you know, I agree with Skylar. I also watch that same YouTube video and I feel like personally myself, I don't know if you guys know much about me, but I used to be a paramedic back in the day and I read a lot of books about how to intubate people and that was cool. But then you have to go and actually do it. So I feel like you have to watch this course. You've got to go get the, you know, the Spotsy package, the event sorcery package, read some documentation.
01:29:17
Speaker
and actually make something because otherwise, you know, if you cannot put into practice, it's useless. I think that's really my position. And I yeah, that's I think that's true of everything, right? Like, you can you can understand this theory.
01:29:34
Speaker
And I mean, you know, I, I, uh, rail against private, private methods and, and final classes. Um, sometimes they're perfectly fine, but like, if you don't know when and how to use something, you can, you can get caught up in using it the wrong way or, or like, you know, I don't know. Maybe that's a bad analogy to draw, but
01:30:03
Speaker
I didn't understand the difference between private and protected until I started working here and Chris changed my PR, the first PR I made and said, we don't do private here.
01:30:14
Speaker
The difference is that private is something that you never type into code and protected is something that you use when it's not public.

Conclusion and Future Topics

01:30:25
Speaker
Yes, indeed. Yes. And final is a word that you can just leave out of your vocabulary. All right. Well, I think that's a perfect place to stop.
01:30:43
Speaker
This has been fun. Indeed it has. See you guys. Until next time. See ya.